NeahNew/.next/server/vendor-chunks/html-to-text.js
2025-05-03 14:17:46 +02:00

35 lines
354 KiB
JavaScript

"use strict";
/*
* ATTENTION: An "eval-source-map" devtool has been used.
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
exports.id = "vendor-chunks/html-to-text";
exports.ids = ["vendor-chunks/html-to-text"];
exports.modules = {
/***/ "(action-browser)/./node_modules/html-to-text/lib/html-to-text.cjs":
/*!********************************************************!*\
!*** ./node_modules/html-to-text/lib/html-to-text.cjs ***!
\********************************************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
eval("\n\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n\nvar pluginHtmlparser2 = __webpack_require__(/*! @selderee/plugin-htmlparser2 */ \"(action-browser)/./node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.cjs\");\nvar htmlparser2 = __webpack_require__(/*! htmlparser2 */ \"(action-browser)/./node_modules/htmlparser2/lib/index.js\");\nvar selderee = __webpack_require__(/*! selderee */ \"(action-browser)/./node_modules/selderee/lib/selderee.cjs\");\nvar merge = __webpack_require__(/*! deepmerge */ \"(action-browser)/./node_modules/deepmerge/dist/cjs.js\");\nvar domSerializer = __webpack_require__(/*! dom-serializer */ \"(action-browser)/./node_modules/dom-serializer/lib/index.js\");\n\nfunction _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }\n\nvar merge__default = /*#__PURE__*/_interopDefaultLegacy(merge);\n\n/**\n * Make a recursive function that will only run to a given depth\n * and switches to an alternative function at that depth. \\\n * No limitation if `n` is `undefined` (Just wraps `f` in that case).\n *\n * @param { number | undefined } n Allowed depth of recursion. `undefined` for no limitation.\n * @param { Function } f Function that accepts recursive callback as the first argument.\n * @param { Function } [g] Function to run instead, when maximum depth was reached. Do nothing by default.\n * @returns { Function }\n */\nfunction limitedDepthRecursive (n, f, g = () => undefined) {\n if (n === undefined) {\n const f1 = function (...args) { return f(f1, ...args); };\n return f1;\n }\n if (n >= 0) {\n return function (...args) { return f(limitedDepthRecursive(n - 1, f, g), ...args); };\n }\n return g;\n}\n\n/**\n * Return the same string or a substring with\n * the given character occurrences removed from each side.\n *\n * @param { string } str A string to trim.\n * @param { string } char A character to be trimmed.\n * @returns { string }\n */\nfunction trimCharacter (str, char) {\n let start = 0;\n let end = str.length;\n while (start < end && str[start] === char) { ++start; }\n while (end > start && str[end - 1] === char) { --end; }\n return (start > 0 || end < str.length)\n ? str.substring(start, end)\n : str;\n}\n\n/**\n * Return the same string or a substring with\n * the given character occurrences removed from the end only.\n *\n * @param { string } str A string to trim.\n * @param { string } char A character to be trimmed.\n * @returns { string }\n */\nfunction trimCharacterEnd (str, char) {\n let end = str.length;\n while (end > 0 && str[end - 1] === char) { --end; }\n return (end < str.length)\n ? str.substring(0, end)\n : str;\n}\n\n/**\n * Return a new string will all characters replaced with unicode escape sequences.\n * This extreme kind of escaping can used to be safely compose regular expressions.\n *\n * @param { string } str A string to escape.\n * @returns { string } A string of unicode escape sequences.\n */\nfunction unicodeEscape (str) {\n return str.replace(/[\\s\\S]/g, c => '\\\\u' + c.charCodeAt().toString(16).padStart(4, '0'));\n}\n\n/**\n * Deduplicate an array by a given key callback.\n * Item properties are merged recursively and with the preference for last defined values.\n * Of items with the same key, merged item takes the place of the last item,\n * others are omitted.\n *\n * @param { any[] } items An array to deduplicate.\n * @param { (x: any) => string } getKey Callback to get a value that distinguishes unique items.\n * @returns { any[] }\n */\nfunction mergeDuplicatesPreferLast (items, getKey) {\n const map = new Map();\n for (let i = items.length; i-- > 0;) {\n const item = items[i];\n const key = getKey(item);\n map.set(\n key,\n (map.has(key))\n ? merge__default[\"default\"](item, map.get(key), { arrayMerge: overwriteMerge$1 })\n : item\n );\n }\n return [...map.values()].reverse();\n}\n\nconst overwriteMerge$1 = (acc, src, options) => [...src];\n\n/**\n * Get a nested property from an object.\n *\n * @param { object } obj The object to query for the value.\n * @param { string[] } path The path to the property.\n * @returns { any }\n */\nfunction get (obj, path) {\n for (const key of path) {\n if (!obj) { return undefined; }\n obj = obj[key];\n }\n return obj;\n}\n\n/**\n * Convert a number into alphabetic sequence representation (Sequence without zeroes).\n *\n * For example: `a, ..., z, aa, ..., zz, aaa, ...`.\n *\n * @param { number } num Number to convert. Must be >= 1.\n * @param { string } [baseChar = 'a'] Character for 1 in the sequence.\n * @param { number } [base = 26] Number of characters in the sequence.\n * @returns { string }\n */\nfunction numberToLetterSequence (num, baseChar = 'a', base = 26) {\n const digits = [];\n do {\n num -= 1;\n digits.push(num % base);\n num = (num / base) >> 0; // quick `floor`\n } while (num > 0);\n const baseCode = baseChar.charCodeAt(0);\n return digits\n .reverse()\n .map(n => String.fromCharCode(baseCode + n))\n .join('');\n}\n\nconst I = ['I', 'X', 'C', 'M'];\nconst V = ['V', 'L', 'D'];\n\n/**\n * Convert a number to it's Roman representation. No large numbers extension.\n *\n * @param { number } num Number to convert. `0 < num <= 3999`.\n * @returns { string }\n */\nfunction numberToRoman (num) {\n return [...(num) + '']\n .map(n => +n)\n .reverse()\n .map((v, i) => ((v % 5 < 4)\n ? (v < 5 ? '' : V[i]) + I[i].repeat(v % 5)\n : I[i] + (v < 5 ? V[i] : I[i + 1])))\n .reverse()\n .join('');\n}\n\n/**\n * Helps to build text from words.\n */\nclass InlineTextBuilder {\n /**\n * Creates an instance of InlineTextBuilder.\n *\n * If `maxLineLength` is not provided then it is either `options.wordwrap` or unlimited.\n *\n * @param { Options } options HtmlToText options.\n * @param { number } [ maxLineLength ] This builder will try to wrap text to fit this line length.\n */\n constructor (options, maxLineLength = undefined) {\n /** @type { string[][] } */\n this.lines = [];\n /** @type { string[] } */\n this.nextLineWords = [];\n this.maxLineLength = maxLineLength || options.wordwrap || Number.MAX_VALUE;\n this.nextLineAvailableChars = this.maxLineLength;\n this.wrapCharacters = get(options, ['longWordSplit', 'wrapCharacters']) || [];\n this.forceWrapOnLimit = get(options, ['longWordSplit', 'forceWrapOnLimit']) || false;\n\n this.stashedSpace = false;\n this.wordBreakOpportunity = false;\n }\n\n /**\n * Add a new word.\n *\n * @param { string } word A word to add.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n pushWord (word, noWrap = false) {\n if (this.nextLineAvailableChars <= 0 && !noWrap) {\n this.startNewLine();\n }\n const isLineStart = this.nextLineWords.length === 0;\n const cost = word.length + (isLineStart ? 0 : 1);\n if ((cost <= this.nextLineAvailableChars) || noWrap) { // Fits into available budget\n\n this.nextLineWords.push(word);\n this.nextLineAvailableChars -= cost;\n\n } else { // Does not fit - try to split the word\n\n // The word is moved to a new line - prefer to wrap between words.\n const [first, ...rest] = this.splitLongWord(word);\n if (!isLineStart) { this.startNewLine(); }\n this.nextLineWords.push(first);\n this.nextLineAvailableChars -= first.length;\n for (const part of rest) {\n this.startNewLine();\n this.nextLineWords.push(part);\n this.nextLineAvailableChars -= part.length;\n }\n\n }\n }\n\n /**\n * Pop a word from the currently built line.\n * This doesn't affect completed lines.\n *\n * @returns { string }\n */\n popWord () {\n const lastWord = this.nextLineWords.pop();\n if (lastWord !== undefined) {\n const isLineStart = this.nextLineWords.length === 0;\n const cost = lastWord.length + (isLineStart ? 0 : 1);\n this.nextLineAvailableChars += cost;\n }\n return lastWord;\n }\n\n /**\n * Concat a word to the last word already in the builder.\n * Adds a new word in case there are no words yet in the last line.\n *\n * @param { string } word A word to be concatenated.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n concatWord (word, noWrap = false) {\n if (this.wordBreakOpportunity && word.length > this.nextLineAvailableChars) {\n this.pushWord(word, noWrap);\n this.wordBreakOpportunity = false;\n } else {\n const lastWord = this.popWord();\n this.pushWord((lastWord) ? lastWord.concat(word) : word, noWrap);\n }\n }\n\n /**\n * Add current line (and more empty lines if provided argument > 1) to the list of complete lines and start a new one.\n *\n * @param { number } n Number of line breaks that will be added to the resulting string.\n */\n startNewLine (n = 1) {\n this.lines.push(this.nextLineWords);\n if (n > 1) {\n this.lines.push(...Array.from({ length: n - 1 }, () => []));\n }\n this.nextLineWords = [];\n this.nextLineAvailableChars = this.maxLineLength;\n }\n\n /**\n * No words in this builder.\n *\n * @returns { boolean }\n */\n isEmpty () {\n return this.lines.length === 0\n && this.nextLineWords.length === 0;\n }\n\n clear () {\n this.lines.length = 0;\n this.nextLineWords.length = 0;\n this.nextLineAvailableChars = this.maxLineLength;\n }\n\n /**\n * Join all lines of words inside the InlineTextBuilder into a complete string.\n *\n * @returns { string }\n */\n toString () {\n return [...this.lines, this.nextLineWords]\n .map(words => words.join(' '))\n .join('\\n');\n }\n\n /**\n * Split a long word up to fit within the word wrap limit.\n * Use either a character to split looking back from the word wrap limit,\n * or truncate to the word wrap limit.\n *\n * @param { string } word Input word.\n * @returns { string[] } Parts of the word.\n */\n splitLongWord (word) {\n const parts = [];\n let idx = 0;\n while (word.length > this.maxLineLength) {\n\n const firstLine = word.substring(0, this.maxLineLength);\n const remainingChars = word.substring(this.maxLineLength);\n\n const splitIndex = firstLine.lastIndexOf(this.wrapCharacters[idx]);\n\n if (splitIndex > -1) { // Found a character to split on\n\n word = firstLine.substring(splitIndex + 1) + remainingChars;\n parts.push(firstLine.substring(0, splitIndex + 1));\n\n } else { // Not found a character to split on\n\n idx++;\n if (idx < this.wrapCharacters.length) { // There is next character to try\n\n word = firstLine + remainingChars;\n\n } else { // No more characters to try\n\n if (this.forceWrapOnLimit) {\n parts.push(firstLine);\n word = remainingChars;\n if (word.length > this.maxLineLength) {\n continue;\n }\n } else {\n word = firstLine + remainingChars;\n }\n break;\n\n }\n\n }\n\n }\n parts.push(word); // Add remaining part to array\n return parts;\n }\n}\n\n/* eslint-disable max-classes-per-file */\n\n\nclass StackItem {\n constructor (next = null) { this.next = next; }\n\n getRoot () { return (this.next) ? this.next : this; }\n}\n\nclass BlockStackItem extends StackItem {\n constructor (options, next = null, leadingLineBreaks = 1, maxLineLength = undefined) {\n super(next);\n this.leadingLineBreaks = leadingLineBreaks;\n this.inlineTextBuilder = new InlineTextBuilder(options, maxLineLength);\n this.rawText = '';\n this.stashedLineBreaks = 0;\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass ListStackItem extends BlockStackItem {\n constructor (\n options,\n next = null,\n {\n interRowLineBreaks = 1,\n leadingLineBreaks = 2,\n maxLineLength = undefined,\n maxPrefixLength = 0,\n prefixAlign = 'left',\n } = {}\n ) {\n super(options, next, leadingLineBreaks, maxLineLength);\n this.maxPrefixLength = maxPrefixLength;\n this.prefixAlign = prefixAlign;\n this.interRowLineBreaks = interRowLineBreaks;\n }\n}\n\nclass ListItemStackItem extends BlockStackItem {\n constructor (\n options,\n next = null,\n {\n leadingLineBreaks = 1,\n maxLineLength = undefined,\n prefix = '',\n } = {}\n ) {\n super(options, next, leadingLineBreaks, maxLineLength);\n this.prefix = prefix;\n }\n}\n\nclass TableStackItem extends StackItem {\n constructor (next = null) {\n super(next);\n this.rows = [];\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TableRowStackItem extends StackItem {\n constructor (next = null) {\n super(next);\n this.cells = [];\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TableCellStackItem extends StackItem {\n constructor (options, next = null, maxColumnWidth = undefined) {\n super(next);\n this.inlineTextBuilder = new InlineTextBuilder(options, maxColumnWidth);\n this.rawText = '';\n this.stashedLineBreaks = 0;\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TransformerStackItem extends StackItem {\n constructor (next = null, transform) {\n super(next);\n this.transform = transform;\n }\n}\n\nfunction charactersToCodes (str) {\n return [...str]\n .map(c => '\\\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'))\n .join('');\n}\n\n/**\n * Helps to handle HTML whitespaces.\n *\n * @class WhitespaceProcessor\n */\nclass WhitespaceProcessor {\n\n /**\n * Creates an instance of WhitespaceProcessor.\n *\n * @param { Options } options HtmlToText options.\n * @memberof WhitespaceProcessor\n */\n constructor (options) {\n this.whitespaceChars = (options.preserveNewlines)\n ? options.whitespaceCharacters.replace(/\\n/g, '')\n : options.whitespaceCharacters;\n const whitespaceCodes = charactersToCodes(this.whitespaceChars);\n this.leadingWhitespaceRe = new RegExp(`^[${whitespaceCodes}]`);\n this.trailingWhitespaceRe = new RegExp(`[${whitespaceCodes}]$`);\n this.allWhitespaceOrEmptyRe = new RegExp(`^[${whitespaceCodes}]*$`);\n this.newlineOrNonWhitespaceRe = new RegExp(`(\\\\n|[^\\\\n${whitespaceCodes}])`, 'g');\n this.newlineOrNonNewlineStringRe = new RegExp(`(\\\\n|[^\\\\n]+)`, 'g');\n\n if (options.preserveNewlines) {\n\n const wordOrNewlineRe = new RegExp(`\\\\n|[^\\\\n${whitespaceCodes}]+`, 'gm');\n\n /**\n * Shrink whitespaces and wrap text, add to the builder.\n *\n * @param { string } text Input text.\n * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.\n * @param { (str: string) => string } [ transform ] A transform to be applied to words.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n this.shrinkWrapAdd = function (text, inlineTextBuilder, transform = (str => str), noWrap = false) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = wordOrNewlineRe.exec(text);\n if (m) {\n anyMatch = true;\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else if (previouslyStashedSpace || this.testLeadingWhitespace(text)) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n } else {\n inlineTextBuilder.concatWord(transform(m[0]), noWrap);\n }\n while ((m = wordOrNewlineRe.exec(text)) !== null) {\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n }\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch) || (this.testTrailingWhitespace(text));\n // No need to stash a space in case last added item was a new line,\n // but that won't affect anything later anyway.\n };\n\n } else {\n\n const wordRe = new RegExp(`[^${whitespaceCodes}]+`, 'g');\n\n this.shrinkWrapAdd = function (text, inlineTextBuilder, transform = (str => str), noWrap = false) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = wordRe.exec(text);\n if (m) {\n anyMatch = true;\n if (previouslyStashedSpace || this.testLeadingWhitespace(text)) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n } else {\n inlineTextBuilder.concatWord(transform(m[0]), noWrap);\n }\n while ((m = wordRe.exec(text)) !== null) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch) || this.testTrailingWhitespace(text);\n };\n\n }\n }\n\n /**\n * Add text with only minimal processing.\n * Everything between newlines considered a single word.\n * No whitespace is trimmed.\n * Not affected by preserveNewlines option - `\\n` always starts a new line.\n *\n * `noWrap` argument is `true` by default - this won't start a new line\n * even if there is not enough space left in the current line.\n *\n * @param { string } text Input text.\n * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n addLiteral (text, inlineTextBuilder, noWrap = true) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = this.newlineOrNonNewlineStringRe.exec(text);\n if (m) {\n anyMatch = true;\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else if (previouslyStashedSpace) {\n inlineTextBuilder.pushWord(m[0], noWrap);\n } else {\n inlineTextBuilder.concatWord(m[0], noWrap);\n }\n while ((m = this.newlineOrNonNewlineStringRe.exec(text)) !== null) {\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else {\n inlineTextBuilder.pushWord(m[0], noWrap);\n }\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch);\n }\n\n /**\n * Test whether the given text starts with HTML whitespace character.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testLeadingWhitespace (text) {\n return this.leadingWhitespaceRe.test(text);\n }\n\n /**\n * Test whether the given text ends with HTML whitespace character.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testTrailingWhitespace (text) {\n return this.trailingWhitespaceRe.test(text);\n }\n\n /**\n * Test whether the given text contains any non-whitespace characters.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testContainsWords (text) {\n return !this.allWhitespaceOrEmptyRe.test(text);\n }\n\n /**\n * Return the number of newlines if there are no words.\n *\n * If any word is found then return zero regardless of the actual number of newlines.\n *\n * @param { string } text Input string.\n * @returns { number }\n */\n countNewlinesNoWords (text) {\n this.newlineOrNonWhitespaceRe.lastIndex = 0;\n let counter = 0;\n let match;\n while ((match = this.newlineOrNonWhitespaceRe.exec(text)) !== null) {\n if (match[0] === '\\n') {\n counter++;\n } else {\n return 0;\n }\n }\n return counter;\n }\n\n}\n\n/**\n * Helps to build text from inline and block elements.\n *\n * @class BlockTextBuilder\n */\nclass BlockTextBuilder {\n\n /**\n * Creates an instance of BlockTextBuilder.\n *\n * @param { Options } options HtmlToText options.\n * @param { import('selderee').Picker<DomNode, TagDefinition> } picker Selectors decision tree picker.\n * @param { any} [metadata] Optional metadata for HTML document, for use in formatters.\n */\n constructor (options, picker, metadata = undefined) {\n this.options = options;\n this.picker = picker;\n this.metadata = metadata;\n this.whitespaceProcessor = new WhitespaceProcessor(options);\n /** @type { StackItem } */\n this._stackItem = new BlockStackItem(options);\n /** @type { TransformerStackItem } */\n this._wordTransformer = undefined;\n }\n\n /**\n * Put a word-by-word transform function onto the transformations stack.\n *\n * Mainly used for uppercasing. Can be bypassed to add unformatted text such as URLs.\n *\n * Word transformations applied before wrapping.\n *\n * @param { (str: string) => string } wordTransform Word transformation function.\n */\n pushWordTransform (wordTransform) {\n this._wordTransformer = new TransformerStackItem(this._wordTransformer, wordTransform);\n }\n\n /**\n * Remove a function from the word transformations stack.\n *\n * @returns { (str: string) => string } A function that was removed.\n */\n popWordTransform () {\n if (!this._wordTransformer) { return undefined; }\n const transform = this._wordTransformer.transform;\n this._wordTransformer = this._wordTransformer.next;\n return transform;\n }\n\n /**\n * Ignore wordwrap option in followup inline additions and disable automatic wrapping.\n */\n startNoWrap () {\n this._stackItem.isNoWrap = true;\n }\n\n /**\n * Return automatic wrapping to behavior defined by options.\n */\n stopNoWrap () {\n this._stackItem.isNoWrap = false;\n }\n\n /** @returns { (str: string) => string } */\n _getCombinedWordTransformer () {\n const wt = (this._wordTransformer)\n ? ((str) => applyTransformer(str, this._wordTransformer))\n : undefined;\n const ce = this.options.encodeCharacters;\n return (wt)\n ? ((ce) ? (str) => ce(wt(str)) : wt)\n : ce;\n }\n\n _popStackItem () {\n const item = this._stackItem;\n this._stackItem = item.next;\n return item;\n }\n\n /**\n * Add a line break into currently built block.\n */\n addLineBreak () {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n if (this._stackItem.isPre) {\n this._stackItem.rawText += '\\n';\n } else {\n this._stackItem.inlineTextBuilder.startNewLine();\n }\n }\n\n /**\n * Allow to break line in case directly following text will not fit.\n */\n addWordBreakOpportunity () {\n if (\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n ) {\n this._stackItem.inlineTextBuilder.wordBreakOpportunity = true;\n }\n }\n\n /**\n * Add a node inline into the currently built block.\n *\n * @param { string } str\n * Text content of a node to add.\n *\n * @param { object } [param1]\n * Object holding the parameters of the operation.\n *\n * @param { boolean } [param1.noWordTransform]\n * Ignore word transformers if there are any.\n * Don't encode characters as well.\n * (Use this for things like URL addresses).\n */\n addInline (str, { noWordTransform = false } = {}) {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n\n if (this._stackItem.isPre) {\n this._stackItem.rawText += str;\n return;\n }\n\n if (\n str.length === 0 || // empty string\n (\n this._stackItem.stashedLineBreaks && // stashed linebreaks make whitespace irrelevant\n !this.whitespaceProcessor.testContainsWords(str) // no words to add\n )\n ) { return; }\n\n if (this.options.preserveNewlines) {\n const newlinesNumber = this.whitespaceProcessor.countNewlinesNoWords(str);\n if (newlinesNumber > 0) {\n this._stackItem.inlineTextBuilder.startNewLine(newlinesNumber);\n // keep stashedLineBreaks unchanged\n return;\n }\n }\n\n if (this._stackItem.stashedLineBreaks) {\n this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);\n }\n this.whitespaceProcessor.shrinkWrapAdd(\n str,\n this._stackItem.inlineTextBuilder,\n (noWordTransform) ? undefined : this._getCombinedWordTransformer(),\n this._stackItem.isNoWrap\n );\n this._stackItem.stashedLineBreaks = 0; // inline text doesn't introduce line breaks\n }\n\n /**\n * Add a string inline into the currently built block.\n *\n * Use this for markup elements that don't have to adhere\n * to text layout rules.\n *\n * @param { string } str Text to add.\n */\n addLiteral (str) {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n\n if (str.length === 0) { return; }\n\n if (this._stackItem.isPre) {\n this._stackItem.rawText += str;\n return;\n }\n\n if (this._stackItem.stashedLineBreaks) {\n this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);\n }\n this.whitespaceProcessor.addLiteral(\n str,\n this._stackItem.inlineTextBuilder,\n this._stackItem.isNoWrap\n );\n this._stackItem.stashedLineBreaks = 0;\n }\n\n /**\n * Start building a new block.\n *\n * @param { object } [param0]\n * Object holding the parameters of the block.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This block should have at least this number of line breaks to separate it from any preceding block.\n *\n * @param { number } [param0.reservedLineLength]\n * Reserve this number of characters on each line for block markup.\n *\n * @param { boolean } [param0.isPre]\n * Should HTML whitespace be preserved inside this block.\n */\n openBlock ({ leadingLineBreaks = 1, reservedLineLength = 0, isPre = false } = {}) {\n const maxLineLength = Math.max(20, this._stackItem.inlineTextBuilder.maxLineLength - reservedLineLength);\n this._stackItem = new BlockStackItem(\n this.options,\n this._stackItem,\n leadingLineBreaks,\n maxLineLength\n );\n if (isPre) { this._stackItem.isPre = true; }\n }\n\n /**\n * Finalize currently built block, add it's content to the parent block.\n *\n * @param { object } [param0]\n * Object holding the parameters of the block.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This block should have at least this number of line breaks to separate it from any following block.\n *\n * @param { (str: string) => string } [param0.blockTransform]\n * A function to transform the block text before adding to the parent block.\n * This happens after word wrap and should be used in combination with reserved line length\n * in order to keep line lengths correct.\n * Used for whole block markup.\n */\n closeBlock ({ trailingLineBreaks = 1, blockTransform = undefined } = {}) {\n const block = this._popStackItem();\n const blockText = (blockTransform) ? blockTransform(getText(block)) : getText(block);\n addText(this._stackItem, blockText, block.leadingLineBreaks, Math.max(block.stashedLineBreaks, trailingLineBreaks));\n }\n\n /**\n * Start building a new list.\n *\n * @param { object } [param0]\n * Object holding the parameters of the list.\n *\n * @param { number } [param0.maxPrefixLength]\n * Length of the longest list item prefix.\n * If not supplied or too small then list items won't be aligned properly.\n *\n * @param { 'left' | 'right' } [param0.prefixAlign]\n * Specify how prefixes of different lengths have to be aligned\n * within a column.\n *\n * @param { number } [param0.interRowLineBreaks]\n * Minimum number of line breaks between list items.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This list should have at least this number of line breaks to separate it from any preceding block.\n */\n openList ({ maxPrefixLength = 0, prefixAlign = 'left', interRowLineBreaks = 1, leadingLineBreaks = 2 } = {}) {\n this._stackItem = new ListStackItem(this.options, this._stackItem, {\n interRowLineBreaks: interRowLineBreaks,\n leadingLineBreaks: leadingLineBreaks,\n maxLineLength: this._stackItem.inlineTextBuilder.maxLineLength,\n maxPrefixLength: maxPrefixLength,\n prefixAlign: prefixAlign\n });\n }\n\n /**\n * Start building a new list item.\n *\n * @param {object} param0\n * Object holding the parameters of the list item.\n *\n * @param { string } [param0.prefix]\n * Prefix for this list item (item number, bullet point, etc).\n */\n openListItem ({ prefix = '' } = {}) {\n if (!(this._stackItem instanceof ListStackItem)) {\n throw new Error('Can\\'t add a list item to something that is not a list! Check the formatter.');\n }\n const list = this._stackItem;\n const prefixLength = Math.max(prefix.length, list.maxPrefixLength);\n const maxLineLength = Math.max(20, list.inlineTextBuilder.maxLineLength - prefixLength);\n this._stackItem = new ListItemStackItem(this.options, list, {\n prefix: prefix,\n maxLineLength: maxLineLength,\n leadingLineBreaks: list.interRowLineBreaks\n });\n }\n\n /**\n * Finalize currently built list item, add it's content to the parent list.\n */\n closeListItem () {\n const listItem = this._popStackItem();\n const list = listItem.next;\n\n const prefixLength = Math.max(listItem.prefix.length, list.maxPrefixLength);\n const spacing = '\\n' + ' '.repeat(prefixLength);\n const prefix = (list.prefixAlign === 'right')\n ? listItem.prefix.padStart(prefixLength)\n : listItem.prefix.padEnd(prefixLength);\n const text = prefix + getText(listItem).replace(/\\n/g, spacing);\n\n addText(\n list,\n text,\n listItem.leadingLineBreaks,\n Math.max(listItem.stashedLineBreaks, list.interRowLineBreaks)\n );\n }\n\n /**\n * Finalize currently built list, add it's content to the parent block.\n *\n * @param { object } param0\n * Object holding the parameters of the list.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This list should have at least this number of line breaks to separate it from any following block.\n */\n closeList ({ trailingLineBreaks = 2 } = {}) {\n const list = this._popStackItem();\n const text = getText(list);\n if (text) {\n addText(this._stackItem, text, list.leadingLineBreaks, trailingLineBreaks);\n }\n }\n\n /**\n * Start building a table.\n */\n openTable () {\n this._stackItem = new TableStackItem(this._stackItem);\n }\n\n /**\n * Start building a table row.\n */\n openTableRow () {\n if (!(this._stackItem instanceof TableStackItem)) {\n throw new Error('Can\\'t add a table row to something that is not a table! Check the formatter.');\n }\n this._stackItem = new TableRowStackItem(this._stackItem);\n }\n\n /**\n * Start building a table cell.\n *\n * @param { object } [param0]\n * Object holding the parameters of the cell.\n *\n * @param { number } [param0.maxColumnWidth]\n * Wrap cell content to this width. Fall back to global wordwrap value if undefined.\n */\n openTableCell ({ maxColumnWidth = undefined } = {}) {\n if (!(this._stackItem instanceof TableRowStackItem)) {\n throw new Error('Can\\'t add a table cell to something that is not a table row! Check the formatter.');\n }\n this._stackItem = new TableCellStackItem(this.options, this._stackItem, maxColumnWidth);\n }\n\n /**\n * Finalize currently built table cell and add it to parent table row's cells.\n *\n * @param { object } [param0]\n * Object holding the parameters of the cell.\n *\n * @param { number } [param0.colspan] How many columns this cell should occupy.\n * @param { number } [param0.rowspan] How many rows this cell should occupy.\n */\n closeTableCell ({ colspan = 1, rowspan = 1 } = {}) {\n const cell = this._popStackItem();\n const text = trimCharacter(getText(cell), '\\n');\n cell.next.cells.push({ colspan: colspan, rowspan: rowspan, text: text });\n }\n\n /**\n * Finalize currently built table row and add it to parent table's rows.\n */\n closeTableRow () {\n const row = this._popStackItem();\n row.next.rows.push(row.cells);\n }\n\n /**\n * Finalize currently built table and add the rendered text to the parent block.\n *\n * @param { object } param0\n * Object holding the parameters of the table.\n *\n * @param { TablePrinter } param0.tableToString\n * A function to convert a table of stringified cells into a complete table.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This table should have at least this number of line breaks to separate if from any preceding block.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This table should have at least this number of line breaks to separate it from any following block.\n */\n closeTable ({ tableToString, leadingLineBreaks = 2, trailingLineBreaks = 2 }) {\n const table = this._popStackItem();\n const output = tableToString(table.rows);\n if (output) {\n addText(this._stackItem, output, leadingLineBreaks, trailingLineBreaks);\n }\n }\n\n /**\n * Return the rendered text content of this builder.\n *\n * @returns { string }\n */\n toString () {\n return getText(this._stackItem.getRoot());\n // There should only be the root item if everything is closed properly.\n }\n\n}\n\nfunction getText (stackItem) {\n if (!(\n stackItem instanceof BlockStackItem\n || stackItem instanceof ListItemStackItem\n || stackItem instanceof TableCellStackItem\n )) {\n throw new Error('Only blocks, list items and table cells can be requested for text contents.');\n }\n return (stackItem.inlineTextBuilder.isEmpty())\n ? stackItem.rawText\n : stackItem.rawText + stackItem.inlineTextBuilder.toString();\n}\n\nfunction addText (stackItem, text, leadingLineBreaks, trailingLineBreaks) {\n if (!(\n stackItem instanceof BlockStackItem\n || stackItem instanceof ListItemStackItem\n || stackItem instanceof TableCellStackItem\n )) {\n throw new Error('Only blocks, list items and table cells can contain text.');\n }\n const parentText = getText(stackItem);\n const lineBreaks = Math.max(stackItem.stashedLineBreaks, leadingLineBreaks);\n stackItem.inlineTextBuilder.clear();\n if (parentText) {\n stackItem.rawText = parentText + '\\n'.repeat(lineBreaks) + text;\n } else {\n stackItem.rawText = text;\n stackItem.leadingLineBreaks = lineBreaks;\n }\n stackItem.stashedLineBreaks = trailingLineBreaks;\n}\n\n/**\n * @param { string } str A string to transform.\n * @param { TransformerStackItem } transformer A transformer item (with possible continuation).\n * @returns { string }\n */\nfunction applyTransformer (str, transformer) {\n return ((transformer) ? applyTransformer(transformer.transform(str), transformer.next) : str);\n}\n\n/**\n * Compile selectors into a decision tree,\n * return a function intended for batch processing.\n *\n * @param { Options } [options = {}] HtmlToText options (defaults, formatters, user options merged, deduplicated).\n * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.\n * @static\n */\nfunction compile$1 (options = {}) {\n const selectorsWithoutFormat = options.selectors.filter(s => !s.format);\n if (selectorsWithoutFormat.length) {\n throw new Error(\n 'Following selectors have no specified format: ' +\n selectorsWithoutFormat.map(s => `\\`${s.selector}\\``).join(', ')\n );\n }\n const picker = new selderee.DecisionTree(\n options.selectors.map(s => [s.selector, s])\n ).build(pluginHtmlparser2.hp2Builder);\n\n if (typeof options.encodeCharacters !== 'function') {\n options.encodeCharacters = makeReplacerFromDict(options.encodeCharacters);\n }\n\n const baseSelectorsPicker = new selderee.DecisionTree(\n options.baseElements.selectors.map((s, i) => [s, i + 1])\n ).build(pluginHtmlparser2.hp2Builder);\n function findBaseElements (dom) {\n return findBases(dom, options, baseSelectorsPicker);\n }\n\n const limitedWalk = limitedDepthRecursive(\n options.limits.maxDepth,\n recursiveWalk,\n function (dom, builder) {\n builder.addInline(options.limits.ellipsis || '');\n }\n );\n\n return function (html, metadata = undefined) {\n return process(html, metadata, options, picker, findBaseElements, limitedWalk);\n };\n}\n\n\n/**\n * Convert given HTML according to preprocessed options.\n *\n * @param { string } html HTML content to convert.\n * @param { any } metadata Optional metadata for HTML document, for use in formatters.\n * @param { Options } options HtmlToText options (preprocessed).\n * @param { import('selderee').Picker<DomNode, TagDefinition> } picker\n * Tag definition picker for DOM nodes processing.\n * @param { (dom: DomNode[]) => DomNode[] } findBaseElements\n * Function to extract elements from HTML DOM\n * that will only be present in the output text.\n * @param { RecursiveCallback } walk Recursive callback.\n * @returns { string }\n */\nfunction process (html, metadata, options, picker, findBaseElements, walk) {\n const maxInputLength = options.limits.maxInputLength;\n if (maxInputLength && html && html.length > maxInputLength) {\n console.warn(\n `Input length ${html.length} is above allowed limit of ${maxInputLength}. Truncating without ellipsis.`\n );\n html = html.substring(0, maxInputLength);\n }\n\n const document = htmlparser2.parseDocument(html, { decodeEntities: options.decodeEntities });\n const bases = findBaseElements(document.children);\n const builder = new BlockTextBuilder(options, picker, metadata);\n walk(bases, builder);\n return builder.toString();\n}\n\n\nfunction findBases (dom, options, baseSelectorsPicker) {\n const results = [];\n\n function recursiveWalk (walk, /** @type { DomNode[] } */ dom) {\n dom = dom.slice(0, options.limits.maxChildNodes);\n for (const elem of dom) {\n if (elem.type !== 'tag') {\n continue;\n }\n const pickedSelectorIndex = baseSelectorsPicker.pick1(elem);\n if (pickedSelectorIndex > 0) {\n results.push({ selectorIndex: pickedSelectorIndex, element: elem });\n } else if (elem.children) {\n walk(elem.children);\n }\n if (results.length >= options.limits.maxBaseElements) {\n return;\n }\n }\n }\n\n const limitedWalk = limitedDepthRecursive(\n options.limits.maxDepth,\n recursiveWalk\n );\n limitedWalk(dom);\n\n if (options.baseElements.orderBy !== 'occurrence') { // 'selectors'\n results.sort((a, b) => a.selectorIndex - b.selectorIndex);\n }\n return (options.baseElements.returnDomByDefault && results.length === 0)\n ? dom\n : results.map(x => x.element);\n}\n\n/**\n * Function to walk through DOM nodes and accumulate their string representations.\n *\n * @param { RecursiveCallback } walk Recursive callback.\n * @param { DomNode[] } [dom] Nodes array to process.\n * @param { BlockTextBuilder } builder Passed around to accumulate output text.\n * @private\n */\nfunction recursiveWalk (walk, dom, builder) {\n if (!dom) { return; }\n\n const options = builder.options;\n\n const tooManyChildNodes = dom.length > options.limits.maxChildNodes;\n if (tooManyChildNodes) {\n dom = dom.slice(0, options.limits.maxChildNodes);\n dom.push({\n data: options.limits.ellipsis,\n type: 'text'\n });\n }\n\n for (const elem of dom) {\n switch (elem.type) {\n case 'text': {\n builder.addInline(elem.data);\n break;\n }\n case 'tag': {\n const tagDefinition = builder.picker.pick1(elem);\n const format = options.formatters[tagDefinition.format];\n format(elem, walk, builder, tagDefinition.options || {});\n break;\n }\n }\n }\n\n return;\n}\n\n/**\n * @param { Object<string,string | false> } dict\n * A dictionary where keys are characters to replace\n * and values are replacement strings.\n *\n * First code point from dict keys is used.\n * Compound emojis with ZWJ are not supported (not until Node 16).\n *\n * @returns { ((str: string) => string) | undefined }\n */\nfunction makeReplacerFromDict (dict) {\n if (!dict || Object.keys(dict).length === 0) {\n return undefined;\n }\n /** @type { [string, string][] } */\n const entries = Object.entries(dict).filter(([, v]) => v !== false);\n const regex = new RegExp(\n entries\n .map(([c]) => `(${unicodeEscape([...c][0])})`)\n .join('|'),\n 'g'\n );\n const values = entries.map(([, v]) => v);\n const replacer = (m, ...cgs) => values[cgs.findIndex(cg => cg)];\n return (str) => str.replace(regex, replacer);\n}\n\n/**\n * Dummy formatter that discards the input and does nothing.\n *\n * @type { FormatCallback }\n */\nfunction formatSkip (elem, walk, builder, formatOptions) {\n /* do nothing */\n}\n\n/**\n * Insert the given string literal inline instead of a tag.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineString (elem, walk, builder, formatOptions) {\n builder.addLiteral(formatOptions.string || '');\n}\n\n/**\n * Insert a block with the given string literal instead of a tag.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockString (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.addLiteral(formatOptions.string || '');\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process an inline-level element.\n *\n * @type { FormatCallback }\n */\nfunction formatInline (elem, walk, builder, formatOptions) {\n walk(elem.children, builder);\n}\n\n/**\n * Process a block-level container.\n *\n * @type { FormatCallback }\n */\nfunction formatBlock$1 (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\nfunction renderOpenTag (elem) {\n const attrs = (elem.attribs && elem.attribs.length)\n ? ' ' + Object.entries(elem.attribs)\n .map(([k, v]) => ((v === '') ? k : `${k}=${v.replace(/\"/g, '&quot;')}`))\n .join(' ')\n : '';\n return `<${elem.name}${attrs}>`;\n}\n\nfunction renderCloseTag (elem) {\n return `</${elem.name}>`;\n}\n\n/**\n * Render an element as inline HTML tag, walk through it's children.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineTag (elem, walk, builder, formatOptions) {\n builder.startNoWrap();\n builder.addLiteral(renderOpenTag(elem));\n builder.stopNoWrap();\n walk(elem.children, builder);\n builder.startNoWrap();\n builder.addLiteral(renderCloseTag(elem));\n builder.stopNoWrap();\n}\n\n/**\n * Render an element as HTML block bag, walk through it's children.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockTag (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.startNoWrap();\n builder.addLiteral(renderOpenTag(elem));\n builder.stopNoWrap();\n walk(elem.children, builder);\n builder.startNoWrap();\n builder.addLiteral(renderCloseTag(elem));\n builder.stopNoWrap();\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Render an element with all it's children as inline HTML.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineHtml (elem, walk, builder, formatOptions) {\n builder.startNoWrap();\n builder.addLiteral(\n domSerializer.render(elem, { decodeEntities: builder.options.decodeEntities })\n );\n builder.stopNoWrap();\n}\n\n/**\n * Render an element with all it's children as HTML block.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockHtml (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.startNoWrap();\n builder.addLiteral(\n domSerializer.render(elem, { decodeEntities: builder.options.decodeEntities })\n );\n builder.stopNoWrap();\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Render inline element wrapped with given strings.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineSurround (elem, walk, builder, formatOptions) {\n builder.addLiteral(formatOptions.prefix || '');\n walk(elem.children, builder);\n builder.addLiteral(formatOptions.suffix || '');\n}\n\nvar genericFormatters = /*#__PURE__*/Object.freeze({\n __proto__: null,\n block: formatBlock$1,\n blockHtml: formatBlockHtml,\n blockString: formatBlockString,\n blockTag: formatBlockTag,\n inline: formatInline,\n inlineHtml: formatInlineHtml,\n inlineString: formatInlineString,\n inlineSurround: formatInlineSurround,\n inlineTag: formatInlineTag,\n skip: formatSkip\n});\n\nfunction getRow (matrix, j) {\n if (!matrix[j]) { matrix[j] = []; }\n return matrix[j];\n}\n\nfunction findFirstVacantIndex (row, x = 0) {\n while (row[x]) { x++; }\n return x;\n}\n\nfunction transposeInPlace (matrix, maxSize) {\n for (let i = 0; i < maxSize; i++) {\n const rowI = getRow(matrix, i);\n for (let j = 0; j < i; j++) {\n const rowJ = getRow(matrix, j);\n if (rowI[j] || rowJ[i]) {\n const temp = rowI[j];\n rowI[j] = rowJ[i];\n rowJ[i] = temp;\n }\n }\n }\n}\n\nfunction putCellIntoLayout (cell, layout, baseRow, baseCol) {\n for (let r = 0; r < cell.rowspan; r++) {\n const layoutRow = getRow(layout, baseRow + r);\n for (let c = 0; c < cell.colspan; c++) {\n layoutRow[baseCol + c] = cell;\n }\n }\n}\n\nfunction getOrInitOffset (offsets, index) {\n if (offsets[index] === undefined) {\n offsets[index] = (index === 0) ? 0 : 1 + getOrInitOffset(offsets, index - 1);\n }\n return offsets[index];\n}\n\nfunction updateOffset (offsets, base, span, value) {\n offsets[base + span] = Math.max(\n getOrInitOffset(offsets, base + span),\n getOrInitOffset(offsets, base) + value\n );\n}\n\n/**\n * Render a table into a string.\n * Cells can contain multiline text and span across multiple rows and columns.\n *\n * Modifies cells to add lines array.\n *\n * @param { TablePrinterCell[][] } tableRows Table to render.\n * @param { number } rowSpacing Number of spaces between columns.\n * @param { number } colSpacing Number of empty lines between rows.\n * @returns { string }\n */\nfunction tableToString (tableRows, rowSpacing, colSpacing) {\n const layout = [];\n let colNumber = 0;\n const rowNumber = tableRows.length;\n const rowOffsets = [0];\n // Fill the layout table and row offsets row-by-row.\n for (let j = 0; j < rowNumber; j++) {\n const layoutRow = getRow(layout, j);\n const cells = tableRows[j];\n let x = 0;\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i];\n x = findFirstVacantIndex(layoutRow, x);\n putCellIntoLayout(cell, layout, j, x);\n x += cell.colspan;\n cell.lines = cell.text.split('\\n');\n const cellHeight = cell.lines.length;\n updateOffset(rowOffsets, j, cell.rowspan, cellHeight + rowSpacing);\n }\n colNumber = (layoutRow.length > colNumber) ? layoutRow.length : colNumber;\n }\n\n transposeInPlace(layout, (rowNumber > colNumber) ? rowNumber : colNumber);\n\n const outputLines = [];\n const colOffsets = [0];\n // Fill column offsets and output lines column-by-column.\n for (let x = 0; x < colNumber; x++) {\n let y = 0;\n let cell;\n const rowsInThisColumn = Math.min(rowNumber, layout[x].length);\n while (y < rowsInThisColumn) {\n cell = layout[x][y];\n if (cell) {\n if (!cell.rendered) {\n let cellWidth = 0;\n for (let j = 0; j < cell.lines.length; j++) {\n const line = cell.lines[j];\n const lineOffset = rowOffsets[y] + j;\n outputLines[lineOffset] = (outputLines[lineOffset] || '').padEnd(colOffsets[x]) + line;\n cellWidth = (line.length > cellWidth) ? line.length : cellWidth;\n }\n updateOffset(colOffsets, x, cell.colspan, cellWidth + colSpacing);\n cell.rendered = true;\n }\n y += cell.rowspan;\n } else {\n const lineOffset = rowOffsets[y];\n outputLines[lineOffset] = (outputLines[lineOffset] || '');\n y++;\n }\n }\n }\n\n return outputLines.join('\\n');\n}\n\n/**\n * Process a line-break.\n *\n * @type { FormatCallback }\n */\nfunction formatLineBreak (elem, walk, builder, formatOptions) {\n builder.addLineBreak();\n}\n\n/**\n * Process a `wbr` tag (word break opportunity).\n *\n * @type { FormatCallback }\n */\nfunction formatWbr (elem, walk, builder, formatOptions) {\n builder.addWordBreakOpportunity();\n}\n\n/**\n * Process a horizontal line.\n *\n * @type { FormatCallback }\n */\nfunction formatHorizontalLine (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.addInline('-'.repeat(formatOptions.length || builder.options.wordwrap || 40));\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a paragraph.\n *\n * @type { FormatCallback }\n */\nfunction formatParagraph (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a preformatted content.\n *\n * @type { FormatCallback }\n */\nfunction formatPre (elem, walk, builder, formatOptions) {\n builder.openBlock({\n isPre: true,\n leadingLineBreaks: formatOptions.leadingLineBreaks || 2\n });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a heading.\n *\n * @type { FormatCallback }\n */\nfunction formatHeading (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n if (formatOptions.uppercase !== false) {\n builder.pushWordTransform(str => str.toUpperCase());\n walk(elem.children, builder);\n builder.popWordTransform();\n } else {\n walk(elem.children, builder);\n }\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a blockquote.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockquote (elem, walk, builder, formatOptions) {\n builder.openBlock({\n leadingLineBreaks: formatOptions.leadingLineBreaks || 2,\n reservedLineLength: 2\n });\n walk(elem.children, builder);\n builder.closeBlock({\n trailingLineBreaks: formatOptions.trailingLineBreaks || 2,\n blockTransform: str => ((formatOptions.trimEmptyLines !== false) ? trimCharacter(str, '\\n') : str)\n .split('\\n')\n .map(line => '> ' + line)\n .join('\\n')\n });\n}\n\nfunction withBrackets (str, brackets) {\n if (!brackets) { return str; }\n\n const lbr = (typeof brackets[0] === 'string')\n ? brackets[0]\n : '[';\n const rbr = (typeof brackets[1] === 'string')\n ? brackets[1]\n : ']';\n return lbr + str + rbr;\n}\n\nfunction pathRewrite (path, rewriter, baseUrl, metadata, elem) {\n const modifiedPath = (typeof rewriter === 'function')\n ? rewriter(path, metadata, elem)\n : path;\n return (modifiedPath[0] === '/' && baseUrl)\n ? trimCharacterEnd(baseUrl, '/') + modifiedPath\n : modifiedPath;\n}\n\n/**\n * Process an image.\n *\n * @type { FormatCallback }\n */\nfunction formatImage (elem, walk, builder, formatOptions) {\n const attribs = elem.attribs || {};\n const alt = (attribs.alt)\n ? attribs.alt\n : '';\n const src = (!attribs.src)\n ? ''\n : pathRewrite(attribs.src, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);\n const text = (!src)\n ? alt\n : (!alt)\n ? withBrackets(src, formatOptions.linkBrackets)\n : alt + ' ' + withBrackets(src, formatOptions.linkBrackets);\n\n builder.addInline(text, { noWordTransform: true });\n}\n\n// a img baseUrl\n// a img pathRewrite\n// a img linkBrackets\n\n// a ignoreHref: false\n// ignoreText ?\n// a noAnchorUrl: true\n// can be replaced with selector\n// a hideLinkHrefIfSameAsText: false\n// how to compare, what to show (text, href, normalized) ?\n// a mailto protocol removed without options\n\n// a protocols: mailto, tel, ...\n// can be matched with selector?\n\n// anchors, protocols - only if no pathRewrite fn is provided\n\n// normalize-url ?\n\n// a\n// a[href^=\"#\"] - format:skip by default\n// a[href^=\"mailto:\"] - ?\n\n/**\n * Process an anchor.\n *\n * @type { FormatCallback }\n */\nfunction formatAnchor (elem, walk, builder, formatOptions) {\n function getHref () {\n if (formatOptions.ignoreHref) { return ''; }\n if (!elem.attribs || !elem.attribs.href) { return ''; }\n let href = elem.attribs.href.replace(/^mailto:/, '');\n if (formatOptions.noAnchorUrl && href[0] === '#') { return ''; }\n href = pathRewrite(href, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);\n return href;\n }\n const href = getHref();\n if (!href) {\n walk(elem.children, builder);\n } else {\n let text = '';\n builder.pushWordTransform(\n str => {\n if (str) { text += str; }\n return str;\n }\n );\n walk(elem.children, builder);\n builder.popWordTransform();\n\n const hideSameLink = formatOptions.hideLinkHrefIfSameAsText && href === text;\n if (!hideSameLink) {\n builder.addInline(\n (!text)\n ? href\n : ' ' + withBrackets(href, formatOptions.linkBrackets),\n { noWordTransform: true }\n );\n }\n }\n}\n\n/**\n * @param { DomNode } elem List items with their prefixes.\n * @param { RecursiveCallback } walk Recursive callback to process child nodes.\n * @param { BlockTextBuilder } builder Passed around to accumulate output text.\n * @param { FormatOptions } formatOptions Options specific to a formatter.\n * @param { () => string } nextPrefixCallback Function that returns increasing index each time it is called.\n */\nfunction formatList (elem, walk, builder, formatOptions, nextPrefixCallback) {\n const isNestedList = get(elem, ['parent', 'name']) === 'li';\n\n // With Roman numbers, index length is not as straightforward as with Arabic numbers or letters,\n // so the dumb length comparison is the most robust way to get the correct value.\n let maxPrefixLength = 0;\n const listItems = (elem.children || [])\n // it might be more accurate to check only for html spaces here, but no significant benefit\n .filter(child => child.type !== 'text' || !/^\\s*$/.test(child.data))\n .map(function (child) {\n if (child.name !== 'li') {\n return { node: child, prefix: '' };\n }\n const prefix = (isNestedList)\n ? nextPrefixCallback().trimStart()\n : nextPrefixCallback();\n if (prefix.length > maxPrefixLength) { maxPrefixLength = prefix.length; }\n return { node: child, prefix: prefix };\n });\n if (!listItems.length) { return; }\n\n builder.openList({\n interRowLineBreaks: 1,\n leadingLineBreaks: isNestedList ? 1 : (formatOptions.leadingLineBreaks || 2),\n maxPrefixLength: maxPrefixLength,\n prefixAlign: 'left'\n });\n\n for (const { node, prefix } of listItems) {\n builder.openListItem({ prefix: prefix });\n walk([node], builder);\n builder.closeListItem();\n }\n\n builder.closeList({ trailingLineBreaks: isNestedList ? 1 : (formatOptions.trailingLineBreaks || 2) });\n}\n\n/**\n * Process an unordered list.\n *\n * @type { FormatCallback }\n */\nfunction formatUnorderedList (elem, walk, builder, formatOptions) {\n const prefix = formatOptions.itemPrefix || ' * ';\n return formatList(elem, walk, builder, formatOptions, () => prefix);\n}\n\n/**\n * Process an ordered list.\n *\n * @type { FormatCallback }\n */\nfunction formatOrderedList (elem, walk, builder, formatOptions) {\n let nextIndex = Number(elem.attribs.start || '1');\n const indexFunction = getOrderedListIndexFunction(elem.attribs.type);\n const nextPrefixCallback = () => ' ' + indexFunction(nextIndex++) + '. ';\n return formatList(elem, walk, builder, formatOptions, nextPrefixCallback);\n}\n\n/**\n * Return a function that can be used to generate index markers of a specified format.\n *\n * @param { string } [olType='1'] Marker type.\n * @returns { (i: number) => string }\n */\nfunction getOrderedListIndexFunction (olType = '1') {\n switch (olType) {\n case 'a': return (i) => numberToLetterSequence(i, 'a');\n case 'A': return (i) => numberToLetterSequence(i, 'A');\n case 'i': return (i) => numberToRoman(i).toLowerCase();\n case 'I': return (i) => numberToRoman(i);\n case '1':\n default: return (i) => (i).toString();\n }\n}\n\n/**\n * Given a list of class and ID selectors (prefixed with '.' and '#'),\n * return them as separate lists of names without prefixes.\n *\n * @param { string[] } selectors Class and ID selectors (`[\".class\", \"#id\"]` etc).\n * @returns { { classes: string[], ids: string[] } }\n */\nfunction splitClassesAndIds (selectors) {\n const classes = [];\n const ids = [];\n for (const selector of selectors) {\n if (selector.startsWith('.')) {\n classes.push(selector.substring(1));\n } else if (selector.startsWith('#')) {\n ids.push(selector.substring(1));\n }\n }\n return { classes: classes, ids: ids };\n}\n\nfunction isDataTable (attr, tables) {\n if (tables === true) { return true; }\n if (!attr) { return false; }\n\n const { classes, ids } = splitClassesAndIds(tables);\n const attrClasses = (attr['class'] || '').split(' ');\n const attrIds = (attr['id'] || '').split(' ');\n\n return attrClasses.some(x => classes.includes(x)) || attrIds.some(x => ids.includes(x));\n}\n\n/**\n * Process a table (either as a container or as a data table, depending on options).\n *\n * @type { FormatCallback }\n */\nfunction formatTable (elem, walk, builder, formatOptions) {\n return isDataTable(elem.attribs, builder.options.tables)\n ? formatDataTable(elem, walk, builder, formatOptions)\n : formatBlock(elem, walk, builder, formatOptions);\n}\n\nfunction formatBlock (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks });\n}\n\n/**\n * Process a data table.\n *\n * @type { FormatCallback }\n */\nfunction formatDataTable (elem, walk, builder, formatOptions) {\n builder.openTable();\n elem.children.forEach(walkTable);\n builder.closeTable({\n tableToString: (rows) => tableToString(rows, formatOptions.rowSpacing ?? 0, formatOptions.colSpacing ?? 3),\n leadingLineBreaks: formatOptions.leadingLineBreaks,\n trailingLineBreaks: formatOptions.trailingLineBreaks\n });\n\n function formatCell (cellNode) {\n const colspan = +get(cellNode, ['attribs', 'colspan']) || 1;\n const rowspan = +get(cellNode, ['attribs', 'rowspan']) || 1;\n builder.openTableCell({ maxColumnWidth: formatOptions.maxColumnWidth });\n walk(cellNode.children, builder);\n builder.closeTableCell({ colspan: colspan, rowspan: rowspan });\n }\n\n function walkTable (elem) {\n if (elem.type !== 'tag') { return; }\n\n const formatHeaderCell = (formatOptions.uppercaseHeaderCells !== false)\n ? (cellNode) => {\n builder.pushWordTransform(str => str.toUpperCase());\n formatCell(cellNode);\n builder.popWordTransform();\n }\n : formatCell;\n\n switch (elem.name) {\n case 'thead':\n case 'tbody':\n case 'tfoot':\n case 'center':\n elem.children.forEach(walkTable);\n return;\n\n case 'tr': {\n builder.openTableRow();\n for (const childOfTr of elem.children) {\n if (childOfTr.type !== 'tag') { continue; }\n switch (childOfTr.name) {\n case 'th': {\n formatHeaderCell(childOfTr);\n break;\n }\n case 'td': {\n formatCell(childOfTr);\n break;\n }\n // do nothing\n }\n }\n builder.closeTableRow();\n break;\n }\n // do nothing\n }\n }\n}\n\nvar textFormatters = /*#__PURE__*/Object.freeze({\n __proto__: null,\n anchor: formatAnchor,\n blockquote: formatBlockquote,\n dataTable: formatDataTable,\n heading: formatHeading,\n horizontalLine: formatHorizontalLine,\n image: formatImage,\n lineBreak: formatLineBreak,\n orderedList: formatOrderedList,\n paragraph: formatParagraph,\n pre: formatPre,\n table: formatTable,\n unorderedList: formatUnorderedList,\n wbr: formatWbr\n});\n\n/**\n * Default options.\n *\n * @constant\n * @type { Options }\n * @default\n * @private\n */\nconst DEFAULT_OPTIONS = {\n baseElements: {\n selectors: [ 'body' ],\n orderBy: 'selectors', // 'selectors' | 'occurrence'\n returnDomByDefault: true\n },\n decodeEntities: true,\n encodeCharacters: {},\n formatters: {},\n limits: {\n ellipsis: '...',\n maxBaseElements: undefined,\n maxChildNodes: undefined,\n maxDepth: undefined,\n maxInputLength: (1 << 24) // 16_777_216\n },\n longWordSplit: {\n forceWrapOnLimit: false,\n wrapCharacters: []\n },\n preserveNewlines: false,\n selectors: [\n { selector: '*', format: 'inline' },\n {\n selector: 'a',\n format: 'anchor',\n options: {\n baseUrl: null,\n hideLinkHrefIfSameAsText: false,\n ignoreHref: false,\n linkBrackets: ['[', ']'],\n noAnchorUrl: true\n }\n },\n { selector: 'article', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'aside', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'blockquote',\n format: 'blockquote',\n options: { leadingLineBreaks: 2, trailingLineBreaks: 2, trimEmptyLines: true }\n },\n { selector: 'br', format: 'lineBreak' },\n { selector: 'div', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'footer', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'form', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'h1', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h2', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h3', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h4', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h5', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h6', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'header', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'hr',\n format: 'horizontalLine',\n options: { leadingLineBreaks: 2, length: undefined, trailingLineBreaks: 2 }\n },\n {\n selector: 'img',\n format: 'image',\n options: { baseUrl: null, linkBrackets: ['[', ']'] }\n },\n { selector: 'main', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'nav', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'ol',\n format: 'orderedList',\n options: { leadingLineBreaks: 2, trailingLineBreaks: 2 }\n },\n { selector: 'p', format: 'paragraph', options: { leadingLineBreaks: 2, trailingLineBreaks: 2 } },\n { selector: 'pre', format: 'pre', options: { leadingLineBreaks: 2, trailingLineBreaks: 2 } },\n { selector: 'section', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'table',\n format: 'table',\n options: {\n colSpacing: 3,\n leadingLineBreaks: 2,\n maxColumnWidth: 60,\n rowSpacing: 0,\n trailingLineBreaks: 2,\n uppercaseHeaderCells: true\n }\n },\n {\n selector: 'ul',\n format: 'unorderedList',\n options: { itemPrefix: ' * ', leadingLineBreaks: 2, trailingLineBreaks: 2 }\n },\n { selector: 'wbr', format: 'wbr' },\n ],\n tables: [], // deprecated\n whitespaceCharacters: ' \\t\\r\\n\\f\\u200b',\n wordwrap: 80\n};\n\nconst concatMerge = (acc, src, options) => [...acc, ...src];\nconst overwriteMerge = (acc, src, options) => [...src];\nconst selectorsMerge = (acc, src, options) => (\n (acc.some(s => typeof s === 'object'))\n ? concatMerge(acc, src) // selectors\n : overwriteMerge(acc, src) // baseElements.selectors\n);\n\n/**\n * Preprocess options, compile selectors into a decision tree,\n * return a function intended for batch processing.\n *\n * @param { Options } [options = {}] HtmlToText options.\n * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.\n * @static\n */\nfunction compile (options = {}) {\n options = merge__default[\"default\"](\n DEFAULT_OPTIONS,\n options,\n {\n arrayMerge: overwriteMerge,\n customMerge: (key) => ((key === 'selectors') ? selectorsMerge : undefined)\n }\n );\n options.formatters = Object.assign({}, genericFormatters, textFormatters, options.formatters);\n options.selectors = mergeDuplicatesPreferLast(options.selectors, (s => s.selector));\n\n handleDeprecatedOptions(options);\n\n return compile$1(options);\n}\n\n/**\n * Convert given HTML content to plain text string.\n *\n * @param { string } html HTML content to convert.\n * @param { Options } [options = {}] HtmlToText options.\n * @param { any } [metadata] Optional metadata for HTML document, for use in formatters.\n * @returns { string } Plain text string.\n * @static\n *\n * @example\n * const { convert } = require('html-to-text');\n * const text = convert('<h1>Hello World</h1>', {\n * wordwrap: 130\n * });\n * console.log(text); // HELLO WORLD\n */\nfunction convert (html, options = {}, metadata = undefined) {\n return compile(options)(html, metadata);\n}\n\n/**\n * Map previously existing and now deprecated options to the new options layout.\n * This is a subject for cleanup in major releases.\n *\n * @param { Options } options HtmlToText options.\n */\nfunction handleDeprecatedOptions (options) {\n if (options.tags) {\n const tagDefinitions = Object.entries(options.tags).map(\n ([selector, definition]) => ({ ...definition, selector: selector || '*' })\n );\n options.selectors.push(...tagDefinitions);\n options.selectors = mergeDuplicatesPreferLast(options.selectors, (s => s.selector));\n }\n\n function set (obj, path, value) {\n const valueKey = path.pop();\n for (const key of path) {\n let nested = obj[key];\n if (!nested) {\n nested = {};\n obj[key] = nested;\n }\n obj = nested;\n }\n obj[valueKey] = value;\n }\n\n if (options['baseElement']) {\n const baseElement = options['baseElement'];\n set(\n options,\n ['baseElements', 'selectors'],\n (Array.isArray(baseElement) ? baseElement : [baseElement])\n );\n }\n if (options['returnDomByDefault'] !== undefined) {\n set(options, ['baseElements', 'returnDomByDefault'], options['returnDomByDefault']);\n }\n\n for (const definition of options.selectors) {\n if (definition.format === 'anchor' && get(definition, ['options', 'noLinkBrackets'])) {\n set(definition, ['options', 'linkBrackets'], false);\n }\n }\n}\n\nexports.compile = compile;\nexports.convert = convert;\nexports.htmlToText = convert;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKGFjdGlvbi1icm93c2VyKS8uL25vZGVfbW9kdWxlcy9odG1sLXRvLXRleHQvbGliL2h0bWwtdG8tdGV4dC5janMiLCJtYXBwaW5ncyI6IkFBQWE7O0FBRWIsOENBQTZDLEVBQUUsYUFBYSxFQUFDOztBQUU3RCx3QkFBd0IsbUJBQU8sQ0FBQyxzSEFBOEI7QUFDOUQsa0JBQWtCLG1CQUFPLENBQUMsNkVBQWE7QUFDdkMsZUFBZSxtQkFBTyxDQUFDLDJFQUFVO0FBQ2pDLFlBQVksbUJBQU8sQ0FBQyx3RUFBVztBQUMvQixvQkFBb0IsbUJBQU8sQ0FBQyxtRkFBZ0I7O0FBRTVDLHFDQUFxQyw0REFBNEQ7O0FBRWpHOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHFCQUFxQjtBQUNuQyxjQUFjLHFCQUFxQjtBQUNuQyxjQUFjLHFCQUFxQjtBQUNuQyxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQTtBQUNBLGdDQUFnQztBQUNoQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtDQUErQztBQUMvQyxpREFBaUQ7QUFDakQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLHFCQUFxQjtBQUNqQyxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsNkJBQTZCLFFBQVE7QUFDckM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBEQUEwRCw4QkFBOEI7QUFDeEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFdBQVc7QUFDekIsY0FBYyxXQUFXO0FBQ3pCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjLFNBQVM7QUFDdkIsY0FBYyxTQUFTO0FBQ3ZCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSw2QkFBNkI7QUFDN0IsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFVBQVU7QUFDeEIsY0FBYyxVQUFVO0FBQ3hCO0FBQ0E7QUFDQSxnQkFBZ0IsYUFBYTtBQUM3QjtBQUNBLGdCQUFnQixhQUFhO0FBQzdCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjLFVBQVU7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwyREFBMkQ7O0FBRTNEO0FBQ0E7O0FBRUEsTUFBTSxPQUFPOztBQUViO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjLFVBQVU7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0MsZUFBZTtBQUNyRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixXQUFXO0FBQzNCLGdCQUFnQixnQkFBZ0I7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLDZCQUE2Qjs7QUFFN0I7QUFDQTs7QUFFQSxRQUFRLE9BQU87O0FBRWY7QUFDQSxnREFBZ0Q7O0FBRWhEOztBQUVBLFVBQVUsT0FBTzs7QUFFakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLHNCQUFzQjtBQUN0QjtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0EsOEJBQThCOztBQUU5QixlQUFlO0FBQ2Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFVBQVU7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0MsZ0JBQWdCO0FBQy9ELCtDQUErQyxnQkFBZ0I7QUFDL0Qsa0RBQWtELGdCQUFnQjtBQUNsRSw0REFBNEQsZ0JBQWdCO0FBQzVFOztBQUVBOztBQUVBLHFEQUFxRCxnQkFBZ0I7O0FBRXJFO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQiwwQkFBMEI7QUFDNUMsa0JBQWtCLDBCQUEwQjtBQUM1QyxrQkFBa0IsMEJBQTBCO0FBQzVDLGtCQUFrQiwwQkFBMEI7QUFDNUM7QUFDQTtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTixxQ0FBcUMsZ0JBQWdCOztBQUVyRDtBQUNBLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxvQkFBb0I7QUFDbEMsY0FBYyxvQkFBb0I7QUFDbEMsY0FBYyxvQkFBb0I7QUFDbEM7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsVUFBVTtBQUMxQixnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLFVBQVU7QUFDMUIsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixVQUFVO0FBQzFCLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLFVBQVU7QUFDMUIsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxVQUFVO0FBQ3hCLGNBQWMsb0RBQW9EO0FBQ2xFLGNBQWMsS0FBSztBQUNuQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsWUFBWTtBQUM1QjtBQUNBLGdCQUFnQix1QkFBdUI7QUFDdkM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsMEJBQTBCO0FBQ3hDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQiwwQkFBMEI7QUFDMUM7QUFDQTtBQUNBLGtDQUFrQztBQUNsQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlCQUFpQiwwQkFBMEI7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsVUFBVTtBQUN4QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLG9CQUFvQiwwQkFBMEIsSUFBSTtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7O0FBRVQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTs7QUFFUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQztBQUMzQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsU0FBUzs7QUFFVCw0QkFBNEI7O0FBRTVCO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQSxjQUFjLFVBQVU7QUFDeEI7QUFDQTtBQUNBLGNBQWMsVUFBVTtBQUN4QjtBQUNBO0FBQ0EsZUFBZSwrREFBK0QsSUFBSTtBQUNsRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsY0FBYywwQkFBMEI7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGdCQUFnQixxREFBcUQsSUFBSTtBQUN6RTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQSxjQUFjLG1CQUFtQjtBQUNqQztBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsY0FBYywyRkFBMkYsSUFBSTtBQUM3RztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGtCQUFrQixjQUFjLElBQUk7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsZUFBZSx5QkFBeUIsSUFBSTtBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsbUJBQW1CLDZCQUE2QixJQUFJO0FBQ3BEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkIsY0FBYyxTQUFTO0FBQ3ZCO0FBQ0Esb0JBQW9CLDJCQUEyQixJQUFJO0FBQ25EO0FBQ0E7QUFDQSwyQkFBMkIsZ0RBQWdEO0FBQzNFOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsY0FBYyxlQUFlO0FBQzdCO0FBQ0E7QUFDQSxjQUFjLFNBQVM7QUFDdkI7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0EsZ0JBQWdCLDhEQUE4RDtBQUM5RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLFNBQVM7QUFDckIsWUFBWSx1QkFBdUI7QUFDbkMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxVQUFVLGFBQWE7QUFDckMsY0FBYywyQ0FBMkM7QUFDekQ7QUFDQTtBQUNBLGdDQUFnQztBQUNoQztBQUNBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQyxXQUFXO0FBQ3REO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLFlBQVksTUFBTTtBQUNsQixZQUFZLFVBQVU7QUFDdEIsWUFBWSxvREFBb0Q7QUFDaEU7QUFDQSxZQUFZLGdDQUFnQztBQUM1QztBQUNBO0FBQ0EsWUFBWSxvQkFBb0I7QUFDaEMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0IsYUFBYSw0QkFBNEIsZUFBZTtBQUM5RTtBQUNBO0FBQ0E7O0FBRUEscURBQXFELHdDQUF3QztBQUM3RjtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBLDRDQUE0QyxZQUFZO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLG1EQUFtRDtBQUMxRSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx1REFBdUQ7QUFDdkQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsb0JBQW9CO0FBQ2xDLGNBQWMsb0JBQW9CO0FBQ2xDLGNBQWMsb0JBQW9CO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLGNBQWM7O0FBRWQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLCtEQUErRDtBQUMvRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsWUFBWSxnQ0FBZ0M7QUFDNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLHFCQUFxQjtBQUNuQztBQUNBO0FBQ0E7QUFDQSx3QkFBd0IseUJBQXlCO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQSxzQkFBc0IseURBQXlEO0FBQy9FO0FBQ0EsdUJBQXVCLDJEQUEyRDtBQUNsRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQSxzQkFBc0IseURBQXlEO0FBQy9FO0FBQ0EsdUJBQXVCLDJEQUEyRDtBQUNsRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw0Q0FBNEMsRUFBRSxHQUFHLHVCQUF1QixHQUFHO0FBQzNFO0FBQ0E7QUFDQSxhQUFhLFVBQVUsRUFBRSxNQUFNO0FBQy9COztBQUVBO0FBQ0EsY0FBYyxVQUFVO0FBQ3hCOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBLHNCQUFzQix5REFBeUQ7QUFDL0U7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUIsMkRBQTJEO0FBQ2xGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyxnREFBZ0Q7QUFDakY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0Esc0JBQXNCLHlEQUF5RDtBQUMvRTtBQUNBO0FBQ0EsaUNBQWlDLGdEQUFnRDtBQUNqRjtBQUNBO0FBQ0EsdUJBQXVCLDJEQUEyRDtBQUNsRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQSxvQkFBb0I7QUFDcEI7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBOztBQUVBO0FBQ0Esa0JBQWtCLGFBQWE7QUFDL0I7QUFDQSxvQkFBb0IsT0FBTztBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrQkFBa0Isa0JBQWtCO0FBQ3BDO0FBQ0Esb0JBQW9CLGtCQUFrQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksdUJBQXVCO0FBQ25DLFlBQVksU0FBUztBQUNyQixZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLGVBQWU7QUFDakM7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLGtCQUFrQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxrQkFBa0IsZUFBZTtBQUNqQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLHVCQUF1QjtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBLHNCQUFzQix5REFBeUQ7QUFDL0U7QUFDQSx1QkFBdUIsMkRBQTJEO0FBQ2xGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0Esc0JBQXNCLHlEQUF5RDtBQUMvRTtBQUNBLHVCQUF1QiwyREFBMkQ7QUFDbEY7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSx1QkFBdUIsMkRBQTJEO0FBQ2xGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0Esc0JBQXNCLHlEQUF5RDtBQUMvRTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsdUJBQXVCLDJEQUEyRDtBQUNsRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBLG1CQUFtQjs7QUFFbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDRCQUE0Qix1QkFBdUI7QUFDbkQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQSxvQ0FBb0M7QUFDcEMsK0NBQStDO0FBQy9DO0FBQ0Esd0RBQXdEO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxZQUFZLG9CQUFvQjtBQUNoQyxZQUFZLG9CQUFvQjtBQUNoQyxZQUFZLG9CQUFvQjtBQUNoQyxZQUFZLG9CQUFvQjtBQUNoQyxZQUFZLG9CQUFvQjtBQUNoQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QztBQUM3QyxlQUFlO0FBQ2YsS0FBSztBQUNMLDJCQUEyQjs7QUFFM0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUgsZUFBZSxlQUFlO0FBQzlCLDJCQUEyQixnQkFBZ0I7QUFDM0M7QUFDQTtBQUNBOztBQUVBLHNCQUFzQixnRkFBZ0Y7QUFDdEc7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksV0FBVztBQUN2QixnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYOztBQUVBO0FBQ0EseUJBQXlCO0FBQ3pCLGVBQWU7O0FBRWYsVUFBVSxlQUFlO0FBQ3pCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esc0JBQXNCLG9EQUFvRDtBQUMxRTtBQUNBLHVCQUF1QixzREFBc0Q7QUFDN0U7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVztBQUNYO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qiw4Q0FBOEM7QUFDMUU7QUFDQSw2QkFBNkIsb0NBQW9DO0FBQ2pFOztBQUVBO0FBQ0EsK0JBQStCOztBQUUvQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSwwQ0FBMEM7QUFDMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFdBQVc7QUFDWDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0Esc0JBQXNCO0FBQ3RCLGdCQUFnQjtBQUNoQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxNQUFNLGlDQUFpQztBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxNQUFNLGlEQUFpRCwrQ0FBK0M7QUFDdEcsTUFBTSwrQ0FBK0MsK0NBQStDO0FBQ3BHO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixLQUFLO0FBQ0wsTUFBTSxxQ0FBcUM7QUFDM0MsTUFBTSw2Q0FBNkMsK0NBQStDO0FBQ2xHLE1BQU0sZ0RBQWdELCtDQUErQztBQUNyRyxNQUFNLDhDQUE4QywrQ0FBK0M7QUFDbkcsTUFBTSw4Q0FBOEMsZ0VBQWdFO0FBQ3BILE1BQU0sOENBQThDLGdFQUFnRTtBQUNwSCxNQUFNLDhDQUE4QyxnRUFBZ0U7QUFDcEgsTUFBTSw4Q0FBOEMsZ0VBQWdFO0FBQ3BILE1BQU0sOENBQThDLGdFQUFnRTtBQUNwSCxNQUFNLDhDQUE4QyxnRUFBZ0U7QUFDcEgsTUFBTSxnREFBZ0QsK0NBQStDO0FBQ3JHO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCO0FBQ2pCLEtBQUs7QUFDTCxNQUFNLDhDQUE4QywrQ0FBK0M7QUFDbkcsTUFBTSw2Q0FBNkMsK0NBQStDO0FBQ2xHO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQjtBQUNqQixLQUFLO0FBQ0wsTUFBTSwrQ0FBK0MsK0NBQStDO0FBQ3BHLE1BQU0sMkNBQTJDLCtDQUErQztBQUNoRyxNQUFNLGlEQUFpRCwrQ0FBK0M7QUFDdEc7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakIsS0FBSztBQUNMLE1BQU0sZ0NBQWdDO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFVBQVUsYUFBYTtBQUNyQyxjQUFjLDJDQUEyQztBQUN6RDtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUM7QUFDdkM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFVBQVU7QUFDeEIsY0FBYyxVQUFVLGFBQWE7QUFDckMsY0FBYyxVQUFVO0FBQ3hCLGNBQWMseUJBQXlCO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBLFdBQVcsVUFBVTtBQUNyQjtBQUNBO0FBQ0EsSUFBSTtBQUNKLHNCQUFzQjtBQUN0QjtBQUNBLG9DQUFvQztBQUNwQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxVQUFVO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLDBDQUEwQztBQUMvRTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZUFBZTtBQUNmLGVBQWU7QUFDZixrQkFBa0IiLCJzb3VyY2VzIjpbIi9ob21lL2FsbWEvbmV4dGdlbi9OZWFoLW1haWwvbm9kZV9tb2R1bGVzL2h0bWwtdG8tdGV4dC9saWIvaHRtbC10by10ZXh0LmNqcyJdLCJzb3VyY2VzQ29udGVudCI6WyIndXNlIHN0cmljdCc7XG5cbk9iamVjdC5kZWZpbmVQcm9wZXJ0eShleHBvcnRzLCAnX19lc01vZHVsZScsIHsgdmFsdWU6IHRydWUgfSk7XG5cbnZhciBwbHVnaW5IdG1scGFyc2VyMiA9IHJlcXVpcmUoJ0BzZWxkZXJlZS9wbHVnaW4taHRtbHBhcnNlcjInKTtcbnZhciBodG1scGFyc2VyMiA9IHJlcXVpcmUoJ2h0bWxwYXJzZXIyJyk7XG52YXIgc2VsZGVyZWUgPSByZXF1aXJlKCdzZWxkZXJlZScpO1xudmFyIG1lcmdlID0gcmVxdWlyZSgnZGVlcG1lcmdlJyk7XG52YXIgZG9tU2VyaWFsaXplciA9IHJlcXVpcmUoJ2RvbS1zZXJpYWxpemVyJyk7XG5cbmZ1bmN0aW9uIF9pbnRlcm9wRGVmYXVsdExlZ2FjeSAoZSkgeyByZXR1cm4gZSAmJiB0eXBlb2YgZSA9PT0gJ29iamVjdCcgJiYgJ2RlZmF1bHQnIGluIGUgPyBlIDogeyAnZGVmYXVsdCc6IGUgfTsgfVxuXG52YXIgbWVyZ2VfX2RlZmF1bHQgPSAvKiNfX1BVUkVfXyovX2ludGVyb3BEZWZhdWx0TGVnYWN5KG1lcmdlKTtcblxuLyoqXG4gKiBNYWtlIGEgcmVjdXJzaXZlIGZ1bmN0aW9uIHRoYXQgd2lsbCBvbmx5IHJ1biB0byBhIGdpdmVuIGRlcHRoXG4gKiBhbmQgc3dpdGNoZXMgdG8gYW4gYWx0ZXJuYXRpdmUgZnVuY3Rpb24gYXQgdGhhdCBkZXB0aC4gXFxcbiAqIE5vIGxpbWl0YXRpb24gaWYgYG5gIGlzIGB1bmRlZmluZWRgIChKdXN0IHdyYXBzIGBmYCBpbiB0aGF0IGNhc2UpLlxuICpcbiAqIEBwYXJhbSAgIHsgbnVtYmVyIHwgdW5kZWZpbmVkIH0gbiAgIEFsbG93ZWQgZGVwdGggb2YgcmVjdXJzaW9uLiBgdW5kZWZpbmVkYCBmb3Igbm8gbGltaXRhdGlvbi5cbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSAgICAgICAgICAgZiAgIEZ1bmN0aW9uIHRoYXQgYWNjZXB0cyByZWN1cnNpdmUgY2FsbGJhY2sgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LlxuICogQHBhcmFtICAgeyBGdW5jdGlvbiB9ICAgICAgICAgICBbZ10gRnVuY3Rpb24gdG8gcnVuIGluc3RlYWQsIHdoZW4gbWF4aW11bSBkZXB0aCB3YXMgcmVhY2hlZC4gRG8gbm90aGluZyBieSBkZWZhdWx0LlxuICogQHJldHVybnMgeyBGdW5jdGlvbiB9XG4gKi9cbmZ1bmN0aW9uIGxpbWl0ZWREZXB0aFJlY3Vyc2l2ZSAobiwgZiwgZyA9ICgpID0+IHVuZGVmaW5lZCkge1xuICBpZiAobiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZjEgPSBmdW5jdGlvbiAoLi4uYXJncykgeyByZXR1cm4gZihmMSwgLi4uYXJncyk7IH07XG4gICAgcmV0dXJuIGYxO1xuICB9XG4gIGlmIChuID49IDApIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKC4uLmFyZ3MpIHsgcmV0dXJuIGYobGltaXRlZERlcHRoUmVjdXJzaXZlKG4gLSAxLCBmLCBnKSwgLi4uYXJncyk7IH07XG4gIH1cbiAgcmV0dXJuIGc7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBzYW1lIHN0cmluZyBvciBhIHN1YnN0cmluZyB3aXRoXG4gKiB0aGUgZ2l2ZW4gY2hhcmFjdGVyIG9jY3VycmVuY2VzIHJlbW92ZWQgZnJvbSBlYWNoIHNpZGUuXG4gKlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSBzdHIgIEEgc3RyaW5nIHRvIHRyaW0uXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IGNoYXIgQSBjaGFyYWN0ZXIgdG8gYmUgdHJpbW1lZC5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gdHJpbUNoYXJhY3RlciAoc3RyLCBjaGFyKSB7XG4gIGxldCBzdGFydCA9IDA7XG4gIGxldCBlbmQgPSBzdHIubGVuZ3RoO1xuICB3aGlsZSAoc3RhcnQgPCBlbmQgJiYgc3RyW3N0YXJ0XSA9PT0gY2hhcikgeyArK3N0YXJ0OyB9XG4gIHdoaWxlIChlbmQgPiBzdGFydCAmJiBzdHJbZW5kIC0gMV0gPT09IGNoYXIpIHsgLS1lbmQ7IH1cbiAgcmV0dXJuIChzdGFydCA+IDAgfHwgZW5kIDwgc3RyLmxlbmd0aClcbiAgICA/IHN0ci5zdWJzdHJpbmcoc3RhcnQsIGVuZClcbiAgICA6IHN0cjtcbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIHNhbWUgc3RyaW5nIG9yIGEgc3Vic3RyaW5nIHdpdGhcbiAqIHRoZSBnaXZlbiBjaGFyYWN0ZXIgb2NjdXJyZW5jZXMgcmVtb3ZlZCBmcm9tIHRoZSBlbmQgb25seS5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IHN0ciAgQSBzdHJpbmcgdG8gdHJpbS5cbiAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gY2hhciBBIGNoYXJhY3RlciB0byBiZSB0cmltbWVkLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiB0cmltQ2hhcmFjdGVyRW5kIChzdHIsIGNoYXIpIHtcbiAgbGV0IGVuZCA9IHN0ci5sZW5ndGg7XG4gIHdoaWxlIChlbmQgPiAwICYmIHN0cltlbmQgLSAxXSA9PT0gY2hhcikgeyAtLWVuZDsgfVxuICByZXR1cm4gKGVuZCA8IHN0ci5sZW5ndGgpXG4gICAgPyBzdHIuc3Vic3RyaW5nKDAsIGVuZClcbiAgICA6IHN0cjtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBuZXcgc3RyaW5nIHdpbGwgYWxsIGNoYXJhY3RlcnMgcmVwbGFjZWQgd2l0aCB1bmljb2RlIGVzY2FwZSBzZXF1ZW5jZXMuXG4gKiBUaGlzIGV4dHJlbWUga2luZCBvZiBlc2NhcGluZyBjYW4gdXNlZCB0byBiZSBzYWZlbHkgY29tcG9zZSByZWd1bGFyIGV4cHJlc3Npb25zLlxuICpcbiAqIEBwYXJhbSB7IHN0cmluZyB9IHN0ciBBIHN0cmluZyB0byBlc2NhcGUuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9IEEgc3RyaW5nIG9mIHVuaWNvZGUgZXNjYXBlIHNlcXVlbmNlcy5cbiAqL1xuZnVuY3Rpb24gdW5pY29kZUVzY2FwZSAoc3RyKSB7XG4gIHJldHVybiBzdHIucmVwbGFjZSgvW1xcc1xcU10vZywgYyA9PiAnXFxcXHUnICsgYy5jaGFyQ29kZUF0KCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDQsICcwJykpO1xufVxuXG4vKipcbiAqIERlZHVwbGljYXRlIGFuIGFycmF5IGJ5IGEgZ2l2ZW4ga2V5IGNhbGxiYWNrLlxuICogSXRlbSBwcm9wZXJ0aWVzIGFyZSBtZXJnZWQgcmVjdXJzaXZlbHkgYW5kIHdpdGggdGhlIHByZWZlcmVuY2UgZm9yIGxhc3QgZGVmaW5lZCB2YWx1ZXMuXG4gKiBPZiBpdGVtcyB3aXRoIHRoZSBzYW1lIGtleSwgbWVyZ2VkIGl0ZW0gdGFrZXMgdGhlIHBsYWNlIG9mIHRoZSBsYXN0IGl0ZW0sXG4gKiBvdGhlcnMgYXJlIG9taXR0ZWQuXG4gKlxuICogQHBhcmFtIHsgYW55W10gfSBpdGVtcyBBbiBhcnJheSB0byBkZWR1cGxpY2F0ZS5cbiAqIEBwYXJhbSB7ICh4OiBhbnkpID0+IHN0cmluZyB9IGdldEtleSBDYWxsYmFjayB0byBnZXQgYSB2YWx1ZSB0aGF0IGRpc3Rpbmd1aXNoZXMgdW5pcXVlIGl0ZW1zLlxuICogQHJldHVybnMgeyBhbnlbXSB9XG4gKi9cbmZ1bmN0aW9uIG1lcmdlRHVwbGljYXRlc1ByZWZlckxhc3QgKGl0ZW1zLCBnZXRLZXkpIHtcbiAgY29uc3QgbWFwID0gbmV3IE1hcCgpO1xuICBmb3IgKGxldCBpID0gaXRlbXMubGVuZ3RoOyBpLS0gPiAwOykge1xuICAgIGNvbnN0IGl0ZW0gPSBpdGVtc1tpXTtcbiAgICBjb25zdCBrZXkgPSBnZXRLZXkoaXRlbSk7XG4gICAgbWFwLnNldChcbiAgICAgIGtleSxcbiAgICAgIChtYXAuaGFzKGtleSkpXG4gICAgICAgID8gbWVyZ2VfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKGl0ZW0sIG1hcC5nZXQoa2V5KSwgeyBhcnJheU1lcmdlOiBvdmVyd3JpdGVNZXJnZSQxIH0pXG4gICAgICAgIDogaXRlbVxuICAgICk7XG4gIH1cbiAgcmV0dXJuIFsuLi5tYXAudmFsdWVzKCldLnJldmVyc2UoKTtcbn1cblxuY29uc3Qgb3ZlcndyaXRlTWVyZ2UkMSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gWy4uLnNyY107XG5cbi8qKlxuICogR2V0IGEgbmVzdGVkIHByb3BlcnR5IGZyb20gYW4gb2JqZWN0LlxuICpcbiAqIEBwYXJhbSAgIHsgb2JqZWN0IH0gICBvYmogIFRoZSBvYmplY3QgdG8gcXVlcnkgZm9yIHRoZSB2YWx1ZS5cbiAqIEBwYXJhbSAgIHsgc3RyaW5nW10gfSBwYXRoIFRoZSBwYXRoIHRvIHRoZSBwcm9wZXJ0eS5cbiAqIEByZXR1cm5zIHsgYW55IH1cbiAqL1xuZnVuY3Rpb24gZ2V0IChvYmosIHBhdGgpIHtcbiAgZm9yIChjb25zdCBrZXkgb2YgcGF0aCkge1xuICAgIGlmICghb2JqKSB7IHJldHVybiB1bmRlZmluZWQ7IH1cbiAgICBvYmogPSBvYmpba2V5XTtcbiAgfVxuICByZXR1cm4gb2JqO1xufVxuXG4vKipcbiAqIENvbnZlcnQgYSBudW1iZXIgaW50byBhbHBoYWJldGljIHNlcXVlbmNlIHJlcHJlc2VudGF0aW9uIChTZXF1ZW5jZSB3aXRob3V0IHplcm9lcykuXG4gKlxuICogRm9yIGV4YW1wbGU6IGBhLCAuLi4sIHosIGFhLCAuLi4sIHp6LCBhYWEsIC4uLmAuXG4gKlxuICogQHBhcmFtICAgeyBudW1iZXIgfSBudW0gICAgICAgICAgICAgIE51bWJlciB0byBjb252ZXJ0LiBNdXN0IGJlID49IDEuXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IFtiYXNlQ2hhciA9ICdhJ10gQ2hhcmFjdGVyIGZvciAxIGluIHRoZSBzZXF1ZW5jZS5cbiAqIEBwYXJhbSAgIHsgbnVtYmVyIH0gW2Jhc2UgPSAyNl0gICAgICBOdW1iZXIgb2YgY2hhcmFjdGVycyBpbiB0aGUgc2VxdWVuY2UuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIG51bWJlclRvTGV0dGVyU2VxdWVuY2UgKG51bSwgYmFzZUNoYXIgPSAnYScsIGJhc2UgPSAyNikge1xuICBjb25zdCBkaWdpdHMgPSBbXTtcbiAgZG8ge1xuICAgIG51bSAtPSAxO1xuICAgIGRpZ2l0cy5wdXNoKG51bSAlIGJhc2UpO1xuICAgIG51bSA9IChudW0gLyBiYXNlKSA+PiAwOyAvLyBxdWljayBgZmxvb3JgXG4gIH0gd2hpbGUgKG51bSA+IDApO1xuICBjb25zdCBiYXNlQ29kZSA9IGJhc2VDaGFyLmNoYXJDb2RlQXQoMCk7XG4gIHJldHVybiBkaWdpdHNcbiAgICAucmV2ZXJzZSgpXG4gICAgLm1hcChuID0+IFN0cmluZy5mcm9tQ2hhckNvZGUoYmFzZUNvZGUgKyBuKSlcbiAgICAuam9pbignJyk7XG59XG5cbmNvbnN0IEkgPSBbJ0knLCAnWCcsICdDJywgJ00nXTtcbmNvbnN0IFYgPSBbJ1YnLCAnTCcsICdEJ107XG5cbi8qKlxuICogQ29udmVydCBhIG51bWJlciB0byBpdCdzIFJvbWFuIHJlcHJlc2VudGF0aW9uLiBObyBsYXJnZSBudW1iZXJzIGV4dGVuc2lvbi5cbiAqXG4gKiBAcGFyYW0gICB7IG51bWJlciB9IG51bSBOdW1iZXIgdG8gY29udmVydC4gYDAgPCBudW0gPD0gMzk5OWAuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIG51bWJlclRvUm9tYW4gKG51bSkge1xuICByZXR1cm4gWy4uLihudW0pICsgJyddXG4gICAgLm1hcChuID0+ICtuKVxuICAgIC5yZXZlcnNlKClcbiAgICAubWFwKCh2LCBpKSA9PiAoKHYgJSA1IDwgNClcbiAgICAgID8gKHYgPCA1ID8gJycgOiBWW2ldKSArIElbaV0ucmVwZWF0KHYgJSA1KVxuICAgICAgOiBJW2ldICsgKHYgPCA1ID8gVltpXSA6IElbaSArIDFdKSkpXG4gICAgLnJldmVyc2UoKVxuICAgIC5qb2luKCcnKTtcbn1cblxuLyoqXG4gKiBIZWxwcyB0byBidWlsZCB0ZXh0IGZyb20gd29yZHMuXG4gKi9cbmNsYXNzIElubGluZVRleHRCdWlsZGVyIHtcbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgSW5saW5lVGV4dEJ1aWxkZXIuXG4gICAqXG4gICAqIElmIGBtYXhMaW5lTGVuZ3RoYCBpcyBub3QgcHJvdmlkZWQgdGhlbiBpdCBpcyBlaXRoZXIgYG9wdGlvbnMud29yZHdyYXBgIG9yIHVubGltaXRlZC5cbiAgICpcbiAgICogQHBhcmFtIHsgT3B0aW9ucyB9IG9wdGlvbnMgICAgICAgICAgIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gIFsgbWF4TGluZUxlbmd0aCBdIFRoaXMgYnVpbGRlciB3aWxsIHRyeSB0byB3cmFwIHRleHQgdG8gZml0IHRoaXMgbGluZSBsZW5ndGguXG4gICAqL1xuICBjb25zdHJ1Y3RvciAob3B0aW9ucywgbWF4TGluZUxlbmd0aCA9IHVuZGVmaW5lZCkge1xuICAgIC8qKiBAdHlwZSB7IHN0cmluZ1tdW10gfSAqL1xuICAgIHRoaXMubGluZXMgPSBbXTtcbiAgICAvKiogQHR5cGUgeyBzdHJpbmdbXSB9ICAgKi9cbiAgICB0aGlzLm5leHRMaW5lV29yZHMgPSBbXTtcbiAgICB0aGlzLm1heExpbmVMZW5ndGggPSBtYXhMaW5lTGVuZ3RoIHx8IG9wdGlvbnMud29yZHdyYXAgfHwgTnVtYmVyLk1BWF9WQUxVRTtcbiAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgPSB0aGlzLm1heExpbmVMZW5ndGg7XG4gICAgdGhpcy53cmFwQ2hhcmFjdGVycyA9IGdldChvcHRpb25zLCBbJ2xvbmdXb3JkU3BsaXQnLCAnd3JhcENoYXJhY3RlcnMnXSkgfHwgW107XG4gICAgdGhpcy5mb3JjZVdyYXBPbkxpbWl0ID0gZ2V0KG9wdGlvbnMsIFsnbG9uZ1dvcmRTcGxpdCcsICdmb3JjZVdyYXBPbkxpbWl0J10pIHx8IGZhbHNlO1xuXG4gICAgdGhpcy5zdGFzaGVkU3BhY2UgPSBmYWxzZTtcbiAgICB0aGlzLndvcmRCcmVha09wcG9ydHVuaXR5ID0gZmFsc2U7XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbmV3IHdvcmQuXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9IHdvcmQgQSB3b3JkIHRvIGFkZC5cbiAgICogQHBhcmFtIHsgYm9vbGVhbiB9IFtub1dyYXBdIERvbid0IHdyYXAgdGV4dCBldmVuIGlmIHRoZSBsaW5lIGlzIHRvbyBsb25nLlxuICAgKi9cbiAgcHVzaFdvcmQgKHdvcmQsIG5vV3JhcCA9IGZhbHNlKSB7XG4gICAgaWYgKHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyA8PSAwICYmICFub1dyYXApIHtcbiAgICAgIHRoaXMuc3RhcnROZXdMaW5lKCk7XG4gICAgfVxuICAgIGNvbnN0IGlzTGluZVN0YXJ0ID0gdGhpcy5uZXh0TGluZVdvcmRzLmxlbmd0aCA9PT0gMDtcbiAgICBjb25zdCBjb3N0ID0gd29yZC5sZW5ndGggKyAoaXNMaW5lU3RhcnQgPyAwIDogMSk7XG4gICAgaWYgKChjb3N0IDw9IHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycykgfHwgbm9XcmFwKSB7IC8vIEZpdHMgaW50byBhdmFpbGFibGUgYnVkZ2V0XG5cbiAgICAgIHRoaXMubmV4dExpbmVXb3Jkcy5wdXNoKHdvcmQpO1xuICAgICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzIC09IGNvc3Q7XG5cbiAgICB9IGVsc2UgeyAvLyBEb2VzIG5vdCBmaXQgLSB0cnkgdG8gc3BsaXQgdGhlIHdvcmRcblxuICAgICAgLy8gVGhlIHdvcmQgaXMgbW92ZWQgdG8gYSBuZXcgbGluZSAtIHByZWZlciB0byB3cmFwIGJldHdlZW4gd29yZHMuXG4gICAgICBjb25zdCBbZmlyc3QsIC4uLnJlc3RdID0gdGhpcy5zcGxpdExvbmdXb3JkKHdvcmQpO1xuICAgICAgaWYgKCFpc0xpbmVTdGFydCkgeyB0aGlzLnN0YXJ0TmV3TGluZSgpOyB9XG4gICAgICB0aGlzLm5leHRMaW5lV29yZHMucHVzaChmaXJzdCk7XG4gICAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgLT0gZmlyc3QubGVuZ3RoO1xuICAgICAgZm9yIChjb25zdCBwYXJ0IG9mIHJlc3QpIHtcbiAgICAgICAgdGhpcy5zdGFydE5ld0xpbmUoKTtcbiAgICAgICAgdGhpcy5uZXh0TGluZVdvcmRzLnB1c2gocGFydCk7XG4gICAgICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyAtPSBwYXJ0Lmxlbmd0aDtcbiAgICAgIH1cblxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBQb3AgYSB3b3JkIGZyb20gdGhlIGN1cnJlbnRseSBidWlsdCBsaW5lLlxuICAgKiBUaGlzIGRvZXNuJ3QgYWZmZWN0IGNvbXBsZXRlZCBsaW5lcy5cbiAgICpcbiAgICogQHJldHVybnMgeyBzdHJpbmcgfVxuICAgKi9cbiAgcG9wV29yZCAoKSB7XG4gICAgY29uc3QgbGFzdFdvcmQgPSB0aGlzLm5leHRMaW5lV29yZHMucG9wKCk7XG4gICAgaWYgKGxhc3RXb3JkICE9PSB1bmRlZmluZWQpIHtcbiAgICAgIGNvbnN0IGlzTGluZVN0YXJ0ID0gdGhpcy5uZXh0TGluZVdvcmRzLmxlbmd0aCA9PT0gMDtcbiAgICAgIGNvbnN0IGNvc3QgPSBsYXN0V29yZC5sZW5ndGggKyAoaXNMaW5lU3RhcnQgPyAwIDogMSk7XG4gICAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgKz0gY29zdDtcbiAgICB9XG4gICAgcmV0dXJuIGxhc3RXb3JkO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbmNhdCBhIHdvcmQgdG8gdGhlIGxhc3Qgd29yZCBhbHJlYWR5IGluIHRoZSBidWlsZGVyLlxuICAgKiBBZGRzIGEgbmV3IHdvcmQgaW4gY2FzZSB0aGVyZSBhcmUgbm8gd29yZHMgeWV0IGluIHRoZSBsYXN0IGxpbmUuXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9IHdvcmQgQSB3b3JkIHRvIGJlIGNvbmNhdGVuYXRlZC5cbiAgICogQHBhcmFtIHsgYm9vbGVhbiB9IFtub1dyYXBdIERvbid0IHdyYXAgdGV4dCBldmVuIGlmIHRoZSBsaW5lIGlzIHRvbyBsb25nLlxuICAgKi9cbiAgY29uY2F0V29yZCAod29yZCwgbm9XcmFwID0gZmFsc2UpIHtcbiAgICBpZiAodGhpcy53b3JkQnJlYWtPcHBvcnR1bml0eSAmJiB3b3JkLmxlbmd0aCA+IHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycykge1xuICAgICAgdGhpcy5wdXNoV29yZCh3b3JkLCBub1dyYXApO1xuICAgICAgdGhpcy53b3JkQnJlYWtPcHBvcnR1bml0eSA9IGZhbHNlO1xuICAgIH0gZWxzZSB7XG4gICAgICBjb25zdCBsYXN0V29yZCA9IHRoaXMucG9wV29yZCgpO1xuICAgICAgdGhpcy5wdXNoV29yZCgobGFzdFdvcmQpID8gbGFzdFdvcmQuY29uY2F0KHdvcmQpIDogd29yZCwgbm9XcmFwKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGN1cnJlbnQgbGluZSAoYW5kIG1vcmUgZW1wdHkgbGluZXMgaWYgcHJvdmlkZWQgYXJndW1lbnQgPiAxKSB0byB0aGUgbGlzdCBvZiBjb21wbGV0ZSBsaW5lcyBhbmQgc3RhcnQgYSBuZXcgb25lLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBuIE51bWJlciBvZiBsaW5lIGJyZWFrcyB0aGF0IHdpbGwgYmUgYWRkZWQgdG8gdGhlIHJlc3VsdGluZyBzdHJpbmcuXG4gICAqL1xuICBzdGFydE5ld0xpbmUgKG4gPSAxKSB7XG4gICAgdGhpcy5saW5lcy5wdXNoKHRoaXMubmV4dExpbmVXb3Jkcyk7XG4gICAgaWYgKG4gPiAxKSB7XG4gICAgICB0aGlzLmxpbmVzLnB1c2goLi4uQXJyYXkuZnJvbSh7IGxlbmd0aDogbiAtIDEgfSwgKCkgPT4gW10pKTtcbiAgICB9XG4gICAgdGhpcy5uZXh0TGluZVdvcmRzID0gW107XG4gICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzID0gdGhpcy5tYXhMaW5lTGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIE5vIHdvcmRzIGluIHRoaXMgYnVpbGRlci5cbiAgICpcbiAgICogQHJldHVybnMgeyBib29sZWFuIH1cbiAgICovXG4gIGlzRW1wdHkgKCkge1xuICAgIHJldHVybiB0aGlzLmxpbmVzLmxlbmd0aCA9PT0gMFxuICAgICAgICAmJiB0aGlzLm5leHRMaW5lV29yZHMubGVuZ3RoID09PSAwO1xuICB9XG5cbiAgY2xlYXIgKCkge1xuICAgIHRoaXMubGluZXMubGVuZ3RoID0gMDtcbiAgICB0aGlzLm5leHRMaW5lV29yZHMubGVuZ3RoID0gMDtcbiAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgPSB0aGlzLm1heExpbmVMZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogSm9pbiBhbGwgbGluZXMgb2Ygd29yZHMgaW5zaWRlIHRoZSBJbmxpbmVUZXh0QnVpbGRlciBpbnRvIGEgY29tcGxldGUgc3RyaW5nLlxuICAgKlxuICAgKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gICAqL1xuICB0b1N0cmluZyAoKSB7XG4gICAgcmV0dXJuIFsuLi50aGlzLmxpbmVzLCB0aGlzLm5leHRMaW5lV29yZHNdXG4gICAgICAubWFwKHdvcmRzID0+IHdvcmRzLmpvaW4oJyAnKSlcbiAgICAgIC5qb2luKCdcXG4nKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTcGxpdCBhIGxvbmcgd29yZCB1cCB0byBmaXQgd2l0aGluIHRoZSB3b3JkIHdyYXAgbGltaXQuXG4gICAqIFVzZSBlaXRoZXIgYSBjaGFyYWN0ZXIgdG8gc3BsaXQgbG9va2luZyBiYWNrIGZyb20gdGhlIHdvcmQgd3JhcCBsaW1pdCxcbiAgICogb3IgdHJ1bmNhdGUgdG8gdGhlIHdvcmQgd3JhcCBsaW1pdC5cbiAgICpcbiAgICogQHBhcmFtICAgeyBzdHJpbmcgfSAgIHdvcmQgSW5wdXQgd29yZC5cbiAgICogQHJldHVybnMgeyBzdHJpbmdbXSB9ICAgICAgUGFydHMgb2YgdGhlIHdvcmQuXG4gICAqL1xuICBzcGxpdExvbmdXb3JkICh3b3JkKSB7XG4gICAgY29uc3QgcGFydHMgPSBbXTtcbiAgICBsZXQgaWR4ID0gMDtcbiAgICB3aGlsZSAod29yZC5sZW5ndGggPiB0aGlzLm1heExpbmVMZW5ndGgpIHtcblxuICAgICAgY29uc3QgZmlyc3RMaW5lID0gd29yZC5zdWJzdHJpbmcoMCwgdGhpcy5tYXhMaW5lTGVuZ3RoKTtcbiAgICAgIGNvbnN0IHJlbWFpbmluZ0NoYXJzID0gd29yZC5zdWJzdHJpbmcodGhpcy5tYXhMaW5lTGVuZ3RoKTtcblxuICAgICAgY29uc3Qgc3BsaXRJbmRleCA9IGZpcnN0TGluZS5sYXN0SW5kZXhPZih0aGlzLndyYXBDaGFyYWN0ZXJzW2lkeF0pO1xuXG4gICAgICBpZiAoc3BsaXRJbmRleCA+IC0xKSB7IC8vIEZvdW5kIGEgY2hhcmFjdGVyIHRvIHNwbGl0IG9uXG5cbiAgICAgICAgd29yZCA9IGZpcnN0TGluZS5zdWJzdHJpbmcoc3BsaXRJbmRleCArIDEpICsgcmVtYWluaW5nQ2hhcnM7XG4gICAgICAgIHBhcnRzLnB1c2goZmlyc3RMaW5lLnN1YnN0cmluZygwLCBzcGxpdEluZGV4ICsgMSkpO1xuXG4gICAgICB9IGVsc2UgeyAvLyBOb3QgZm91bmQgYSBjaGFyYWN0ZXIgdG8gc3BsaXQgb25cblxuICAgICAgICBpZHgrKztcbiAgICAgICAgaWYgKGlkeCA8IHRoaXMud3JhcENoYXJhY3RlcnMubGVuZ3RoKSB7IC8vIFRoZXJlIGlzIG5leHQgY2hhcmFjdGVyIHRvIHRyeVxuXG4gICAgICAgICAgd29yZCA9IGZpcnN0TGluZSArIHJlbWFpbmluZ0NoYXJzO1xuXG4gICAgICAgIH0gZWxzZSB7IC8vIE5vIG1vcmUgY2hhcmFjdGVycyB0byB0cnlcblxuICAgICAgICAgIGlmICh0aGlzLmZvcmNlV3JhcE9uTGltaXQpIHtcbiAgICAgICAgICAgIHBhcnRzLnB1c2goZmlyc3RMaW5lKTtcbiAgICAgICAgICAgIHdvcmQgPSByZW1haW5pbmdDaGFycztcbiAgICAgICAgICAgIGlmICh3b3JkLmxlbmd0aCA+IHRoaXMubWF4TGluZUxlbmd0aCkge1xuICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgd29yZCA9IGZpcnN0TGluZSArIHJlbWFpbmluZ0NoYXJzO1xuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcblxuICAgICAgICB9XG5cbiAgICAgIH1cblxuICAgIH1cbiAgICBwYXJ0cy5wdXNoKHdvcmQpOyAvLyBBZGQgcmVtYWluaW5nIHBhcnQgdG8gYXJyYXlcbiAgICByZXR1cm4gcGFydHM7XG4gIH1cbn1cblxuLyogZXNsaW50LWRpc2FibGUgbWF4LWNsYXNzZXMtcGVyLWZpbGUgKi9cblxuXG5jbGFzcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAobmV4dCA9IG51bGwpIHsgdGhpcy5uZXh0ID0gbmV4dDsgfVxuXG4gIGdldFJvb3QgKCkgeyByZXR1cm4gKHRoaXMubmV4dCkgPyB0aGlzLm5leHQgOiB0aGlzOyB9XG59XG5cbmNsYXNzIEJsb2NrU3RhY2tJdGVtIGV4dGVuZHMgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG9wdGlvbnMsIG5leHQgPSBudWxsLCBsZWFkaW5nTGluZUJyZWFrcyA9IDEsIG1heExpbmVMZW5ndGggPSB1bmRlZmluZWQpIHtcbiAgICBzdXBlcihuZXh0KTtcbiAgICB0aGlzLmxlYWRpbmdMaW5lQnJlYWtzID0gbGVhZGluZ0xpbmVCcmVha3M7XG4gICAgdGhpcy5pbmxpbmVUZXh0QnVpbGRlciA9IG5ldyBJbmxpbmVUZXh0QnVpbGRlcihvcHRpb25zLCBtYXhMaW5lTGVuZ3RoKTtcbiAgICB0aGlzLnJhd1RleHQgPSAnJztcbiAgICB0aGlzLnN0YXNoZWRMaW5lQnJlYWtzID0gMDtcbiAgICB0aGlzLmlzUHJlID0gbmV4dCAmJiBuZXh0LmlzUHJlO1xuICAgIHRoaXMuaXNOb1dyYXAgPSBuZXh0ICYmIG5leHQuaXNOb1dyYXA7XG4gIH1cbn1cblxuY2xhc3MgTGlzdFN0YWNrSXRlbSBleHRlbmRzIEJsb2NrU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKFxuICAgIG9wdGlvbnMsXG4gICAgbmV4dCA9IG51bGwsXG4gICAge1xuICAgICAgaW50ZXJSb3dMaW5lQnJlYWtzID0gMSxcbiAgICAgIGxlYWRpbmdMaW5lQnJlYWtzID0gMixcbiAgICAgIG1heExpbmVMZW5ndGggPSB1bmRlZmluZWQsXG4gICAgICBtYXhQcmVmaXhMZW5ndGggPSAwLFxuICAgICAgcHJlZml4QWxpZ24gPSAnbGVmdCcsXG4gICAgfSA9IHt9XG4gICkge1xuICAgIHN1cGVyKG9wdGlvbnMsIG5leHQsIGxlYWRpbmdMaW5lQnJlYWtzLCBtYXhMaW5lTGVuZ3RoKTtcbiAgICB0aGlzLm1heFByZWZpeExlbmd0aCA9IG1heFByZWZpeExlbmd0aDtcbiAgICB0aGlzLnByZWZpeEFsaWduID0gcHJlZml4QWxpZ247XG4gICAgdGhpcy5pbnRlclJvd0xpbmVCcmVha3MgPSBpbnRlclJvd0xpbmVCcmVha3M7XG4gIH1cbn1cblxuY2xhc3MgTGlzdEl0ZW1TdGFja0l0ZW0gZXh0ZW5kcyBCbG9ja1N0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChcbiAgICBvcHRpb25zLFxuICAgIG5leHQgPSBudWxsLFxuICAgIHtcbiAgICAgIGxlYWRpbmdMaW5lQnJlYWtzID0gMSxcbiAgICAgIG1heExpbmVMZW5ndGggPSB1bmRlZmluZWQsXG4gICAgICBwcmVmaXggPSAnJyxcbiAgICB9ID0ge31cbiAgKSB7XG4gICAgc3VwZXIob3B0aW9ucywgbmV4dCwgbGVhZGluZ0xpbmVCcmVha3MsIG1heExpbmVMZW5ndGgpO1xuICAgIHRoaXMucHJlZml4ID0gcHJlZml4O1xuICB9XG59XG5cbmNsYXNzIFRhYmxlU3RhY2tJdGVtIGV4dGVuZHMgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG5leHQgPSBudWxsKSB7XG4gICAgc3VwZXIobmV4dCk7XG4gICAgdGhpcy5yb3dzID0gW107XG4gICAgdGhpcy5pc1ByZSA9IG5leHQgJiYgbmV4dC5pc1ByZTtcbiAgICB0aGlzLmlzTm9XcmFwID0gbmV4dCAmJiBuZXh0LmlzTm9XcmFwO1xuICB9XG59XG5cbmNsYXNzIFRhYmxlUm93U3RhY2tJdGVtIGV4dGVuZHMgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG5leHQgPSBudWxsKSB7XG4gICAgc3VwZXIobmV4dCk7XG4gICAgdGhpcy5jZWxscyA9IFtdO1xuICAgIHRoaXMuaXNQcmUgPSBuZXh0ICYmIG5leHQuaXNQcmU7XG4gICAgdGhpcy5pc05vV3JhcCA9IG5leHQgJiYgbmV4dC5pc05vV3JhcDtcbiAgfVxufVxuXG5jbGFzcyBUYWJsZUNlbGxTdGFja0l0ZW0gZXh0ZW5kcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAob3B0aW9ucywgbmV4dCA9IG51bGwsIG1heENvbHVtbldpZHRoID0gdW5kZWZpbmVkKSB7XG4gICAgc3VwZXIobmV4dCk7XG4gICAgdGhpcy5pbmxpbmVUZXh0QnVpbGRlciA9IG5ldyBJbmxpbmVUZXh0QnVpbGRlcihvcHRpb25zLCBtYXhDb2x1bW5XaWR0aCk7XG4gICAgdGhpcy5yYXdUZXh0ID0gJyc7XG4gICAgdGhpcy5zdGFzaGVkTGluZUJyZWFrcyA9IDA7XG4gICAgdGhpcy5pc1ByZSA9IG5leHQgJiYgbmV4dC5pc1ByZTtcbiAgICB0aGlzLmlzTm9XcmFwID0gbmV4dCAmJiBuZXh0LmlzTm9XcmFwO1xuICB9XG59XG5cbmNsYXNzIFRyYW5zZm9ybWVyU3RhY2tJdGVtIGV4dGVuZHMgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG5leHQgPSBudWxsLCB0cmFuc2Zvcm0pIHtcbiAgICBzdXBlcihuZXh0KTtcbiAgICB0aGlzLnRyYW5zZm9ybSA9IHRyYW5zZm9ybTtcbiAgfVxufVxuXG5mdW5jdGlvbiBjaGFyYWN0ZXJzVG9Db2RlcyAoc3RyKSB7XG4gIHJldHVybiBbLi4uc3RyXVxuICAgIC5tYXAoYyA9PiAnXFxcXHUnICsgYy5jaGFyQ29kZUF0KDApLnRvU3RyaW5nKDE2KS5wYWRTdGFydCg0LCAnMCcpKVxuICAgIC5qb2luKCcnKTtcbn1cblxuLyoqXG4gKiBIZWxwcyB0byBoYW5kbGUgSFRNTCB3aGl0ZXNwYWNlcy5cbiAqXG4gKiBAY2xhc3MgV2hpdGVzcGFjZVByb2Nlc3NvclxuICovXG5jbGFzcyBXaGl0ZXNwYWNlUHJvY2Vzc29yIHtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBXaGl0ZXNwYWNlUHJvY2Vzc29yLlxuICAgKlxuICAgKiBAcGFyYW0geyBPcHRpb25zIH0gb3B0aW9ucyAgICBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gICAqIEBtZW1iZXJvZiBXaGl0ZXNwYWNlUHJvY2Vzc29yXG4gICAqL1xuICBjb25zdHJ1Y3RvciAob3B0aW9ucykge1xuICAgIHRoaXMud2hpdGVzcGFjZUNoYXJzID0gKG9wdGlvbnMucHJlc2VydmVOZXdsaW5lcylcbiAgICAgID8gb3B0aW9ucy53aGl0ZXNwYWNlQ2hhcmFjdGVycy5yZXBsYWNlKC9cXG4vZywgJycpXG4gICAgICA6IG9wdGlvbnMud2hpdGVzcGFjZUNoYXJhY3RlcnM7XG4gICAgY29uc3Qgd2hpdGVzcGFjZUNvZGVzID0gY2hhcmFjdGVyc1RvQ29kZXModGhpcy53aGl0ZXNwYWNlQ2hhcnMpO1xuICAgIHRoaXMubGVhZGluZ1doaXRlc3BhY2VSZSA9IG5ldyBSZWdFeHAoYF5bJHt3aGl0ZXNwYWNlQ29kZXN9XWApO1xuICAgIHRoaXMudHJhaWxpbmdXaGl0ZXNwYWNlUmUgPSBuZXcgUmVnRXhwKGBbJHt3aGl0ZXNwYWNlQ29kZXN9XSRgKTtcbiAgICB0aGlzLmFsbFdoaXRlc3BhY2VPckVtcHR5UmUgPSBuZXcgUmVnRXhwKGBeWyR7d2hpdGVzcGFjZUNvZGVzfV0qJGApO1xuICAgIHRoaXMubmV3bGluZU9yTm9uV2hpdGVzcGFjZVJlID0gbmV3IFJlZ0V4cChgKFxcXFxufFteXFxcXG4ke3doaXRlc3BhY2VDb2Rlc31dKWAsICdnJyk7XG4gICAgdGhpcy5uZXdsaW5lT3JOb25OZXdsaW5lU3RyaW5nUmUgPSBuZXcgUmVnRXhwKGAoXFxcXG58W15cXFxcbl0rKWAsICdnJyk7XG5cbiAgICBpZiAob3B0aW9ucy5wcmVzZXJ2ZU5ld2xpbmVzKSB7XG5cbiAgICAgIGNvbnN0IHdvcmRPck5ld2xpbmVSZSA9IG5ldyBSZWdFeHAoYFxcXFxufFteXFxcXG4ke3doaXRlc3BhY2VDb2Rlc31dK2AsICdnbScpO1xuXG4gICAgICAvKipcbiAgICAgICAqIFNocmluayB3aGl0ZXNwYWNlcyBhbmQgd3JhcCB0ZXh0LCBhZGQgdG8gdGhlIGJ1aWxkZXIuXG4gICAgICAgKlxuICAgICAgICogQHBhcmFtIHsgc3RyaW5nIH0gICAgICAgICAgICAgICAgICB0ZXh0ICAgICAgICAgICAgICBJbnB1dCB0ZXh0LlxuICAgICAgICogQHBhcmFtIHsgSW5saW5lVGV4dEJ1aWxkZXIgfSAgICAgICBpbmxpbmVUZXh0QnVpbGRlciBBIGJ1aWxkZXIgdG8gcmVjZWl2ZSBwcm9jZXNzZWQgdGV4dC5cbiAgICAgICAqIEBwYXJhbSB7IChzdHI6IHN0cmluZykgPT4gc3RyaW5nIH0gWyB0cmFuc2Zvcm0gXSAgICAgQSB0cmFuc2Zvcm0gdG8gYmUgYXBwbGllZCB0byB3b3Jkcy5cbiAgICAgICAqIEBwYXJhbSB7IGJvb2xlYW4gfSAgICAgICAgICAgICAgICAgW25vV3JhcF0gRG9uJ3Qgd3JhcCB0ZXh0IGV2ZW4gaWYgdGhlIGxpbmUgaXMgdG9vIGxvbmcuXG4gICAgICAgKi9cbiAgICAgIHRoaXMuc2hyaW5rV3JhcEFkZCA9IGZ1bmN0aW9uICh0ZXh0LCBpbmxpbmVUZXh0QnVpbGRlciwgdHJhbnNmb3JtID0gKHN0ciA9PiBzdHIpLCBub1dyYXAgPSBmYWxzZSkge1xuICAgICAgICBpZiAoIXRleHQpIHsgcmV0dXJuOyB9XG4gICAgICAgIGNvbnN0IHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgPSBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2U7XG4gICAgICAgIGxldCBhbnlNYXRjaCA9IGZhbHNlO1xuICAgICAgICBsZXQgbSA9IHdvcmRPck5ld2xpbmVSZS5leGVjKHRleHQpO1xuICAgICAgICBpZiAobSkge1xuICAgICAgICAgIGFueU1hdGNoID0gdHJ1ZTtcbiAgICAgICAgICBpZiAobVswXSA9PT0gJ1xcbicpIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSgpO1xuICAgICAgICAgIH0gZWxzZSBpZiAocHJldmlvdXNseVN0YXNoZWRTcGFjZSB8fCB0aGlzLnRlc3RMZWFkaW5nV2hpdGVzcGFjZSh0ZXh0KSkge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5jb25jYXRXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgd2hpbGUgKChtID0gd29yZE9yTmV3bGluZVJlLmV4ZWModGV4dCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICBpZiAobVswXSA9PT0gJ1xcbicpIHtcbiAgICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZSA9IChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlICYmICFhbnlNYXRjaCkgfHwgKHRoaXMudGVzdFRyYWlsaW5nV2hpdGVzcGFjZSh0ZXh0KSk7XG4gICAgICAgIC8vIE5vIG5lZWQgdG8gc3Rhc2ggYSBzcGFjZSBpbiBjYXNlIGxhc3QgYWRkZWQgaXRlbSB3YXMgYSBuZXcgbGluZSxcbiAgICAgICAgLy8gYnV0IHRoYXQgd29uJ3QgYWZmZWN0IGFueXRoaW5nIGxhdGVyIGFueXdheS5cbiAgICAgIH07XG5cbiAgICB9IGVsc2Uge1xuXG4gICAgICBjb25zdCB3b3JkUmUgPSBuZXcgUmVnRXhwKGBbXiR7d2hpdGVzcGFjZUNvZGVzfV0rYCwgJ2cnKTtcblxuICAgICAgdGhpcy5zaHJpbmtXcmFwQWRkID0gZnVuY3Rpb24gKHRleHQsIGlubGluZVRleHRCdWlsZGVyLCB0cmFuc2Zvcm0gPSAoc3RyID0+IHN0ciksIG5vV3JhcCA9IGZhbHNlKSB7XG4gICAgICAgIGlmICghdGV4dCkgeyByZXR1cm47IH1cbiAgICAgICAgY29uc3QgcHJldmlvdXNseVN0YXNoZWRTcGFjZSA9IGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZTtcbiAgICAgICAgbGV0IGFueU1hdGNoID0gZmFsc2U7XG4gICAgICAgIGxldCBtID0gd29yZFJlLmV4ZWModGV4dCk7XG4gICAgICAgIGlmIChtKSB7XG4gICAgICAgICAgYW55TWF0Y2ggPSB0cnVlO1xuICAgICAgICAgIGlmIChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlIHx8IHRoaXMudGVzdExlYWRpbmdXaGl0ZXNwYWNlKHRleHQpKSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLmNvbmNhdFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB3aGlsZSAoKG0gPSB3b3JkUmUuZXhlYyh0ZXh0KSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlID0gKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgJiYgIWFueU1hdGNoKSB8fCB0aGlzLnRlc3RUcmFpbGluZ1doaXRlc3BhY2UodGV4dCk7XG4gICAgICB9O1xuXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCB0ZXh0IHdpdGggb25seSBtaW5pbWFsIHByb2Nlc3NpbmcuXG4gICAqIEV2ZXJ5dGhpbmcgYmV0d2VlbiBuZXdsaW5lcyBjb25zaWRlcmVkIGEgc2luZ2xlIHdvcmQuXG4gICAqIE5vIHdoaXRlc3BhY2UgaXMgdHJpbW1lZC5cbiAgICogTm90IGFmZmVjdGVkIGJ5IHByZXNlcnZlTmV3bGluZXMgb3B0aW9uIC0gYFxcbmAgYWx3YXlzIHN0YXJ0cyBhIG5ldyBsaW5lLlxuICAgKlxuICAgKiBgbm9XcmFwYCBhcmd1bWVudCBpcyBgdHJ1ZWAgYnkgZGVmYXVsdCAtIHRoaXMgd29uJ3Qgc3RhcnQgYSBuZXcgbGluZVxuICAgKiBldmVuIGlmIHRoZXJlIGlzIG5vdCBlbm91Z2ggc3BhY2UgbGVmdCBpbiB0aGUgY3VycmVudCBsaW5lLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSAgICAgICAgICAgIHRleHQgICAgICAgICAgICAgIElucHV0IHRleHQuXG4gICAqIEBwYXJhbSB7IElubGluZVRleHRCdWlsZGVyIH0gaW5saW5lVGV4dEJ1aWxkZXIgQSBidWlsZGVyIHRvIHJlY2VpdmUgcHJvY2Vzc2VkIHRleHQuXG4gICAqIEBwYXJhbSB7IGJvb2xlYW4gfSAgICAgICAgICAgW25vV3JhcF0gRG9uJ3Qgd3JhcCB0ZXh0IGV2ZW4gaWYgdGhlIGxpbmUgaXMgdG9vIGxvbmcuXG4gICAqL1xuICBhZGRMaXRlcmFsICh0ZXh0LCBpbmxpbmVUZXh0QnVpbGRlciwgbm9XcmFwID0gdHJ1ZSkge1xuICAgIGlmICghdGV4dCkgeyByZXR1cm47IH1cbiAgICBjb25zdCBwcmV2aW91c2x5U3Rhc2hlZFNwYWNlID0gaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlO1xuICAgIGxldCBhbnlNYXRjaCA9IGZhbHNlO1xuICAgIGxldCBtID0gdGhpcy5uZXdsaW5lT3JOb25OZXdsaW5lU3RyaW5nUmUuZXhlYyh0ZXh0KTtcbiAgICBpZiAobSkge1xuICAgICAgYW55TWF0Y2ggPSB0cnVlO1xuICAgICAgaWYgKG1bMF0gPT09ICdcXG4nKSB7XG4gICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSgpO1xuICAgICAgfSBlbHNlIGlmIChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlKSB7XG4gICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKG1bMF0sIG5vV3JhcCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5jb25jYXRXb3JkKG1bMF0sIG5vV3JhcCk7XG4gICAgICB9XG4gICAgICB3aGlsZSAoKG0gPSB0aGlzLm5ld2xpbmVPck5vbk5ld2xpbmVTdHJpbmdSZS5leGVjKHRleHQpKSAhPT0gbnVsbCkge1xuICAgICAgICBpZiAobVswXSA9PT0gJ1xcbicpIHtcbiAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUoKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZChtWzBdLCBub1dyYXApO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZSA9IChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlICYmICFhbnlNYXRjaCk7XG4gIH1cblxuICAvKipcbiAgICogVGVzdCB3aGV0aGVyIHRoZSBnaXZlbiB0ZXh0IHN0YXJ0cyB3aXRoIEhUTUwgd2hpdGVzcGFjZSBjaGFyYWN0ZXIuXG4gICAqXG4gICAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gIHRleHQgIFRoZSBzdHJpbmcgdG8gdGVzdC5cbiAgICogQHJldHVybnMgeyBib29sZWFuIH1cbiAgICovXG4gIHRlc3RMZWFkaW5nV2hpdGVzcGFjZSAodGV4dCkge1xuICAgIHJldHVybiB0aGlzLmxlYWRpbmdXaGl0ZXNwYWNlUmUudGVzdCh0ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0IHdoZXRoZXIgdGhlIGdpdmVuIHRleHQgZW5kcyB3aXRoIEhUTUwgd2hpdGVzcGFjZSBjaGFyYWN0ZXIuXG4gICAqXG4gICAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gIHRleHQgIFRoZSBzdHJpbmcgdG8gdGVzdC5cbiAgICogQHJldHVybnMgeyBib29sZWFuIH1cbiAgICovXG4gIHRlc3RUcmFpbGluZ1doaXRlc3BhY2UgKHRleHQpIHtcbiAgICByZXR1cm4gdGhpcy50cmFpbGluZ1doaXRlc3BhY2VSZS50ZXN0KHRleHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRlc3Qgd2hldGhlciB0aGUgZ2l2ZW4gdGV4dCBjb250YWlucyBhbnkgbm9uLXdoaXRlc3BhY2UgY2hhcmFjdGVycy5cbiAgICpcbiAgICogQHBhcmFtICAgeyBzdHJpbmcgfSAgdGV4dCAgVGhlIHN0cmluZyB0byB0ZXN0LlxuICAgKiBAcmV0dXJucyB7IGJvb2xlYW4gfVxuICAgKi9cbiAgdGVzdENvbnRhaW5zV29yZHMgKHRleHQpIHtcbiAgICByZXR1cm4gIXRoaXMuYWxsV2hpdGVzcGFjZU9yRW1wdHlSZS50ZXN0KHRleHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgbnVtYmVyIG9mIG5ld2xpbmVzIGlmIHRoZXJlIGFyZSBubyB3b3Jkcy5cbiAgICpcbiAgICogSWYgYW55IHdvcmQgaXMgZm91bmQgdGhlbiByZXR1cm4gemVybyByZWdhcmRsZXNzIG9mIHRoZSBhY3R1YWwgbnVtYmVyIG9mIG5ld2xpbmVzLlxuICAgKlxuICAgKiBAcGFyYW0gICB7IHN0cmluZyB9ICB0ZXh0ICBJbnB1dCBzdHJpbmcuXG4gICAqIEByZXR1cm5zIHsgbnVtYmVyIH1cbiAgICovXG4gIGNvdW50TmV3bGluZXNOb1dvcmRzICh0ZXh0KSB7XG4gICAgdGhpcy5uZXdsaW5lT3JOb25XaGl0ZXNwYWNlUmUubGFzdEluZGV4ID0gMDtcbiAgICBsZXQgY291bnRlciA9IDA7XG4gICAgbGV0IG1hdGNoO1xuICAgIHdoaWxlICgobWF0Y2ggPSB0aGlzLm5ld2xpbmVPck5vbldoaXRlc3BhY2VSZS5leGVjKHRleHQpKSAhPT0gbnVsbCkge1xuICAgICAgaWYgKG1hdGNoWzBdID09PSAnXFxuJykge1xuICAgICAgICBjb3VudGVyKys7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXR1cm4gMDtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNvdW50ZXI7XG4gIH1cblxufVxuXG4vKipcbiAqIEhlbHBzIHRvIGJ1aWxkIHRleHQgZnJvbSBpbmxpbmUgYW5kIGJsb2NrIGVsZW1lbnRzLlxuICpcbiAqIEBjbGFzcyBCbG9ja1RleHRCdWlsZGVyXG4gKi9cbmNsYXNzIEJsb2NrVGV4dEJ1aWxkZXIge1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIEJsb2NrVGV4dEJ1aWxkZXIuXG4gICAqXG4gICAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAgICogQHBhcmFtIHsgaW1wb3J0KCdzZWxkZXJlZScpLlBpY2tlcjxEb21Ob2RlLCBUYWdEZWZpbml0aW9uPiB9IHBpY2tlciBTZWxlY3RvcnMgZGVjaXNpb24gdHJlZSBwaWNrZXIuXG4gICAqIEBwYXJhbSB7IGFueX0gW21ldGFkYXRhXSBPcHRpb25hbCBtZXRhZGF0YSBmb3IgSFRNTCBkb2N1bWVudCwgZm9yIHVzZSBpbiBmb3JtYXR0ZXJzLlxuICAgKi9cbiAgY29uc3RydWN0b3IgKG9wdGlvbnMsIHBpY2tlciwgbWV0YWRhdGEgPSB1bmRlZmluZWQpIHtcbiAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgIHRoaXMucGlja2VyID0gcGlja2VyO1xuICAgIHRoaXMubWV0YWRhdGEgPSBtZXRhZGF0YTtcbiAgICB0aGlzLndoaXRlc3BhY2VQcm9jZXNzb3IgPSBuZXcgV2hpdGVzcGFjZVByb2Nlc3NvcihvcHRpb25zKTtcbiAgICAvKiogQHR5cGUgeyBTdGFja0l0ZW0gfSAqL1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBCbG9ja1N0YWNrSXRlbShvcHRpb25zKTtcbiAgICAvKiogQHR5cGUgeyBUcmFuc2Zvcm1lclN0YWNrSXRlbSB9ICovXG4gICAgdGhpcy5fd29yZFRyYW5zZm9ybWVyID0gdW5kZWZpbmVkO1xuICB9XG5cbiAgLyoqXG4gICAqIFB1dCBhIHdvcmQtYnktd29yZCB0cmFuc2Zvcm0gZnVuY3Rpb24gb250byB0aGUgdHJhbnNmb3JtYXRpb25zIHN0YWNrLlxuICAgKlxuICAgKiBNYWlubHkgdXNlZCBmb3IgdXBwZXJjYXNpbmcuIENhbiBiZSBieXBhc3NlZCB0byBhZGQgdW5mb3JtYXR0ZWQgdGV4dCBzdWNoIGFzIFVSTHMuXG4gICAqXG4gICAqIFdvcmQgdHJhbnNmb3JtYXRpb25zIGFwcGxpZWQgYmVmb3JlIHdyYXBwaW5nLlxuICAgKlxuICAgKiBAcGFyYW0geyAoc3RyOiBzdHJpbmcpID0+IHN0cmluZyB9IHdvcmRUcmFuc2Zvcm0gV29yZCB0cmFuc2Zvcm1hdGlvbiBmdW5jdGlvbi5cbiAgICovXG4gIHB1c2hXb3JkVHJhbnNmb3JtICh3b3JkVHJhbnNmb3JtKSB7XG4gICAgdGhpcy5fd29yZFRyYW5zZm9ybWVyID0gbmV3IFRyYW5zZm9ybWVyU3RhY2tJdGVtKHRoaXMuX3dvcmRUcmFuc2Zvcm1lciwgd29yZFRyYW5zZm9ybSk7XG4gIH1cblxuICAvKipcbiAgICogUmVtb3ZlIGEgZnVuY3Rpb24gZnJvbSB0aGUgd29yZCB0cmFuc2Zvcm1hdGlvbnMgc3RhY2suXG4gICAqXG4gICAqIEByZXR1cm5zIHsgKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcgfSBBIGZ1bmN0aW9uIHRoYXQgd2FzIHJlbW92ZWQuXG4gICAqL1xuICBwb3BXb3JkVHJhbnNmb3JtICgpIHtcbiAgICBpZiAoIXRoaXMuX3dvcmRUcmFuc2Zvcm1lcikgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgY29uc3QgdHJhbnNmb3JtID0gdGhpcy5fd29yZFRyYW5zZm9ybWVyLnRyYW5zZm9ybTtcbiAgICB0aGlzLl93b3JkVHJhbnNmb3JtZXIgPSB0aGlzLl93b3JkVHJhbnNmb3JtZXIubmV4dDtcbiAgICByZXR1cm4gdHJhbnNmb3JtO1xuICB9XG5cbiAgLyoqXG4gICAqIElnbm9yZSB3b3Jkd3JhcCBvcHRpb24gaW4gZm9sbG93dXAgaW5saW5lIGFkZGl0aW9ucyBhbmQgZGlzYWJsZSBhdXRvbWF0aWMgd3JhcHBpbmcuXG4gICAqL1xuICBzdGFydE5vV3JhcCAoKSB7XG4gICAgdGhpcy5fc3RhY2tJdGVtLmlzTm9XcmFwID0gdHJ1ZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gYXV0b21hdGljIHdyYXBwaW5nIHRvIGJlaGF2aW9yIGRlZmluZWQgYnkgb3B0aW9ucy5cbiAgICovXG4gIHN0b3BOb1dyYXAgKCkge1xuICAgIHRoaXMuX3N0YWNrSXRlbS5pc05vV3JhcCA9IGZhbHNlO1xuICB9XG5cbiAgLyoqIEByZXR1cm5zIHsgKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcgfSAqL1xuICBfZ2V0Q29tYmluZWRXb3JkVHJhbnNmb3JtZXIgKCkge1xuICAgIGNvbnN0IHd0ID0gKHRoaXMuX3dvcmRUcmFuc2Zvcm1lcilcbiAgICAgID8gKChzdHIpID0+IGFwcGx5VHJhbnNmb3JtZXIoc3RyLCB0aGlzLl93b3JkVHJhbnNmb3JtZXIpKVxuICAgICAgOiB1bmRlZmluZWQ7XG4gICAgY29uc3QgY2UgPSB0aGlzLm9wdGlvbnMuZW5jb2RlQ2hhcmFjdGVycztcbiAgICByZXR1cm4gKHd0KVxuICAgICAgPyAoKGNlKSA/IChzdHIpID0+IGNlKHd0KHN0cikpIDogd3QpXG4gICAgICA6IGNlO1xuICB9XG5cbiAgX3BvcFN0YWNrSXRlbSAoKSB7XG4gICAgY29uc3QgaXRlbSA9IHRoaXMuX3N0YWNrSXRlbTtcbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBpdGVtLm5leHQ7XG4gICAgcmV0dXJuIGl0ZW07XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbGluZSBicmVhayBpbnRvIGN1cnJlbnRseSBidWlsdCBibG9jay5cbiAgICovXG4gIGFkZExpbmVCcmVhayAoKSB7XG4gICAgaWYgKCEoXG4gICAgICB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICAgICkpIHsgcmV0dXJuOyB9XG4gICAgaWYgKHRoaXMuX3N0YWNrSXRlbS5pc1ByZSkge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLnJhd1RleHQgKz0gJ1xcbic7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUoKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWxsb3cgdG8gYnJlYWsgbGluZSBpbiBjYXNlIGRpcmVjdGx5IGZvbGxvd2luZyB0ZXh0IHdpbGwgbm90IGZpdC5cbiAgICovXG4gIGFkZFdvcmRCcmVha09wcG9ydHVuaXR5ICgpIHtcbiAgICBpZiAoXG4gICAgICB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICAgICkge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLndvcmRCcmVha09wcG9ydHVuaXR5ID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgbm9kZSBpbmxpbmUgaW50byB0aGUgY3VycmVudGx5IGJ1aWx0IGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSBzdHJcbiAgICogVGV4dCBjb250ZW50IG9mIGEgbm9kZSB0byBhZGQuXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTFdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBvcGVyYXRpb24uXG4gICAqXG4gICAqIEBwYXJhbSB7IGJvb2xlYW4gfSBbcGFyYW0xLm5vV29yZFRyYW5zZm9ybV1cbiAgICogSWdub3JlIHdvcmQgdHJhbnNmb3JtZXJzIGlmIHRoZXJlIGFyZSBhbnkuXG4gICAqIERvbid0IGVuY29kZSBjaGFyYWN0ZXJzIGFzIHdlbGwuXG4gICAqIChVc2UgdGhpcyBmb3IgdGhpbmdzIGxpa2UgVVJMIGFkZHJlc3NlcykuXG4gICAqL1xuICBhZGRJbmxpbmUgKHN0ciwgeyBub1dvcmRUcmFuc2Zvcm0gPSBmYWxzZSB9ID0ge30pIHtcbiAgICBpZiAoIShcbiAgICAgIHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICAgKSkgeyByZXR1cm47IH1cblxuICAgIGlmICh0aGlzLl9zdGFja0l0ZW0uaXNQcmUpIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5yYXdUZXh0ICs9IHN0cjtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoXG4gICAgICBzdHIubGVuZ3RoID09PSAwIHx8IC8vIGVtcHR5IHN0cmluZ1xuICAgICAgKFxuICAgICAgICB0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MgJiYgLy8gc3Rhc2hlZCBsaW5lYnJlYWtzIG1ha2Ugd2hpdGVzcGFjZSBpcnJlbGV2YW50XG4gICAgICAgICF0aGlzLndoaXRlc3BhY2VQcm9jZXNzb3IudGVzdENvbnRhaW5zV29yZHMoc3RyKSAvLyBubyB3b3JkcyB0byBhZGRcbiAgICAgIClcbiAgICApIHsgcmV0dXJuOyB9XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnByZXNlcnZlTmV3bGluZXMpIHtcbiAgICAgIGNvbnN0IG5ld2xpbmVzTnVtYmVyID0gdGhpcy53aGl0ZXNwYWNlUHJvY2Vzc29yLmNvdW50TmV3bGluZXNOb1dvcmRzKHN0cik7XG4gICAgICBpZiAobmV3bGluZXNOdW1iZXIgPiAwKSB7XG4gICAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUobmV3bGluZXNOdW1iZXIpO1xuICAgICAgICAvLyBrZWVwIHN0YXNoZWRMaW5lQnJlYWtzIHVuY2hhbmdlZFxuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcykge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSh0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MpO1xuICAgIH1cbiAgICB0aGlzLndoaXRlc3BhY2VQcm9jZXNzb3Iuc2hyaW5rV3JhcEFkZChcbiAgICAgIHN0cixcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlcixcbiAgICAgIChub1dvcmRUcmFuc2Zvcm0pID8gdW5kZWZpbmVkIDogdGhpcy5fZ2V0Q29tYmluZWRXb3JkVHJhbnNmb3JtZXIoKSxcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pc05vV3JhcFxuICAgICk7XG4gICAgdGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzID0gMDsgLy8gaW5saW5lIHRleHQgZG9lc24ndCBpbnRyb2R1Y2UgbGluZSBicmVha3NcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBzdHJpbmcgaW5saW5lIGludG8gdGhlIGN1cnJlbnRseSBidWlsdCBibG9jay5cbiAgICpcbiAgICogVXNlIHRoaXMgZm9yIG1hcmt1cCBlbGVtZW50cyB0aGF0IGRvbid0IGhhdmUgdG8gYWRoZXJlXG4gICAqIHRvIHRleHQgbGF5b3V0IHJ1bGVzLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSBzdHIgVGV4dCB0byBhZGQuXG4gICAqL1xuICBhZGRMaXRlcmFsIChzdHIpIHtcbiAgICBpZiAoIShcbiAgICAgIHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICAgKSkgeyByZXR1cm47IH1cblxuICAgIGlmIChzdHIubGVuZ3RoID09PSAwKSB7IHJldHVybjsgfVxuXG4gICAgaWYgKHRoaXMuX3N0YWNrSXRlbS5pc1ByZSkge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLnJhd1RleHQgKz0gc3RyO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmICh0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MpIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUodGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzKTtcbiAgICB9XG4gICAgdGhpcy53aGl0ZXNwYWNlUHJvY2Vzc29yLmFkZExpdGVyYWwoXG4gICAgICBzdHIsXG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIsXG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaXNOb1dyYXBcbiAgICApO1xuICAgIHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyA9IDA7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSBuZXcgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTBdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5sZWFkaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyBibG9jayBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpdCBmcm9tIGFueSBwcmVjZWRpbmcgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9ICBbcGFyYW0wLnJlc2VydmVkTGluZUxlbmd0aF1cbiAgICogUmVzZXJ2ZSB0aGlzIG51bWJlciBvZiBjaGFyYWN0ZXJzIG9uIGVhY2ggbGluZSBmb3IgYmxvY2sgbWFya3VwLlxuICAgKlxuICAgKiBAcGFyYW0geyBib29sZWFuIH0gW3BhcmFtMC5pc1ByZV1cbiAgICogU2hvdWxkIEhUTUwgd2hpdGVzcGFjZSBiZSBwcmVzZXJ2ZWQgaW5zaWRlIHRoaXMgYmxvY2suXG4gICAqL1xuICBvcGVuQmxvY2sgKHsgbGVhZGluZ0xpbmVCcmVha3MgPSAxLCByZXNlcnZlZExpbmVMZW5ndGggPSAwLCBpc1ByZSA9IGZhbHNlIH0gPSB7fSkge1xuICAgIGNvbnN0IG1heExpbmVMZW5ndGggPSBNYXRoLm1heCgyMCwgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLm1heExpbmVMZW5ndGggLSByZXNlcnZlZExpbmVMZW5ndGgpO1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBCbG9ja1N0YWNrSXRlbShcbiAgICAgIHRoaXMub3B0aW9ucyxcbiAgICAgIHRoaXMuX3N0YWNrSXRlbSxcbiAgICAgIGxlYWRpbmdMaW5lQnJlYWtzLFxuICAgICAgbWF4TGluZUxlbmd0aFxuICAgICk7XG4gICAgaWYgKGlzUHJlKSB7IHRoaXMuX3N0YWNrSXRlbS5pc1ByZSA9IHRydWU7IH1cbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgYmxvY2ssIGFkZCBpdCdzIGNvbnRlbnQgdG8gdGhlIHBhcmVudCBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMF1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLnRyYWlsaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyBibG9jayBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpdCBmcm9tIGFueSBmb2xsb3dpbmcgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IChzdHI6IHN0cmluZykgPT4gc3RyaW5nIH0gW3BhcmFtMC5ibG9ja1RyYW5zZm9ybV1cbiAgICogQSBmdW5jdGlvbiB0byB0cmFuc2Zvcm0gdGhlIGJsb2NrIHRleHQgYmVmb3JlIGFkZGluZyB0byB0aGUgcGFyZW50IGJsb2NrLlxuICAgKiBUaGlzIGhhcHBlbnMgYWZ0ZXIgd29yZCB3cmFwIGFuZCBzaG91bGQgYmUgdXNlZCBpbiBjb21iaW5hdGlvbiB3aXRoIHJlc2VydmVkIGxpbmUgbGVuZ3RoXG4gICAqIGluIG9yZGVyIHRvIGtlZXAgbGluZSBsZW5ndGhzIGNvcnJlY3QuXG4gICAqIFVzZWQgZm9yIHdob2xlIGJsb2NrIG1hcmt1cC5cbiAgICovXG4gIGNsb3NlQmxvY2sgKHsgdHJhaWxpbmdMaW5lQnJlYWtzID0gMSwgYmxvY2tUcmFuc2Zvcm0gPSB1bmRlZmluZWQgfSA9IHt9KSB7XG4gICAgY29uc3QgYmxvY2sgPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICBjb25zdCBibG9ja1RleHQgPSAoYmxvY2tUcmFuc2Zvcm0pID8gYmxvY2tUcmFuc2Zvcm0oZ2V0VGV4dChibG9jaykpIDogZ2V0VGV4dChibG9jayk7XG4gICAgYWRkVGV4dCh0aGlzLl9zdGFja0l0ZW0sIGJsb2NrVGV4dCwgYmxvY2subGVhZGluZ0xpbmVCcmVha3MsIE1hdGgubWF4KGJsb2NrLnN0YXNoZWRMaW5lQnJlYWtzLCB0cmFpbGluZ0xpbmVCcmVha3MpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIG5ldyBsaXN0LlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0wXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbGlzdC5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5tYXhQcmVmaXhMZW5ndGhdXG4gICAqIExlbmd0aCBvZiB0aGUgbG9uZ2VzdCBsaXN0IGl0ZW0gcHJlZml4LlxuICAgKiBJZiBub3Qgc3VwcGxpZWQgb3IgdG9vIHNtYWxsIHRoZW4gbGlzdCBpdGVtcyB3b24ndCBiZSBhbGlnbmVkIHByb3Blcmx5LlxuICAgKlxuICAgKiBAcGFyYW0geyAnbGVmdCcgfCAncmlnaHQnIH0gW3BhcmFtMC5wcmVmaXhBbGlnbl1cbiAgICogU3BlY2lmeSBob3cgcHJlZml4ZXMgb2YgZGlmZmVyZW50IGxlbmd0aHMgaGF2ZSB0byBiZSBhbGlnbmVkXG4gICAqIHdpdGhpbiBhIGNvbHVtbi5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5pbnRlclJvd0xpbmVCcmVha3NdXG4gICAqIE1pbmltdW0gbnVtYmVyIG9mIGxpbmUgYnJlYWtzIGJldHdlZW4gbGlzdCBpdGVtcy5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5sZWFkaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyBsaXN0IHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGl0IGZyb20gYW55IHByZWNlZGluZyBibG9jay5cbiAgICovXG4gIG9wZW5MaXN0ICh7IG1heFByZWZpeExlbmd0aCA9IDAsIHByZWZpeEFsaWduID0gJ2xlZnQnLCBpbnRlclJvd0xpbmVCcmVha3MgPSAxLCBsZWFkaW5nTGluZUJyZWFrcyA9IDIgfSA9IHt9KSB7XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IExpc3RTdGFja0l0ZW0odGhpcy5vcHRpb25zLCB0aGlzLl9zdGFja0l0ZW0sIHtcbiAgICAgIGludGVyUm93TGluZUJyZWFrczogaW50ZXJSb3dMaW5lQnJlYWtzLFxuICAgICAgbGVhZGluZ0xpbmVCcmVha3M6IGxlYWRpbmdMaW5lQnJlYWtzLFxuICAgICAgbWF4TGluZUxlbmd0aDogdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLm1heExpbmVMZW5ndGgsXG4gICAgICBtYXhQcmVmaXhMZW5ndGg6IG1heFByZWZpeExlbmd0aCxcbiAgICAgIHByZWZpeEFsaWduOiBwcmVmaXhBbGlnblxuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgbmV3IGxpc3QgaXRlbS5cbiAgICpcbiAgICogQHBhcmFtIHtvYmplY3R9IHBhcmFtMFxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbGlzdCBpdGVtLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSBbcGFyYW0wLnByZWZpeF1cbiAgICogUHJlZml4IGZvciB0aGlzIGxpc3QgaXRlbSAoaXRlbSBudW1iZXIsIGJ1bGxldCBwb2ludCwgZXRjKS5cbiAgICovXG4gIG9wZW5MaXN0SXRlbSAoeyBwcmVmaXggPSAnJyB9ID0ge30pIHtcbiAgICBpZiAoISh0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0U3RhY2tJdGVtKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGFkZCBhIGxpc3QgaXRlbSB0byBzb21ldGhpbmcgdGhhdCBpcyBub3QgYSBsaXN0ISBDaGVjayB0aGUgZm9ybWF0dGVyLicpO1xuICAgIH1cbiAgICBjb25zdCBsaXN0ID0gdGhpcy5fc3RhY2tJdGVtO1xuICAgIGNvbnN0IHByZWZpeExlbmd0aCA9IE1hdGgubWF4KHByZWZpeC5sZW5ndGgsIGxpc3QubWF4UHJlZml4TGVuZ3RoKTtcbiAgICBjb25zdCBtYXhMaW5lTGVuZ3RoID0gTWF0aC5tYXgoMjAsIGxpc3QuaW5saW5lVGV4dEJ1aWxkZXIubWF4TGluZUxlbmd0aCAtIHByZWZpeExlbmd0aCk7XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IExpc3RJdGVtU3RhY2tJdGVtKHRoaXMub3B0aW9ucywgbGlzdCwge1xuICAgICAgcHJlZml4OiBwcmVmaXgsXG4gICAgICBtYXhMaW5lTGVuZ3RoOiBtYXhMaW5lTGVuZ3RoLFxuICAgICAgbGVhZGluZ0xpbmVCcmVha3M6IGxpc3QuaW50ZXJSb3dMaW5lQnJlYWtzXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IGxpc3QgaXRlbSwgYWRkIGl0J3MgY29udGVudCB0byB0aGUgcGFyZW50IGxpc3QuXG4gICAqL1xuICBjbG9zZUxpc3RJdGVtICgpIHtcbiAgICBjb25zdCBsaXN0SXRlbSA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIGNvbnN0IGxpc3QgPSBsaXN0SXRlbS5uZXh0O1xuXG4gICAgY29uc3QgcHJlZml4TGVuZ3RoID0gTWF0aC5tYXgobGlzdEl0ZW0ucHJlZml4Lmxlbmd0aCwgbGlzdC5tYXhQcmVmaXhMZW5ndGgpO1xuICAgIGNvbnN0IHNwYWNpbmcgPSAnXFxuJyArICcgJy5yZXBlYXQocHJlZml4TGVuZ3RoKTtcbiAgICBjb25zdCBwcmVmaXggPSAobGlzdC5wcmVmaXhBbGlnbiA9PT0gJ3JpZ2h0JylcbiAgICAgID8gbGlzdEl0ZW0ucHJlZml4LnBhZFN0YXJ0KHByZWZpeExlbmd0aClcbiAgICAgIDogbGlzdEl0ZW0ucHJlZml4LnBhZEVuZChwcmVmaXhMZW5ndGgpO1xuICAgIGNvbnN0IHRleHQgPSBwcmVmaXggKyBnZXRUZXh0KGxpc3RJdGVtKS5yZXBsYWNlKC9cXG4vZywgc3BhY2luZyk7XG5cbiAgICBhZGRUZXh0KFxuICAgICAgbGlzdCxcbiAgICAgIHRleHQsXG4gICAgICBsaXN0SXRlbS5sZWFkaW5nTGluZUJyZWFrcyxcbiAgICAgIE1hdGgubWF4KGxpc3RJdGVtLnN0YXNoZWRMaW5lQnJlYWtzLCBsaXN0LmludGVyUm93TGluZUJyZWFrcylcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCBsaXN0LCBhZGQgaXQncyBjb250ZW50IHRvIHRoZSBwYXJlbnQgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IHBhcmFtMFxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgbGlzdC5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC50cmFpbGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgbGlzdCBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpdCBmcm9tIGFueSBmb2xsb3dpbmcgYmxvY2suXG4gICAqL1xuICBjbG9zZUxpc3QgKHsgdHJhaWxpbmdMaW5lQnJlYWtzID0gMiB9ID0ge30pIHtcbiAgICBjb25zdCBsaXN0ID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgY29uc3QgdGV4dCA9IGdldFRleHQobGlzdCk7XG4gICAgaWYgKHRleHQpIHtcbiAgICAgIGFkZFRleHQodGhpcy5fc3RhY2tJdGVtLCB0ZXh0LCBsaXN0LmxlYWRpbmdMaW5lQnJlYWtzLCB0cmFpbGluZ0xpbmVCcmVha3MpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIHRhYmxlLlxuICAgKi9cbiAgb3BlblRhYmxlICgpIHtcbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgVGFibGVTdGFja0l0ZW0odGhpcy5fc3RhY2tJdGVtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIHRhYmxlIHJvdy5cbiAgICovXG4gIG9wZW5UYWJsZVJvdyAoKSB7XG4gICAgaWYgKCEodGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVTdGFja0l0ZW0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhblxcJ3QgYWRkIGEgdGFibGUgcm93IHRvIHNvbWV0aGluZyB0aGF0IGlzIG5vdCBhIHRhYmxlISBDaGVjayB0aGUgZm9ybWF0dGVyLicpO1xuICAgIH1cbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgVGFibGVSb3dTdGFja0l0ZW0odGhpcy5fc3RhY2tJdGVtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIHRhYmxlIGNlbGwuXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTBdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBjZWxsLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLm1heENvbHVtbldpZHRoXVxuICAgKiBXcmFwIGNlbGwgY29udGVudCB0byB0aGlzIHdpZHRoLiBGYWxsIGJhY2sgdG8gZ2xvYmFsIHdvcmR3cmFwIHZhbHVlIGlmIHVuZGVmaW5lZC5cbiAgICovXG4gIG9wZW5UYWJsZUNlbGwgKHsgbWF4Q29sdW1uV2lkdGggPSB1bmRlZmluZWQgfSA9IHt9KSB7XG4gICAgaWYgKCEodGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVSb3dTdGFja0l0ZW0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhblxcJ3QgYWRkIGEgdGFibGUgY2VsbCB0byBzb21ldGhpbmcgdGhhdCBpcyBub3QgYSB0YWJsZSByb3chIENoZWNrIHRoZSBmb3JtYXR0ZXIuJyk7XG4gICAgfVxuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBUYWJsZUNlbGxTdGFja0l0ZW0odGhpcy5vcHRpb25zLCB0aGlzLl9zdGFja0l0ZW0sIG1heENvbHVtbldpZHRoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgdGFibGUgY2VsbCBhbmQgYWRkIGl0IHRvIHBhcmVudCB0YWJsZSByb3cncyBjZWxscy5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMF1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGNlbGwuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAuY29sc3Bhbl0gSG93IG1hbnkgY29sdW1ucyB0aGlzIGNlbGwgc2hvdWxkIG9jY3VweS5cbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5yb3dzcGFuXSBIb3cgbWFueSByb3dzIHRoaXMgY2VsbCBzaG91bGQgb2NjdXB5LlxuICAgKi9cbiAgY2xvc2VUYWJsZUNlbGwgKHsgY29sc3BhbiA9IDEsIHJvd3NwYW4gPSAxIH0gPSB7fSkge1xuICAgIGNvbnN0IGNlbGwgPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICBjb25zdCB0ZXh0ID0gdHJpbUNoYXJhY3RlcihnZXRUZXh0KGNlbGwpLCAnXFxuJyk7XG4gICAgY2VsbC5uZXh0LmNlbGxzLnB1c2goeyBjb2xzcGFuOiBjb2xzcGFuLCByb3dzcGFuOiByb3dzcGFuLCB0ZXh0OiB0ZXh0IH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCB0YWJsZSByb3cgYW5kIGFkZCBpdCB0byBwYXJlbnQgdGFibGUncyByb3dzLlxuICAgKi9cbiAgY2xvc2VUYWJsZVJvdyAoKSB7XG4gICAgY29uc3Qgcm93ID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgcm93Lm5leHQucm93cy5wdXNoKHJvdy5jZWxscyk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IHRhYmxlIGFuZCBhZGQgdGhlIHJlbmRlcmVkIHRleHQgdG8gdGhlIHBhcmVudCBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gcGFyYW0wXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSB0YWJsZS5cbiAgICpcbiAgICogQHBhcmFtIHsgVGFibGVQcmludGVyIH0gcGFyYW0wLnRhYmxlVG9TdHJpbmdcbiAgICogQSBmdW5jdGlvbiB0byBjb252ZXJ0IGEgdGFibGUgb2Ygc3RyaW5naWZpZWQgY2VsbHMgaW50byBhIGNvbXBsZXRlIHRhYmxlLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLmxlYWRpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIHRhYmxlIHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGlmIGZyb20gYW55IHByZWNlZGluZyBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC50cmFpbGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgdGFibGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaXQgZnJvbSBhbnkgZm9sbG93aW5nIGJsb2NrLlxuICAgKi9cbiAgY2xvc2VUYWJsZSAoeyB0YWJsZVRvU3RyaW5nLCBsZWFkaW5nTGluZUJyZWFrcyA9IDIsIHRyYWlsaW5nTGluZUJyZWFrcyA9IDIgfSkge1xuICAgIGNvbnN0IHRhYmxlID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgY29uc3Qgb3V0cHV0ID0gdGFibGVUb1N0cmluZyh0YWJsZS5yb3dzKTtcbiAgICBpZiAob3V0cHV0KSB7XG4gICAgICBhZGRUZXh0KHRoaXMuX3N0YWNrSXRlbSwgb3V0cHV0LCBsZWFkaW5nTGluZUJyZWFrcywgdHJhaWxpbmdMaW5lQnJlYWtzKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSByZW5kZXJlZCB0ZXh0IGNvbnRlbnQgb2YgdGhpcyBidWlsZGVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gICAqL1xuICB0b1N0cmluZyAoKSB7XG4gICAgcmV0dXJuIGdldFRleHQodGhpcy5fc3RhY2tJdGVtLmdldFJvb3QoKSk7XG4gICAgLy8gVGhlcmUgc2hvdWxkIG9ubHkgYmUgdGhlIHJvb3QgaXRlbSBpZiBldmVyeXRoaW5nIGlzIGNsb3NlZCBwcm9wZXJseS5cbiAgfVxuXG59XG5cbmZ1bmN0aW9uIGdldFRleHQgKHN0YWNrSXRlbSkge1xuICBpZiAoIShcbiAgICBzdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgIHx8IHN0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgfHwgc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ09ubHkgYmxvY2tzLCBsaXN0IGl0ZW1zIGFuZCB0YWJsZSBjZWxscyBjYW4gYmUgcmVxdWVzdGVkIGZvciB0ZXh0IGNvbnRlbnRzLicpO1xuICB9XG4gIHJldHVybiAoc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLmlzRW1wdHkoKSlcbiAgICA/IHN0YWNrSXRlbS5yYXdUZXh0XG4gICAgOiBzdGFja0l0ZW0ucmF3VGV4dCArIHN0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci50b1N0cmluZygpO1xufVxuXG5mdW5jdGlvbiBhZGRUZXh0IChzdGFja0l0ZW0sIHRleHQsIGxlYWRpbmdMaW5lQnJlYWtzLCB0cmFpbGluZ0xpbmVCcmVha3MpIHtcbiAgaWYgKCEoXG4gICAgc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICB8fCBzdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgIHx8IHN0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICApKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdPbmx5IGJsb2NrcywgbGlzdCBpdGVtcyBhbmQgdGFibGUgY2VsbHMgY2FuIGNvbnRhaW4gdGV4dC4nKTtcbiAgfVxuICBjb25zdCBwYXJlbnRUZXh0ID0gZ2V0VGV4dChzdGFja0l0ZW0pO1xuICBjb25zdCBsaW5lQnJlYWtzID0gTWF0aC5tYXgoc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzLCBsZWFkaW5nTGluZUJyZWFrcyk7XG4gIHN0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5jbGVhcigpO1xuICBpZiAocGFyZW50VGV4dCkge1xuICAgIHN0YWNrSXRlbS5yYXdUZXh0ID0gcGFyZW50VGV4dCArICdcXG4nLnJlcGVhdChsaW5lQnJlYWtzKSArIHRleHQ7XG4gIH0gZWxzZSB7XG4gICAgc3RhY2tJdGVtLnJhd1RleHQgPSB0ZXh0O1xuICAgIHN0YWNrSXRlbS5sZWFkaW5nTGluZUJyZWFrcyA9IGxpbmVCcmVha3M7XG4gIH1cbiAgc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzID0gdHJhaWxpbmdMaW5lQnJlYWtzO1xufVxuXG4vKipcbiAqIEBwYXJhbSB7IHN0cmluZyB9IHN0ciBBIHN0cmluZyB0byB0cmFuc2Zvcm0uXG4gKiBAcGFyYW0geyBUcmFuc2Zvcm1lclN0YWNrSXRlbSB9IHRyYW5zZm9ybWVyIEEgdHJhbnNmb3JtZXIgaXRlbSAod2l0aCBwb3NzaWJsZSBjb250aW51YXRpb24pLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiBhcHBseVRyYW5zZm9ybWVyIChzdHIsIHRyYW5zZm9ybWVyKSB7XG4gIHJldHVybiAoKHRyYW5zZm9ybWVyKSA/IGFwcGx5VHJhbnNmb3JtZXIodHJhbnNmb3JtZXIudHJhbnNmb3JtKHN0ciksIHRyYW5zZm9ybWVyLm5leHQpIDogc3RyKTtcbn1cblxuLyoqXG4gKiBDb21waWxlIHNlbGVjdG9ycyBpbnRvIGEgZGVjaXNpb24gdHJlZSxcbiAqIHJldHVybiBhIGZ1bmN0aW9uIGludGVuZGVkIGZvciBiYXRjaCBwcm9jZXNzaW5nLlxuICpcbiAqIEBwYXJhbSAgIHsgT3B0aW9ucyB9IFtvcHRpb25zID0ge31dICAgSHRtbFRvVGV4dCBvcHRpb25zIChkZWZhdWx0cywgZm9ybWF0dGVycywgdXNlciBvcHRpb25zIG1lcmdlZCwgZGVkdXBsaWNhdGVkKS5cbiAqIEByZXR1cm5zIHsgKGh0bWw6IHN0cmluZywgbWV0YWRhdGE/OiBhbnkpID0+IHN0cmluZyB9IFByZS1jb25maWd1cmVkIGNvbnZlcnRlciBmdW5jdGlvbi5cbiAqIEBzdGF0aWNcbiAqL1xuZnVuY3Rpb24gY29tcGlsZSQxIChvcHRpb25zID0ge30pIHtcbiAgY29uc3Qgc2VsZWN0b3JzV2l0aG91dEZvcm1hdCA9IG9wdGlvbnMuc2VsZWN0b3JzLmZpbHRlcihzID0+ICFzLmZvcm1hdCk7XG4gIGlmIChzZWxlY3RvcnNXaXRob3V0Rm9ybWF0Lmxlbmd0aCkge1xuICAgIHRocm93IG5ldyBFcnJvcihcbiAgICAgICdGb2xsb3dpbmcgc2VsZWN0b3JzIGhhdmUgbm8gc3BlY2lmaWVkIGZvcm1hdDogJyArXG4gICAgICBzZWxlY3RvcnNXaXRob3V0Rm9ybWF0Lm1hcChzID0+IGBcXGAke3Muc2VsZWN0b3J9XFxgYCkuam9pbignLCAnKVxuICAgICk7XG4gIH1cbiAgY29uc3QgcGlja2VyID0gbmV3IHNlbGRlcmVlLkRlY2lzaW9uVHJlZShcbiAgICBvcHRpb25zLnNlbGVjdG9ycy5tYXAocyA9PiBbcy5zZWxlY3Rvciwgc10pXG4gICkuYnVpbGQocGx1Z2luSHRtbHBhcnNlcjIuaHAyQnVpbGRlcik7XG5cbiAgaWYgKHR5cGVvZiBvcHRpb25zLmVuY29kZUNoYXJhY3RlcnMgIT09ICdmdW5jdGlvbicpIHtcbiAgICBvcHRpb25zLmVuY29kZUNoYXJhY3RlcnMgPSBtYWtlUmVwbGFjZXJGcm9tRGljdChvcHRpb25zLmVuY29kZUNoYXJhY3RlcnMpO1xuICB9XG5cbiAgY29uc3QgYmFzZVNlbGVjdG9yc1BpY2tlciA9IG5ldyBzZWxkZXJlZS5EZWNpc2lvblRyZWUoXG4gICAgb3B0aW9ucy5iYXNlRWxlbWVudHMuc2VsZWN0b3JzLm1hcCgocywgaSkgPT4gW3MsIGkgKyAxXSlcbiAgKS5idWlsZChwbHVnaW5IdG1scGFyc2VyMi5ocDJCdWlsZGVyKTtcbiAgZnVuY3Rpb24gZmluZEJhc2VFbGVtZW50cyAoZG9tKSB7XG4gICAgcmV0dXJuIGZpbmRCYXNlcyhkb20sIG9wdGlvbnMsIGJhc2VTZWxlY3RvcnNQaWNrZXIpO1xuICB9XG5cbiAgY29uc3QgbGltaXRlZFdhbGsgPSBsaW1pdGVkRGVwdGhSZWN1cnNpdmUoXG4gICAgb3B0aW9ucy5saW1pdHMubWF4RGVwdGgsXG4gICAgcmVjdXJzaXZlV2FsayxcbiAgICBmdW5jdGlvbiAoZG9tLCBidWlsZGVyKSB7XG4gICAgICBidWlsZGVyLmFkZElubGluZShvcHRpb25zLmxpbWl0cy5lbGxpcHNpcyB8fCAnJyk7XG4gICAgfVxuICApO1xuXG4gIHJldHVybiBmdW5jdGlvbiAoaHRtbCwgbWV0YWRhdGEgPSB1bmRlZmluZWQpIHtcbiAgICByZXR1cm4gcHJvY2VzcyhodG1sLCBtZXRhZGF0YSwgb3B0aW9ucywgcGlja2VyLCBmaW5kQmFzZUVsZW1lbnRzLCBsaW1pdGVkV2Fsayk7XG4gIH07XG59XG5cblxuLyoqXG4gKiBDb252ZXJ0IGdpdmVuIEhUTUwgYWNjb3JkaW5nIHRvIHByZXByb2Nlc3NlZCBvcHRpb25zLlxuICpcbiAqIEBwYXJhbSB7IHN0cmluZyB9IGh0bWwgSFRNTCBjb250ZW50IHRvIGNvbnZlcnQuXG4gKiBAcGFyYW0geyBhbnkgfSBtZXRhZGF0YSBPcHRpb25hbCBtZXRhZGF0YSBmb3IgSFRNTCBkb2N1bWVudCwgZm9yIHVzZSBpbiBmb3JtYXR0ZXJzLlxuICogQHBhcmFtIHsgT3B0aW9ucyB9IG9wdGlvbnMgSHRtbFRvVGV4dCBvcHRpb25zIChwcmVwcm9jZXNzZWQpLlxuICogQHBhcmFtIHsgaW1wb3J0KCdzZWxkZXJlZScpLlBpY2tlcjxEb21Ob2RlLCBUYWdEZWZpbml0aW9uPiB9IHBpY2tlclxuICogVGFnIGRlZmluaXRpb24gcGlja2VyIGZvciBET00gbm9kZXMgcHJvY2Vzc2luZy5cbiAqIEBwYXJhbSB7IChkb206IERvbU5vZGVbXSkgPT4gRG9tTm9kZVtdIH0gZmluZEJhc2VFbGVtZW50c1xuICogRnVuY3Rpb24gdG8gZXh0cmFjdCBlbGVtZW50cyBmcm9tIEhUTUwgRE9NXG4gKiB0aGF0IHdpbGwgb25seSBiZSBwcmVzZW50IGluIHRoZSBvdXRwdXQgdGV4dC5cbiAqIEBwYXJhbSB7IFJlY3Vyc2l2ZUNhbGxiYWNrIH0gd2FsayBSZWN1cnNpdmUgY2FsbGJhY2suXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3MgKGh0bWwsIG1ldGFkYXRhLCBvcHRpb25zLCBwaWNrZXIsIGZpbmRCYXNlRWxlbWVudHMsIHdhbGspIHtcbiAgY29uc3QgbWF4SW5wdXRMZW5ndGggPSBvcHRpb25zLmxpbWl0cy5tYXhJbnB1dExlbmd0aDtcbiAgaWYgKG1heElucHV0TGVuZ3RoICYmIGh0bWwgJiYgaHRtbC5sZW5ndGggPiBtYXhJbnB1dExlbmd0aCkge1xuICAgIGNvbnNvbGUud2FybihcbiAgICAgIGBJbnB1dCBsZW5ndGggJHtodG1sLmxlbmd0aH0gaXMgYWJvdmUgYWxsb3dlZCBsaW1pdCBvZiAke21heElucHV0TGVuZ3RofS4gVHJ1bmNhdGluZyB3aXRob3V0IGVsbGlwc2lzLmBcbiAgICApO1xuICAgIGh0bWwgPSBodG1sLnN1YnN0cmluZygwLCBtYXhJbnB1dExlbmd0aCk7XG4gIH1cblxuICBjb25zdCBkb2N1bWVudCA9IGh0bWxwYXJzZXIyLnBhcnNlRG9jdW1lbnQoaHRtbCwgeyBkZWNvZGVFbnRpdGllczogb3B0aW9ucy5kZWNvZGVFbnRpdGllcyB9KTtcbiAgY29uc3QgYmFzZXMgPSBmaW5kQmFzZUVsZW1lbnRzKGRvY3VtZW50LmNoaWxkcmVuKTtcbiAgY29uc3QgYnVpbGRlciA9IG5ldyBCbG9ja1RleHRCdWlsZGVyKG9wdGlvbnMsIHBpY2tlciwgbWV0YWRhdGEpO1xuICB3YWxrKGJhc2VzLCBidWlsZGVyKTtcbiAgcmV0dXJuIGJ1aWxkZXIudG9TdHJpbmcoKTtcbn1cblxuXG5mdW5jdGlvbiBmaW5kQmFzZXMgKGRvbSwgb3B0aW9ucywgYmFzZVNlbGVjdG9yc1BpY2tlcikge1xuICBjb25zdCByZXN1bHRzID0gW107XG5cbiAgZnVuY3Rpb24gcmVjdXJzaXZlV2FsayAod2FsaywgLyoqIEB0eXBlIHsgRG9tTm9kZVtdIH0gKi8gZG9tKSB7XG4gICAgZG9tID0gZG9tLnNsaWNlKDAsIG9wdGlvbnMubGltaXRzLm1heENoaWxkTm9kZXMpO1xuICAgIGZvciAoY29uc3QgZWxlbSBvZiBkb20pIHtcbiAgICAgIGlmIChlbGVtLnR5cGUgIT09ICd0YWcnKSB7XG4gICAgICAgIGNvbnRpbnVlO1xuICAgICAgfVxuICAgICAgY29uc3QgcGlja2VkU2VsZWN0b3JJbmRleCA9IGJhc2VTZWxlY3RvcnNQaWNrZXIucGljazEoZWxlbSk7XG4gICAgICBpZiAocGlja2VkU2VsZWN0b3JJbmRleCA+IDApIHtcbiAgICAgICAgcmVzdWx0cy5wdXNoKHsgc2VsZWN0b3JJbmRleDogcGlja2VkU2VsZWN0b3JJbmRleCwgZWxlbWVudDogZWxlbSB9KTtcbiAgICAgIH0gZWxzZSBpZiAoZWxlbS5jaGlsZHJlbikge1xuICAgICAgICB3YWxrKGVsZW0uY2hpbGRyZW4pO1xuICAgICAgfVxuICAgICAgaWYgKHJlc3VsdHMubGVuZ3RoID49IG9wdGlvbnMubGltaXRzLm1heEJhc2VFbGVtZW50cykge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgY29uc3QgbGltaXRlZFdhbGsgPSBsaW1pdGVkRGVwdGhSZWN1cnNpdmUoXG4gICAgb3B0aW9ucy5saW1pdHMubWF4RGVwdGgsXG4gICAgcmVjdXJzaXZlV2Fsa1xuICApO1xuICBsaW1pdGVkV2Fsayhkb20pO1xuXG4gIGlmIChvcHRpb25zLmJhc2VFbGVtZW50cy5vcmRlckJ5ICE9PSAnb2NjdXJyZW5jZScpIHsgLy8gJ3NlbGVjdG9ycydcbiAgICByZXN1bHRzLnNvcnQoKGEsIGIpID0+IGEuc2VsZWN0b3JJbmRleCAtIGIuc2VsZWN0b3JJbmRleCk7XG4gIH1cbiAgcmV0dXJuIChvcHRpb25zLmJhc2VFbGVtZW50cy5yZXR1cm5Eb21CeURlZmF1bHQgJiYgcmVzdWx0cy5sZW5ndGggPT09IDApXG4gICAgPyBkb21cbiAgICA6IHJlc3VsdHMubWFwKHggPT4geC5lbGVtZW50KTtcbn1cblxuLyoqXG4gKiBGdW5jdGlvbiB0byB3YWxrIHRocm91Z2ggRE9NIG5vZGVzIGFuZCBhY2N1bXVsYXRlIHRoZWlyIHN0cmluZyByZXByZXNlbnRhdGlvbnMuXG4gKlxuICogQHBhcmFtICAgeyBSZWN1cnNpdmVDYWxsYmFjayB9IHdhbGsgICAgUmVjdXJzaXZlIGNhbGxiYWNrLlxuICogQHBhcmFtICAgeyBEb21Ob2RlW10gfSAgICAgICAgIFtkb21dICAgTm9kZXMgYXJyYXkgdG8gcHJvY2Vzcy5cbiAqIEBwYXJhbSAgIHsgQmxvY2tUZXh0QnVpbGRlciB9ICBidWlsZGVyIFBhc3NlZCBhcm91bmQgdG8gYWNjdW11bGF0ZSBvdXRwdXQgdGV4dC5cbiAqIEBwcml2YXRlXG4gKi9cbmZ1bmN0aW9uIHJlY3Vyc2l2ZVdhbGsgKHdhbGssIGRvbSwgYnVpbGRlcikge1xuICBpZiAoIWRvbSkgeyByZXR1cm47IH1cblxuICBjb25zdCBvcHRpb25zID0gYnVpbGRlci5vcHRpb25zO1xuXG4gIGNvbnN0IHRvb01hbnlDaGlsZE5vZGVzID0gZG9tLmxlbmd0aCA+IG9wdGlvbnMubGltaXRzLm1heENoaWxkTm9kZXM7XG4gIGlmICh0b29NYW55Q2hpbGROb2Rlcykge1xuICAgIGRvbSA9IGRvbS5zbGljZSgwLCBvcHRpb25zLmxpbWl0cy5tYXhDaGlsZE5vZGVzKTtcbiAgICBkb20ucHVzaCh7XG4gICAgICBkYXRhOiBvcHRpb25zLmxpbWl0cy5lbGxpcHNpcyxcbiAgICAgIHR5cGU6ICd0ZXh0J1xuICAgIH0pO1xuICB9XG5cbiAgZm9yIChjb25zdCBlbGVtIG9mIGRvbSkge1xuICAgIHN3aXRjaCAoZWxlbS50eXBlKSB7XG4gICAgICBjYXNlICd0ZXh0Jzoge1xuICAgICAgICBidWlsZGVyLmFkZElubGluZShlbGVtLmRhdGEpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGNhc2UgJ3RhZyc6IHtcbiAgICAgICAgY29uc3QgdGFnRGVmaW5pdGlvbiA9IGJ1aWxkZXIucGlja2VyLnBpY2sxKGVsZW0pO1xuICAgICAgICBjb25zdCBmb3JtYXQgPSBvcHRpb25zLmZvcm1hdHRlcnNbdGFnRGVmaW5pdGlvbi5mb3JtYXRdO1xuICAgICAgICBmb3JtYXQoZWxlbSwgd2FsaywgYnVpbGRlciwgdGFnRGVmaW5pdGlvbi5vcHRpb25zIHx8IHt9KTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuO1xufVxuXG4vKipcbiAqIEBwYXJhbSB7IE9iamVjdDxzdHJpbmcsc3RyaW5nIHwgZmFsc2U+IH0gZGljdFxuICogQSBkaWN0aW9uYXJ5IHdoZXJlIGtleXMgYXJlIGNoYXJhY3RlcnMgdG8gcmVwbGFjZVxuICogYW5kIHZhbHVlcyBhcmUgcmVwbGFjZW1lbnQgc3RyaW5ncy5cbiAqXG4gKiBGaXJzdCBjb2RlIHBvaW50IGZyb20gZGljdCBrZXlzIGlzIHVzZWQuXG4gKiBDb21wb3VuZCBlbW9qaXMgd2l0aCBaV0ogYXJlIG5vdCBzdXBwb3J0ZWQgKG5vdCB1bnRpbCBOb2RlIDE2KS5cbiAqXG4gKiBAcmV0dXJucyB7ICgoc3RyOiBzdHJpbmcpID0+IHN0cmluZykgfCB1bmRlZmluZWQgfVxuICovXG5mdW5jdGlvbiBtYWtlUmVwbGFjZXJGcm9tRGljdCAoZGljdCkge1xuICBpZiAoIWRpY3QgfHwgT2JqZWN0LmtleXMoZGljdCkubGVuZ3RoID09PSAwKSB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxuICAvKiogQHR5cGUgeyBbc3RyaW5nLCBzdHJpbmddW10gfSAqL1xuICBjb25zdCBlbnRyaWVzID0gT2JqZWN0LmVudHJpZXMoZGljdCkuZmlsdGVyKChbLCB2XSkgPT4gdiAhPT0gZmFsc2UpO1xuICBjb25zdCByZWdleCA9IG5ldyBSZWdFeHAoXG4gICAgZW50cmllc1xuICAgICAgLm1hcCgoW2NdKSA9PiBgKCR7dW5pY29kZUVzY2FwZShbLi4uY11bMF0pfSlgKVxuICAgICAgLmpvaW4oJ3wnKSxcbiAgICAnZydcbiAgKTtcbiAgY29uc3QgdmFsdWVzID0gZW50cmllcy5tYXAoKFssIHZdKSA9PiB2KTtcbiAgY29uc3QgcmVwbGFjZXIgPSAobSwgLi4uY2dzKSA9PiB2YWx1ZXNbY2dzLmZpbmRJbmRleChjZyA9PiBjZyldO1xuICByZXR1cm4gKHN0cikgPT4gc3RyLnJlcGxhY2UocmVnZXgsIHJlcGxhY2VyKTtcbn1cblxuLyoqXG4gKiBEdW1teSBmb3JtYXR0ZXIgdGhhdCBkaXNjYXJkcyB0aGUgaW5wdXQgYW5kIGRvZXMgbm90aGluZy5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0U2tpcCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICAvKiBkbyBub3RoaW5nICovXG59XG5cbi8qKlxuICogSW5zZXJ0IHRoZSBnaXZlbiBzdHJpbmcgbGl0ZXJhbCBpbmxpbmUgaW5zdGVhZCBvZiBhIHRhZy5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SW5saW5lU3RyaW5nIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChmb3JtYXRPcHRpb25zLnN0cmluZyB8fCAnJyk7XG59XG5cbi8qKlxuICogSW5zZXJ0IGEgYmxvY2sgd2l0aCB0aGUgZ2l2ZW4gc3RyaW5nIGxpdGVyYWwgaW5zdGVhZCBvZiBhIHRhZy5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QmxvY2tTdHJpbmcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5zdHJpbmcgfHwgJycpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiBpbmxpbmUtbGV2ZWwgZWxlbWVudC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SW5saW5lIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGJsb2NrLWxldmVsIGNvbnRhaW5lci5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QmxvY2skMSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuZnVuY3Rpb24gcmVuZGVyT3BlblRhZyAoZWxlbSkge1xuICBjb25zdCBhdHRycyA9IChlbGVtLmF0dHJpYnMgJiYgZWxlbS5hdHRyaWJzLmxlbmd0aClcbiAgICA/ICcgJyArIE9iamVjdC5lbnRyaWVzKGVsZW0uYXR0cmlicylcbiAgICAgIC5tYXAoKFtrLCB2XSkgPT4gKCh2ID09PSAnJykgPyBrIDogYCR7a309JHt2LnJlcGxhY2UoL1wiL2csICcmcXVvdDsnKX1gKSlcbiAgICAgIC5qb2luKCcgJylcbiAgICA6ICcnO1xuICByZXR1cm4gYDwke2VsZW0ubmFtZX0ke2F0dHJzfT5gO1xufVxuXG5mdW5jdGlvbiByZW5kZXJDbG9zZVRhZyAoZWxlbSkge1xuICByZXR1cm4gYDwvJHtlbGVtLm5hbWV9PmA7XG59XG5cbi8qKlxuICogUmVuZGVyIGFuIGVsZW1lbnQgYXMgaW5saW5lIEhUTUwgdGFnLCB3YWxrIHRocm91Z2ggaXQncyBjaGlsZHJlbi5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SW5saW5lVGFnIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuc3RhcnROb1dyYXAoKTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKHJlbmRlck9wZW5UYWcoZWxlbSkpO1xuICBidWlsZGVyLnN0b3BOb1dyYXAoKTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwocmVuZGVyQ2xvc2VUYWcoZWxlbSkpO1xuICBidWlsZGVyLnN0b3BOb1dyYXAoKTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYW4gZWxlbWVudCBhcyBIVE1MIGJsb2NrIGJhZywgd2FsayB0aHJvdWdoIGl0J3MgY2hpbGRyZW4uXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEJsb2NrVGFnIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwocmVuZGVyT3BlblRhZyhlbGVtKSk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChyZW5kZXJDbG9zZVRhZyhlbGVtKSk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUmVuZGVyIGFuIGVsZW1lbnQgd2l0aCBhbGwgaXQncyBjaGlsZHJlbiBhcyBpbmxpbmUgSFRNTC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SW5saW5lSHRtbCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChcbiAgICBkb21TZXJpYWxpemVyLnJlbmRlcihlbGVtLCB7IGRlY29kZUVudGl0aWVzOiBidWlsZGVyLm9wdGlvbnMuZGVjb2RlRW50aXRpZXMgfSlcbiAgKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG59XG5cbi8qKlxuICogUmVuZGVyIGFuIGVsZW1lbnQgd2l0aCBhbGwgaXQncyBjaGlsZHJlbiBhcyBIVE1MIGJsb2NrLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRCbG9ja0h0bWwgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChcbiAgICBkb21TZXJpYWxpemVyLnJlbmRlcihlbGVtLCB7IGRlY29kZUVudGl0aWVzOiBidWlsZGVyLm9wdGlvbnMuZGVjb2RlRW50aXRpZXMgfSlcbiAgKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgaW5saW5lIGVsZW1lbnQgd3JhcHBlZCB3aXRoIGdpdmVuIHN0cmluZ3MuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdElubGluZVN1cnJvdW5kIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChmb3JtYXRPcHRpb25zLnByZWZpeCB8fCAnJyk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChmb3JtYXRPcHRpb25zLnN1ZmZpeCB8fCAnJyk7XG59XG5cbnZhciBnZW5lcmljRm9ybWF0dGVycyA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHtcbiAgX19wcm90b19fOiBudWxsLFxuICBibG9jazogZm9ybWF0QmxvY2skMSxcbiAgYmxvY2tIdG1sOiBmb3JtYXRCbG9ja0h0bWwsXG4gIGJsb2NrU3RyaW5nOiBmb3JtYXRCbG9ja1N0cmluZyxcbiAgYmxvY2tUYWc6IGZvcm1hdEJsb2NrVGFnLFxuICBpbmxpbmU6IGZvcm1hdElubGluZSxcbiAgaW5saW5lSHRtbDogZm9ybWF0SW5saW5lSHRtbCxcbiAgaW5saW5lU3RyaW5nOiBmb3JtYXRJbmxpbmVTdHJpbmcsXG4gIGlubGluZVN1cnJvdW5kOiBmb3JtYXRJbmxpbmVTdXJyb3VuZCxcbiAgaW5saW5lVGFnOiBmb3JtYXRJbmxpbmVUYWcsXG4gIHNraXA6IGZvcm1hdFNraXBcbn0pO1xuXG5mdW5jdGlvbiBnZXRSb3cgKG1hdHJpeCwgaikge1xuICBpZiAoIW1hdHJpeFtqXSkgeyBtYXRyaXhbal0gPSBbXTsgfVxuICByZXR1cm4gbWF0cml4W2pdO1xufVxuXG5mdW5jdGlvbiBmaW5kRmlyc3RWYWNhbnRJbmRleCAocm93LCB4ID0gMCkge1xuICB3aGlsZSAocm93W3hdKSB7IHgrKzsgfVxuICByZXR1cm4geDtcbn1cblxuZnVuY3Rpb24gdHJhbnNwb3NlSW5QbGFjZSAobWF0cml4LCBtYXhTaXplKSB7XG4gIGZvciAobGV0IGkgPSAwOyBpIDwgbWF4U2l6ZTsgaSsrKSB7XG4gICAgY29uc3Qgcm93SSA9IGdldFJvdyhtYXRyaXgsIGkpO1xuICAgIGZvciAobGV0IGogPSAwOyBqIDwgaTsgaisrKSB7XG4gICAgICBjb25zdCByb3dKID0gZ2V0Um93KG1hdHJpeCwgaik7XG4gICAgICBpZiAocm93SVtqXSB8fCByb3dKW2ldKSB7XG4gICAgICAgIGNvbnN0IHRlbXAgPSByb3dJW2pdO1xuICAgICAgICByb3dJW2pdID0gcm93SltpXTtcbiAgICAgICAgcm93SltpXSA9IHRlbXA7XG4gICAgICB9XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIHB1dENlbGxJbnRvTGF5b3V0IChjZWxsLCBsYXlvdXQsIGJhc2VSb3csIGJhc2VDb2wpIHtcbiAgZm9yIChsZXQgciA9IDA7IHIgPCBjZWxsLnJvd3NwYW47IHIrKykge1xuICAgIGNvbnN0IGxheW91dFJvdyA9IGdldFJvdyhsYXlvdXQsIGJhc2VSb3cgKyByKTtcbiAgICBmb3IgKGxldCBjID0gMDsgYyA8IGNlbGwuY29sc3BhbjsgYysrKSB7XG4gICAgICBsYXlvdXRSb3dbYmFzZUNvbCArIGNdID0gY2VsbDtcbiAgICB9XG4gIH1cbn1cblxuZnVuY3Rpb24gZ2V0T3JJbml0T2Zmc2V0IChvZmZzZXRzLCBpbmRleCkge1xuICBpZiAob2Zmc2V0c1tpbmRleF0gPT09IHVuZGVmaW5lZCkge1xuICAgIG9mZnNldHNbaW5kZXhdID0gKGluZGV4ID09PSAwKSA/IDAgOiAxICsgZ2V0T3JJbml0T2Zmc2V0KG9mZnNldHMsIGluZGV4IC0gMSk7XG4gIH1cbiAgcmV0dXJuIG9mZnNldHNbaW5kZXhdO1xufVxuXG5mdW5jdGlvbiB1cGRhdGVPZmZzZXQgKG9mZnNldHMsIGJhc2UsIHNwYW4sIHZhbHVlKSB7XG4gIG9mZnNldHNbYmFzZSArIHNwYW5dID0gTWF0aC5tYXgoXG4gICAgZ2V0T3JJbml0T2Zmc2V0KG9mZnNldHMsIGJhc2UgKyBzcGFuKSxcbiAgICBnZXRPckluaXRPZmZzZXQob2Zmc2V0cywgYmFzZSkgKyB2YWx1ZVxuICApO1xufVxuXG4vKipcbiAqIFJlbmRlciBhIHRhYmxlIGludG8gYSBzdHJpbmcuXG4gKiBDZWxscyBjYW4gY29udGFpbiBtdWx0aWxpbmUgdGV4dCBhbmQgc3BhbiBhY3Jvc3MgbXVsdGlwbGUgcm93cyBhbmQgY29sdW1ucy5cbiAqXG4gKiBNb2RpZmllcyBjZWxscyB0byBhZGQgbGluZXMgYXJyYXkuXG4gKlxuICogQHBhcmFtIHsgVGFibGVQcmludGVyQ2VsbFtdW10gfSB0YWJsZVJvd3MgVGFibGUgdG8gcmVuZGVyLlxuICogQHBhcmFtIHsgbnVtYmVyIH0gcm93U3BhY2luZyBOdW1iZXIgb2Ygc3BhY2VzIGJldHdlZW4gY29sdW1ucy5cbiAqIEBwYXJhbSB7IG51bWJlciB9IGNvbFNwYWNpbmcgTnVtYmVyIG9mIGVtcHR5IGxpbmVzIGJldHdlZW4gcm93cy5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gdGFibGVUb1N0cmluZyAodGFibGVSb3dzLCByb3dTcGFjaW5nLCBjb2xTcGFjaW5nKSB7XG4gIGNvbnN0IGxheW91dCA9IFtdO1xuICBsZXQgY29sTnVtYmVyID0gMDtcbiAgY29uc3Qgcm93TnVtYmVyID0gdGFibGVSb3dzLmxlbmd0aDtcbiAgY29uc3Qgcm93T2Zmc2V0cyA9IFswXTtcbiAgLy8gRmlsbCB0aGUgbGF5b3V0IHRhYmxlIGFuZCByb3cgb2Zmc2V0cyByb3ctYnktcm93LlxuICBmb3IgKGxldCBqID0gMDsgaiA8IHJvd051bWJlcjsgaisrKSB7XG4gICAgY29uc3QgbGF5b3V0Um93ID0gZ2V0Um93KGxheW91dCwgaik7XG4gICAgY29uc3QgY2VsbHMgPSB0YWJsZVJvd3Nbal07XG4gICAgbGV0IHggPSAwO1xuICAgIGZvciAobGV0IGkgPSAwOyBpIDwgY2VsbHMubGVuZ3RoOyBpKyspIHtcbiAgICAgIGNvbnN0IGNlbGwgPSBjZWxsc1tpXTtcbiAgICAgIHggPSBmaW5kRmlyc3RWYWNhbnRJbmRleChsYXlvdXRSb3csIHgpO1xuICAgICAgcHV0Q2VsbEludG9MYXlvdXQoY2VsbCwgbGF5b3V0LCBqLCB4KTtcbiAgICAgIHggKz0gY2VsbC5jb2xzcGFuO1xuICAgICAgY2VsbC5saW5lcyA9IGNlbGwudGV4dC5zcGxpdCgnXFxuJyk7XG4gICAgICBjb25zdCBjZWxsSGVpZ2h0ID0gY2VsbC5saW5lcy5sZW5ndGg7XG4gICAgICB1cGRhdGVPZmZzZXQocm93T2Zmc2V0cywgaiwgY2VsbC5yb3dzcGFuLCBjZWxsSGVpZ2h0ICsgcm93U3BhY2luZyk7XG4gICAgfVxuICAgIGNvbE51bWJlciA9IChsYXlvdXRSb3cubGVuZ3RoID4gY29sTnVtYmVyKSA/IGxheW91dFJvdy5sZW5ndGggOiBjb2xOdW1iZXI7XG4gIH1cblxuICB0cmFuc3Bvc2VJblBsYWNlKGxheW91dCwgKHJvd051bWJlciA+IGNvbE51bWJlcikgPyByb3dOdW1iZXIgOiBjb2xOdW1iZXIpO1xuXG4gIGNvbnN0IG91dHB1dExpbmVzID0gW107XG4gIGNvbnN0IGNvbE9mZnNldHMgPSBbMF07XG4gIC8vIEZpbGwgY29sdW1uIG9mZnNldHMgYW5kIG91dHB1dCBsaW5lcyBjb2x1bW4tYnktY29sdW1uLlxuICBmb3IgKGxldCB4ID0gMDsgeCA8IGNvbE51bWJlcjsgeCsrKSB7XG4gICAgbGV0IHkgPSAwO1xuICAgIGxldCBjZWxsO1xuICAgIGNvbnN0IHJvd3NJblRoaXNDb2x1bW4gPSBNYXRoLm1pbihyb3dOdW1iZXIsIGxheW91dFt4XS5sZW5ndGgpO1xuICAgIHdoaWxlICh5IDwgcm93c0luVGhpc0NvbHVtbikge1xuICAgICAgY2VsbCA9IGxheW91dFt4XVt5XTtcbiAgICAgIGlmIChjZWxsKSB7XG4gICAgICAgIGlmICghY2VsbC5yZW5kZXJlZCkge1xuICAgICAgICAgIGxldCBjZWxsV2lkdGggPSAwO1xuICAgICAgICAgIGZvciAobGV0IGogPSAwOyBqIDwgY2VsbC5saW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgY29uc3QgbGluZSA9IGNlbGwubGluZXNbal07XG4gICAgICAgICAgICBjb25zdCBsaW5lT2Zmc2V0ID0gcm93T2Zmc2V0c1t5XSArIGo7XG4gICAgICAgICAgICBvdXRwdXRMaW5lc1tsaW5lT2Zmc2V0XSA9IChvdXRwdXRMaW5lc1tsaW5lT2Zmc2V0XSB8fCAnJykucGFkRW5kKGNvbE9mZnNldHNbeF0pICsgbGluZTtcbiAgICAgICAgICAgIGNlbGxXaWR0aCA9IChsaW5lLmxlbmd0aCA+IGNlbGxXaWR0aCkgPyBsaW5lLmxlbmd0aCA6IGNlbGxXaWR0aDtcbiAgICAgICAgICB9XG4gICAgICAgICAgdXBkYXRlT2Zmc2V0KGNvbE9mZnNldHMsIHgsIGNlbGwuY29sc3BhbiwgY2VsbFdpZHRoICsgY29sU3BhY2luZyk7XG4gICAgICAgICAgY2VsbC5yZW5kZXJlZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgeSArPSBjZWxsLnJvd3NwYW47XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBjb25zdCBsaW5lT2Zmc2V0ID0gcm93T2Zmc2V0c1t5XTtcbiAgICAgICAgb3V0cHV0TGluZXNbbGluZU9mZnNldF0gPSAob3V0cHV0TGluZXNbbGluZU9mZnNldF0gfHwgJycpO1xuICAgICAgICB5Kys7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIG91dHB1dExpbmVzLmpvaW4oJ1xcbicpO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBsaW5lLWJyZWFrLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRMaW5lQnJlYWsgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5hZGRMaW5lQnJlYWsoKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgYHdicmAgdGFnICh3b3JkIGJyZWFrIG9wcG9ydHVuaXR5KS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0V2JyIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuYWRkV29yZEJyZWFrT3Bwb3J0dW5pdHkoKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgaG9yaXpvbnRhbCBsaW5lLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRIb3Jpem9udGFsTGluZSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG4gIGJ1aWxkZXIuYWRkSW5saW5lKCctJy5yZXBlYXQoZm9ybWF0T3B0aW9ucy5sZW5ndGggfHwgYnVpbGRlci5vcHRpb25zLndvcmR3cmFwIHx8IDQwKSk7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgcGFyYWdyYXBoLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRQYXJhZ3JhcGggKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIHByZWZvcm1hdHRlZCBjb250ZW50LlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRQcmUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soe1xuICAgIGlzUHJlOiB0cnVlLFxuICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDJcbiAgfSk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgaGVhZGluZy5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SGVhZGluZyAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG4gIGlmIChmb3JtYXRPcHRpb25zLnVwcGVyY2FzZSAhPT0gZmFsc2UpIHtcbiAgICBidWlsZGVyLnB1c2hXb3JkVHJhbnNmb3JtKHN0ciA9PiBzdHIudG9VcHBlckNhc2UoKSk7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgICBidWlsZGVyLnBvcFdvcmRUcmFuc2Zvcm0oKTtcbiAgfSBlbHNlIHtcbiAgICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICB9XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgYmxvY2txdW90ZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QmxvY2txdW90ZSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7XG4gICAgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMixcbiAgICByZXNlcnZlZExpbmVMZW5ndGg6IDJcbiAgfSk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7XG4gICAgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyLFxuICAgIGJsb2NrVHJhbnNmb3JtOiBzdHIgPT4gKChmb3JtYXRPcHRpb25zLnRyaW1FbXB0eUxpbmVzICE9PSBmYWxzZSkgPyB0cmltQ2hhcmFjdGVyKHN0ciwgJ1xcbicpIDogc3RyKVxuICAgICAgLnNwbGl0KCdcXG4nKVxuICAgICAgLm1hcChsaW5lID0+ICc+ICcgKyBsaW5lKVxuICAgICAgLmpvaW4oJ1xcbicpXG4gIH0pO1xufVxuXG5mdW5jdGlvbiB3aXRoQnJhY2tldHMgKHN0ciwgYnJhY2tldHMpIHtcbiAgaWYgKCFicmFja2V0cykgeyByZXR1cm4gc3RyOyB9XG5cbiAgY29uc3QgbGJyID0gKHR5cGVvZiBicmFja2V0c1swXSA9PT0gJ3N0cmluZycpXG4gICAgPyBicmFja2V0c1swXVxuICAgIDogJ1snO1xuICBjb25zdCByYnIgPSAodHlwZW9mIGJyYWNrZXRzWzFdID09PSAnc3RyaW5nJylcbiAgICA/IGJyYWNrZXRzWzFdXG4gICAgOiAnXSc7XG4gIHJldHVybiBsYnIgKyBzdHIgKyByYnI7XG59XG5cbmZ1bmN0aW9uIHBhdGhSZXdyaXRlIChwYXRoLCByZXdyaXRlciwgYmFzZVVybCwgbWV0YWRhdGEsIGVsZW0pIHtcbiAgY29uc3QgbW9kaWZpZWRQYXRoID0gKHR5cGVvZiByZXdyaXRlciA9PT0gJ2Z1bmN0aW9uJylcbiAgICA/IHJld3JpdGVyKHBhdGgsIG1ldGFkYXRhLCBlbGVtKVxuICAgIDogcGF0aDtcbiAgcmV0dXJuIChtb2RpZmllZFBhdGhbMF0gPT09ICcvJyAmJiBiYXNlVXJsKVxuICAgID8gdHJpbUNoYXJhY3RlckVuZChiYXNlVXJsLCAnLycpICsgbW9kaWZpZWRQYXRoXG4gICAgOiBtb2RpZmllZFBhdGg7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiBpbWFnZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SW1hZ2UgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgY29uc3QgYXR0cmlicyA9IGVsZW0uYXR0cmlicyB8fCB7fTtcbiAgY29uc3QgYWx0ID0gKGF0dHJpYnMuYWx0KVxuICAgID8gYXR0cmlicy5hbHRcbiAgICA6ICcnO1xuICBjb25zdCBzcmMgPSAoIWF0dHJpYnMuc3JjKVxuICAgID8gJydcbiAgICA6IHBhdGhSZXdyaXRlKGF0dHJpYnMuc3JjLCBmb3JtYXRPcHRpb25zLnBhdGhSZXdyaXRlLCBmb3JtYXRPcHRpb25zLmJhc2VVcmwsIGJ1aWxkZXIubWV0YWRhdGEsIGVsZW0pO1xuICBjb25zdCB0ZXh0ID0gKCFzcmMpXG4gICAgPyBhbHRcbiAgICA6ICghYWx0KVxuICAgICAgPyB3aXRoQnJhY2tldHMoc3JjLCBmb3JtYXRPcHRpb25zLmxpbmtCcmFja2V0cylcbiAgICAgIDogYWx0ICsgJyAnICsgd2l0aEJyYWNrZXRzKHNyYywgZm9ybWF0T3B0aW9ucy5saW5rQnJhY2tldHMpO1xuXG4gIGJ1aWxkZXIuYWRkSW5saW5lKHRleHQsIHsgbm9Xb3JkVHJhbnNmb3JtOiB0cnVlIH0pO1xufVxuXG4vLyBhIGltZyBiYXNlVXJsXG4vLyBhIGltZyBwYXRoUmV3cml0ZVxuLy8gYSBpbWcgbGlua0JyYWNrZXRzXG5cbi8vIGEgICAgIGlnbm9yZUhyZWY6IGZhbHNlXG4vLyAgICAgICAgICAgIGlnbm9yZVRleHQgP1xuLy8gYSAgICAgbm9BbmNob3JVcmw6IHRydWVcbi8vICAgICAgICAgICAgY2FuIGJlIHJlcGxhY2VkIHdpdGggc2VsZWN0b3Jcbi8vIGEgICAgIGhpZGVMaW5rSHJlZklmU2FtZUFzVGV4dDogZmFsc2Vcbi8vICAgICAgICAgICAgaG93IHRvIGNvbXBhcmUsIHdoYXQgdG8gc2hvdyAodGV4dCwgaHJlZiwgbm9ybWFsaXplZCkgP1xuLy8gYSAgICAgbWFpbHRvIHByb3RvY29sIHJlbW92ZWQgd2l0aG91dCBvcHRpb25zXG5cbi8vIGEgICAgIHByb3RvY29sczogbWFpbHRvLCB0ZWwsIC4uLlxuLy8gICAgICAgICAgICBjYW4gYmUgbWF0Y2hlZCB3aXRoIHNlbGVjdG9yP1xuXG4vLyBhbmNob3JzLCBwcm90b2NvbHMgLSBvbmx5IGlmIG5vIHBhdGhSZXdyaXRlIGZuIGlzIHByb3ZpZGVkXG5cbi8vIG5vcm1hbGl6ZS11cmwgP1xuXG4vLyBhXG4vLyBhW2hyZWZePVwiI1wiXSAtIGZvcm1hdDpza2lwIGJ5IGRlZmF1bHRcbi8vIGFbaHJlZl49XCJtYWlsdG86XCJdIC0gP1xuXG4vKipcbiAqIFByb2Nlc3MgYW4gYW5jaG9yLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRBbmNob3IgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgZnVuY3Rpb24gZ2V0SHJlZiAoKSB7XG4gICAgaWYgKGZvcm1hdE9wdGlvbnMuaWdub3JlSHJlZikgeyByZXR1cm4gJyc7IH1cbiAgICBpZiAoIWVsZW0uYXR0cmlicyB8fCAhZWxlbS5hdHRyaWJzLmhyZWYpIHsgcmV0dXJuICcnOyB9XG4gICAgbGV0IGhyZWYgPSBlbGVtLmF0dHJpYnMuaHJlZi5yZXBsYWNlKC9ebWFpbHRvOi8sICcnKTtcbiAgICBpZiAoZm9ybWF0T3B0aW9ucy5ub0FuY2hvclVybCAmJiBocmVmWzBdID09PSAnIycpIHsgcmV0dXJuICcnOyB9XG4gICAgaHJlZiA9IHBhdGhSZXdyaXRlKGhyZWYsIGZvcm1hdE9wdGlvbnMucGF0aFJld3JpdGUsIGZvcm1hdE9wdGlvbnMuYmFzZVVybCwgYnVpbGRlci5tZXRhZGF0YSwgZWxlbSk7XG4gICAgcmV0dXJuIGhyZWY7XG4gIH1cbiAgY29uc3QgaHJlZiA9IGdldEhyZWYoKTtcbiAgaWYgKCFocmVmKSB7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgfSBlbHNlIHtcbiAgICBsZXQgdGV4dCA9ICcnO1xuICAgIGJ1aWxkZXIucHVzaFdvcmRUcmFuc2Zvcm0oXG4gICAgICBzdHIgPT4ge1xuICAgICAgICBpZiAoc3RyKSB7IHRleHQgKz0gc3RyOyB9XG4gICAgICAgIHJldHVybiBzdHI7XG4gICAgICB9XG4gICAgKTtcbiAgICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICAgIGJ1aWxkZXIucG9wV29yZFRyYW5zZm9ybSgpO1xuXG4gICAgY29uc3QgaGlkZVNhbWVMaW5rID0gZm9ybWF0T3B0aW9ucy5oaWRlTGlua0hyZWZJZlNhbWVBc1RleHQgJiYgaHJlZiA9PT0gdGV4dDtcbiAgICBpZiAoIWhpZGVTYW1lTGluaykge1xuICAgICAgYnVpbGRlci5hZGRJbmxpbmUoXG4gICAgICAgICghdGV4dClcbiAgICAgICAgICA/IGhyZWZcbiAgICAgICAgICA6ICcgJyArIHdpdGhCcmFja2V0cyhocmVmLCBmb3JtYXRPcHRpb25zLmxpbmtCcmFja2V0cyksXG4gICAgICAgIHsgbm9Xb3JkVHJhbnNmb3JtOiB0cnVlIH1cbiAgICAgICk7XG4gICAgfVxuICB9XG59XG5cbi8qKlxuICogQHBhcmFtIHsgRG9tTm9kZSB9ICAgICAgICAgICBlbGVtICAgICAgICAgICAgICAgTGlzdCBpdGVtcyB3aXRoIHRoZWlyIHByZWZpeGVzLlxuICogQHBhcmFtIHsgUmVjdXJzaXZlQ2FsbGJhY2sgfSB3YWxrICAgICAgICAgICAgICAgUmVjdXJzaXZlIGNhbGxiYWNrIHRvIHByb2Nlc3MgY2hpbGQgbm9kZXMuXG4gKiBAcGFyYW0geyBCbG9ja1RleHRCdWlsZGVyIH0gIGJ1aWxkZXIgICAgICAgICAgICBQYXNzZWQgYXJvdW5kIHRvIGFjY3VtdWxhdGUgb3V0cHV0IHRleHQuXG4gKiBAcGFyYW0geyBGb3JtYXRPcHRpb25zIH0gICAgIGZvcm1hdE9wdGlvbnMgICAgICBPcHRpb25zIHNwZWNpZmljIHRvIGEgZm9ybWF0dGVyLlxuICogQHBhcmFtIHsgKCkgPT4gc3RyaW5nIH0gICAgICBuZXh0UHJlZml4Q2FsbGJhY2sgRnVuY3Rpb24gdGhhdCByZXR1cm5zIGluY3JlYXNpbmcgaW5kZXggZWFjaCB0aW1lIGl0IGlzIGNhbGxlZC5cbiAqL1xuZnVuY3Rpb24gZm9ybWF0TGlzdCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucywgbmV4dFByZWZpeENhbGxiYWNrKSB7XG4gIGNvbnN0IGlzTmVzdGVkTGlzdCA9IGdldChlbGVtLCBbJ3BhcmVudCcsICduYW1lJ10pID09PSAnbGknO1xuXG4gIC8vIFdpdGggUm9tYW4gbnVtYmVycywgaW5kZXggbGVuZ3RoIGlzIG5vdCBhcyBzdHJhaWdodGZvcndhcmQgYXMgd2l0aCBBcmFiaWMgbnVtYmVycyBvciBsZXR0ZXJzLFxuICAvLyBzbyB0aGUgZHVtYiBsZW5ndGggY29tcGFyaXNvbiBpcyB0aGUgbW9zdCByb2J1c3Qgd2F5IHRvIGdldCB0aGUgY29ycmVjdCB2YWx1ZS5cbiAgbGV0IG1heFByZWZpeExlbmd0aCA9IDA7XG4gIGNvbnN0IGxpc3RJdGVtcyA9IChlbGVtLmNoaWxkcmVuIHx8IFtdKVxuICAgIC8vIGl0IG1pZ2h0IGJlIG1vcmUgYWNjdXJhdGUgdG8gY2hlY2sgb25seSBmb3IgaHRtbCBzcGFjZXMgaGVyZSwgYnV0IG5vIHNpZ25pZmljYW50IGJlbmVmaXRcbiAgICAuZmlsdGVyKGNoaWxkID0+IGNoaWxkLnR5cGUgIT09ICd0ZXh0JyB8fCAhL15cXHMqJC8udGVzdChjaGlsZC5kYXRhKSlcbiAgICAubWFwKGZ1bmN0aW9uIChjaGlsZCkge1xuICAgICAgaWYgKGNoaWxkLm5hbWUgIT09ICdsaScpIHtcbiAgICAgICAgcmV0dXJuIHsgbm9kZTogY2hpbGQsIHByZWZpeDogJycgfTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHByZWZpeCA9IChpc05lc3RlZExpc3QpXG4gICAgICAgID8gbmV4dFByZWZpeENhbGxiYWNrKCkudHJpbVN0YXJ0KClcbiAgICAgICAgOiBuZXh0UHJlZml4Q2FsbGJhY2soKTtcbiAgICAgIGlmIChwcmVmaXgubGVuZ3RoID4gbWF4UHJlZml4TGVuZ3RoKSB7IG1heFByZWZpeExlbmd0aCA9IHByZWZpeC5sZW5ndGg7IH1cbiAgICAgIHJldHVybiB7IG5vZGU6IGNoaWxkLCBwcmVmaXg6IHByZWZpeCB9O1xuICAgIH0pO1xuICBpZiAoIWxpc3RJdGVtcy5sZW5ndGgpIHsgcmV0dXJuOyB9XG5cbiAgYnVpbGRlci5vcGVuTGlzdCh7XG4gICAgaW50ZXJSb3dMaW5lQnJlYWtzOiAxLFxuICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBpc05lc3RlZExpc3QgPyAxIDogKGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiksXG4gICAgbWF4UHJlZml4TGVuZ3RoOiBtYXhQcmVmaXhMZW5ndGgsXG4gICAgcHJlZml4QWxpZ246ICdsZWZ0J1xuICB9KTtcblxuICBmb3IgKGNvbnN0IHsgbm9kZSwgcHJlZml4IH0gb2YgbGlzdEl0ZW1zKSB7XG4gICAgYnVpbGRlci5vcGVuTGlzdEl0ZW0oeyBwcmVmaXg6IHByZWZpeCB9KTtcbiAgICB3YWxrKFtub2RlXSwgYnVpbGRlcik7XG4gICAgYnVpbGRlci5jbG9zZUxpc3RJdGVtKCk7XG4gIH1cblxuICBidWlsZGVyLmNsb3NlTGlzdCh7IHRyYWlsaW5nTGluZUJyZWFrczogaXNOZXN0ZWRMaXN0ID8gMSA6IChmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyKSB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGFuIHVub3JkZXJlZCBsaXN0LlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRVbm9yZGVyZWRMaXN0IChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGNvbnN0IHByZWZpeCA9IGZvcm1hdE9wdGlvbnMuaXRlbVByZWZpeCB8fCAnICogJztcbiAgcmV0dXJuIGZvcm1hdExpc3QoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucywgKCkgPT4gcHJlZml4KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGFuIG9yZGVyZWQgbGlzdC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0T3JkZXJlZExpc3QgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgbGV0IG5leHRJbmRleCA9IE51bWJlcihlbGVtLmF0dHJpYnMuc3RhcnQgfHwgJzEnKTtcbiAgY29uc3QgaW5kZXhGdW5jdGlvbiA9IGdldE9yZGVyZWRMaXN0SW5kZXhGdW5jdGlvbihlbGVtLmF0dHJpYnMudHlwZSk7XG4gIGNvbnN0IG5leHRQcmVmaXhDYWxsYmFjayA9ICgpID0+ICcgJyArIGluZGV4RnVuY3Rpb24obmV4dEluZGV4KyspICsgJy4gJztcbiAgcmV0dXJuIGZvcm1hdExpc3QoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucywgbmV4dFByZWZpeENhbGxiYWNrKTtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBmdW5jdGlvbiB0aGF0IGNhbiBiZSB1c2VkIHRvIGdlbmVyYXRlIGluZGV4IG1hcmtlcnMgb2YgYSBzcGVjaWZpZWQgZm9ybWF0LlxuICpcbiAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gW29sVHlwZT0nMSddIE1hcmtlciB0eXBlLlxuICogQHJldHVybnMgeyAoaTogbnVtYmVyKSA9PiBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiBnZXRPcmRlcmVkTGlzdEluZGV4RnVuY3Rpb24gKG9sVHlwZSA9ICcxJykge1xuICBzd2l0Y2ggKG9sVHlwZSkge1xuICAgIGNhc2UgJ2EnOiByZXR1cm4gKGkpID0+IG51bWJlclRvTGV0dGVyU2VxdWVuY2UoaSwgJ2EnKTtcbiAgICBjYXNlICdBJzogcmV0dXJuIChpKSA9PiBudW1iZXJUb0xldHRlclNlcXVlbmNlKGksICdBJyk7XG4gICAgY2FzZSAnaSc6IHJldHVybiAoaSkgPT4gbnVtYmVyVG9Sb21hbihpKS50b0xvd2VyQ2FzZSgpO1xuICAgIGNhc2UgJ0knOiByZXR1cm4gKGkpID0+IG51bWJlclRvUm9tYW4oaSk7XG4gICAgY2FzZSAnMSc6XG4gICAgZGVmYXVsdDogcmV0dXJuIChpKSA9PiAoaSkudG9TdHJpbmcoKTtcbiAgfVxufVxuXG4vKipcbiAqIEdpdmVuIGEgbGlzdCBvZiBjbGFzcyBhbmQgSUQgc2VsZWN0b3JzIChwcmVmaXhlZCB3aXRoICcuJyBhbmQgJyMnKSxcbiAqIHJldHVybiB0aGVtIGFzIHNlcGFyYXRlIGxpc3RzIG9mIG5hbWVzIHdpdGhvdXQgcHJlZml4ZXMuXG4gKlxuICogQHBhcmFtIHsgc3RyaW5nW10gfSBzZWxlY3RvcnMgQ2xhc3MgYW5kIElEIHNlbGVjdG9ycyAoYFtcIi5jbGFzc1wiLCBcIiNpZFwiXWAgZXRjKS5cbiAqIEByZXR1cm5zIHsgeyBjbGFzc2VzOiBzdHJpbmdbXSwgaWRzOiBzdHJpbmdbXSB9IH1cbiAqL1xuZnVuY3Rpb24gc3BsaXRDbGFzc2VzQW5kSWRzIChzZWxlY3RvcnMpIHtcbiAgY29uc3QgY2xhc3NlcyA9IFtdO1xuICBjb25zdCBpZHMgPSBbXTtcbiAgZm9yIChjb25zdCBzZWxlY3RvciBvZiBzZWxlY3RvcnMpIHtcbiAgICBpZiAoc2VsZWN0b3Iuc3RhcnRzV2l0aCgnLicpKSB7XG4gICAgICBjbGFzc2VzLnB1c2goc2VsZWN0b3Iuc3Vic3RyaW5nKDEpKTtcbiAgICB9IGVsc2UgaWYgKHNlbGVjdG9yLnN0YXJ0c1dpdGgoJyMnKSkge1xuICAgICAgaWRzLnB1c2goc2VsZWN0b3Iuc3Vic3RyaW5nKDEpKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHsgY2xhc3NlczogY2xhc3NlcywgaWRzOiBpZHMgfTtcbn1cblxuZnVuY3Rpb24gaXNEYXRhVGFibGUgKGF0dHIsIHRhYmxlcykge1xuICBpZiAodGFibGVzID09PSB0cnVlKSB7IHJldHVybiB0cnVlOyB9XG4gIGlmICghYXR0cikgeyByZXR1cm4gZmFsc2U7IH1cblxuICBjb25zdCB7IGNsYXNzZXMsIGlkcyB9ID0gc3BsaXRDbGFzc2VzQW5kSWRzKHRhYmxlcyk7XG4gIGNvbnN0IGF0dHJDbGFzc2VzID0gKGF0dHJbJ2NsYXNzJ10gfHwgJycpLnNwbGl0KCcgJyk7XG4gIGNvbnN0IGF0dHJJZHMgPSAoYXR0clsnaWQnXSB8fCAnJykuc3BsaXQoJyAnKTtcblxuICByZXR1cm4gYXR0ckNsYXNzZXMuc29tZSh4ID0+IGNsYXNzZXMuaW5jbHVkZXMoeCkpIHx8IGF0dHJJZHMuc29tZSh4ID0+IGlkcy5pbmNsdWRlcyh4KSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIHRhYmxlIChlaXRoZXIgYXMgYSBjb250YWluZXIgb3IgYXMgYSBkYXRhIHRhYmxlLCBkZXBlbmRpbmcgb24gb3B0aW9ucykuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFRhYmxlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIHJldHVybiBpc0RhdGFUYWJsZShlbGVtLmF0dHJpYnMsIGJ1aWxkZXIub3B0aW9ucy50YWJsZXMpXG4gICAgPyBmb3JtYXREYXRhVGFibGUoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucylcbiAgICA6IGZvcm1hdEJsb2NrKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpO1xufVxuXG5mdW5jdGlvbiBmb3JtYXRCbG9jayAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIH0pO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBkYXRhIHRhYmxlLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXREYXRhVGFibGUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuVGFibGUoKTtcbiAgZWxlbS5jaGlsZHJlbi5mb3JFYWNoKHdhbGtUYWJsZSk7XG4gIGJ1aWxkZXIuY2xvc2VUYWJsZSh7XG4gICAgdGFibGVUb1N0cmluZzogKHJvd3MpID0+IHRhYmxlVG9TdHJpbmcocm93cywgZm9ybWF0T3B0aW9ucy5yb3dTcGFjaW5nID8/IDAsIGZvcm1hdE9wdGlvbnMuY29sU3BhY2luZyA/PyAzKSxcbiAgICBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyxcbiAgICB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzXG4gIH0pO1xuXG4gIGZ1bmN0aW9uIGZvcm1hdENlbGwgKGNlbGxOb2RlKSB7XG4gICAgY29uc3QgY29sc3BhbiA9ICtnZXQoY2VsbE5vZGUsIFsnYXR0cmlicycsICdjb2xzcGFuJ10pIHx8IDE7XG4gICAgY29uc3Qgcm93c3BhbiA9ICtnZXQoY2VsbE5vZGUsIFsnYXR0cmlicycsICdyb3dzcGFuJ10pIHx8IDE7XG4gICAgYnVpbGRlci5vcGVuVGFibGVDZWxsKHsgbWF4Q29sdW1uV2lkdGg6IGZvcm1hdE9wdGlvbnMubWF4Q29sdW1uV2lkdGggfSk7XG4gICAgd2FsayhjZWxsTm9kZS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gICAgYnVpbGRlci5jbG9zZVRhYmxlQ2VsbCh7IGNvbHNwYW46IGNvbHNwYW4sIHJvd3NwYW46IHJvd3NwYW4gfSk7XG4gIH1cblxuICBmdW5jdGlvbiB3YWxrVGFibGUgKGVsZW0pIHtcbiAgICBpZiAoZWxlbS50eXBlICE9PSAndGFnJykgeyByZXR1cm47IH1cblxuICAgIGNvbnN0IGZvcm1hdEhlYWRlckNlbGwgPSAoZm9ybWF0T3B0aW9ucy51cHBlcmNhc2VIZWFkZXJDZWxscyAhPT0gZmFsc2UpXG4gICAgICA/IChjZWxsTm9kZSkgPT4ge1xuICAgICAgICBidWlsZGVyLnB1c2hXb3JkVHJhbnNmb3JtKHN0ciA9PiBzdHIudG9VcHBlckNhc2UoKSk7XG4gICAgICAgIGZvcm1hdENlbGwoY2VsbE5vZGUpO1xuICAgICAgICBidWlsZGVyLnBvcFdvcmRUcmFuc2Zvcm0oKTtcbiAgICAgIH1cbiAgICAgIDogZm9ybWF0Q2VsbDtcblxuICAgIHN3aXRjaCAoZWxlbS5uYW1lKSB7XG4gICAgICBjYXNlICd0aGVhZCc6XG4gICAgICBjYXNlICd0Ym9keSc6XG4gICAgICBjYXNlICd0Zm9vdCc6XG4gICAgICBjYXNlICdjZW50ZXInOlxuICAgICAgICBlbGVtLmNoaWxkcmVuLmZvckVhY2god2Fsa1RhYmxlKTtcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgICBjYXNlICd0cic6IHtcbiAgICAgICAgYnVpbGRlci5vcGVuVGFibGVSb3coKTtcbiAgICAgICAgZm9yIChjb25zdCBjaGlsZE9mVHIgb2YgZWxlbS5jaGlsZHJlbikge1xuICAgICAgICAgIGlmIChjaGlsZE9mVHIudHlwZSAhPT0gJ3RhZycpIHsgY29udGludWU7IH1cbiAgICAgICAgICBzd2l0Y2ggKGNoaWxkT2ZUci5uYW1lKSB7XG4gICAgICAgICAgICBjYXNlICd0aCc6IHtcbiAgICAgICAgICAgICAgZm9ybWF0SGVhZGVyQ2VsbChjaGlsZE9mVHIpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhc2UgJ3RkJzoge1xuICAgICAgICAgICAgICBmb3JtYXRDZWxsKGNoaWxkT2ZUcik7XG4gICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyBkbyBub3RoaW5nXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGJ1aWxkZXIuY2xvc2VUYWJsZVJvdygpO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgICAgLy8gZG8gbm90aGluZ1xuICAgIH1cbiAgfVxufVxuXG52YXIgdGV4dEZvcm1hdHRlcnMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG4gIF9fcHJvdG9fXzogbnVsbCxcbiAgYW5jaG9yOiBmb3JtYXRBbmNob3IsXG4gIGJsb2NrcXVvdGU6IGZvcm1hdEJsb2NrcXVvdGUsXG4gIGRhdGFUYWJsZTogZm9ybWF0RGF0YVRhYmxlLFxuICBoZWFkaW5nOiBmb3JtYXRIZWFkaW5nLFxuICBob3Jpem9udGFsTGluZTogZm9ybWF0SG9yaXpvbnRhbExpbmUsXG4gIGltYWdlOiBmb3JtYXRJbWFnZSxcbiAgbGluZUJyZWFrOiBmb3JtYXRMaW5lQnJlYWssXG4gIG9yZGVyZWRMaXN0OiBmb3JtYXRPcmRlcmVkTGlzdCxcbiAgcGFyYWdyYXBoOiBmb3JtYXRQYXJhZ3JhcGgsXG4gIHByZTogZm9ybWF0UHJlLFxuICB0YWJsZTogZm9ybWF0VGFibGUsXG4gIHVub3JkZXJlZExpc3Q6IGZvcm1hdFVub3JkZXJlZExpc3QsXG4gIHdicjogZm9ybWF0V2JyXG59KTtcblxuLyoqXG4gKiBEZWZhdWx0IG9wdGlvbnMuXG4gKlxuICogQGNvbnN0YW50XG4gKiBAdHlwZSB7IE9wdGlvbnMgfVxuICogQGRlZmF1bHRcbiAqIEBwcml2YXRlXG4gKi9cbmNvbnN0IERFRkFVTFRfT1BUSU9OUyA9IHtcbiAgYmFzZUVsZW1lbnRzOiB7XG4gICAgc2VsZWN0b3JzOiBbICdib2R5JyBdLFxuICAgIG9yZGVyQnk6ICdzZWxlY3RvcnMnLCAvLyAnc2VsZWN0b3JzJyB8ICdvY2N1cnJlbmNlJ1xuICAgIHJldHVybkRvbUJ5RGVmYXVsdDogdHJ1ZVxuICB9LFxuICBkZWNvZGVFbnRpdGllczogdHJ1ZSxcbiAgZW5jb2RlQ2hhcmFjdGVyczoge30sXG4gIGZvcm1hdHRlcnM6IHt9LFxuICBsaW1pdHM6IHtcbiAgICBlbGxpcHNpczogJy4uLicsXG4gICAgbWF4QmFzZUVsZW1lbnRzOiB1bmRlZmluZWQsXG4gICAgbWF4Q2hpbGROb2RlczogdW5kZWZpbmVkLFxuICAgIG1heERlcHRoOiB1bmRlZmluZWQsXG4gICAgbWF4SW5wdXRMZW5ndGg6ICgxIDw8IDI0KSAvLyAxNl83NzdfMjE2XG4gIH0sXG4gIGxvbmdXb3JkU3BsaXQ6IHtcbiAgICBmb3JjZVdyYXBPbkxpbWl0OiBmYWxzZSxcbiAgICB3cmFwQ2hhcmFjdGVyczogW11cbiAgfSxcbiAgcHJlc2VydmVOZXdsaW5lczogZmFsc2UsXG4gIHNlbGVjdG9yczogW1xuICAgIHsgc2VsZWN0b3I6ICcqJywgZm9ybWF0OiAnaW5saW5lJyB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAnYScsXG4gICAgICBmb3JtYXQ6ICdhbmNob3InLFxuICAgICAgb3B0aW9uczoge1xuICAgICAgICBiYXNlVXJsOiBudWxsLFxuICAgICAgICBoaWRlTGlua0hyZWZJZlNhbWVBc1RleHQ6IGZhbHNlLFxuICAgICAgICBpZ25vcmVIcmVmOiBmYWxzZSxcbiAgICAgICAgbGlua0JyYWNrZXRzOiBbJ1snLCAnXSddLFxuICAgICAgICBub0FuY2hvclVybDogdHJ1ZVxuICAgICAgfVxuICAgIH0sXG4gICAgeyBzZWxlY3RvcjogJ2FydGljbGUnLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2FzaWRlJywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAnYmxvY2txdW90ZScsXG4gICAgICBmb3JtYXQ6ICdibG9ja3F1b3RlJyxcbiAgICAgIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdHJpbUVtcHR5TGluZXM6IHRydWUgfVxuICAgIH0sXG4gICAgeyBzZWxlY3RvcjogJ2JyJywgZm9ybWF0OiAnbGluZUJyZWFrJyB9LFxuICAgIHsgc2VsZWN0b3I6ICdkaXYnLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2Zvb3RlcicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnZm9ybScsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDEnLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMywgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoMicsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAzLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2gzJywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDMsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDQnLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoNScsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2g2JywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaGVhZGVyJywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAnaHInLFxuICAgICAgZm9ybWF0OiAnaG9yaXpvbnRhbExpbmUnLFxuICAgICAgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgbGVuZ3RoOiB1bmRlZmluZWQsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9XG4gICAgfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2ltZycsXG4gICAgICBmb3JtYXQ6ICdpbWFnZScsXG4gICAgICBvcHRpb25zOiB7IGJhc2VVcmw6IG51bGwsIGxpbmtCcmFja2V0czogWydbJywgJ10nXSB9XG4gICAgfSxcbiAgICB7IHNlbGVjdG9yOiAnbWFpbicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnbmF2JywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAnb2wnLFxuICAgICAgZm9ybWF0OiAnb3JkZXJlZExpc3QnLFxuICAgICAgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICdwJywgZm9ybWF0OiAncGFyYWdyYXBoJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAncHJlJywgZm9ybWF0OiAncHJlJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnc2VjdGlvbicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ3RhYmxlJyxcbiAgICAgIGZvcm1hdDogJ3RhYmxlJyxcbiAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgY29sU3BhY2luZzogMyxcbiAgICAgICAgbGVhZGluZ0xpbmVCcmVha3M6IDIsXG4gICAgICAgIG1heENvbHVtbldpZHRoOiA2MCxcbiAgICAgICAgcm93U3BhY2luZzogMCxcbiAgICAgICAgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLFxuICAgICAgICB1cHBlcmNhc2VIZWFkZXJDZWxsczogdHJ1ZVxuICAgICAgfVxuICAgIH0sXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICd1bCcsXG4gICAgICBmb3JtYXQ6ICd1bm9yZGVyZWRMaXN0JyxcbiAgICAgIG9wdGlvbnM6IHsgaXRlbVByZWZpeDogJyAqICcsIGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIgfVxuICAgIH0sXG4gICAgeyBzZWxlY3RvcjogJ3dicicsIGZvcm1hdDogJ3dicicgfSxcbiAgXSxcbiAgdGFibGVzOiBbXSwgLy8gZGVwcmVjYXRlZFxuICB3aGl0ZXNwYWNlQ2hhcmFjdGVyczogJyBcXHRcXHJcXG5cXGZcXHUyMDBiJyxcbiAgd29yZHdyYXA6IDgwXG59O1xuXG5jb25zdCBjb25jYXRNZXJnZSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gWy4uLmFjYywgLi4uc3JjXTtcbmNvbnN0IG92ZXJ3cml0ZU1lcmdlID0gKGFjYywgc3JjLCBvcHRpb25zKSA9PiBbLi4uc3JjXTtcbmNvbnN0IHNlbGVjdG9yc01lcmdlID0gKGFjYywgc3JjLCBvcHRpb25zKSA9PiAoXG4gIChhY2Muc29tZShzID0+IHR5cGVvZiBzID09PSAnb2JqZWN0JykpXG4gICAgPyBjb25jYXRNZXJnZShhY2MsIHNyYykgLy8gc2VsZWN0b3JzXG4gICAgOiBvdmVyd3JpdGVNZXJnZShhY2MsIHNyYykgLy8gYmFzZUVsZW1lbnRzLnNlbGVjdG9yc1xuKTtcblxuLyoqXG4gKiBQcmVwcm9jZXNzIG9wdGlvbnMsIGNvbXBpbGUgc2VsZWN0b3JzIGludG8gYSBkZWNpc2lvbiB0cmVlLFxuICogcmV0dXJuIGEgZnVuY3Rpb24gaW50ZW5kZWQgZm9yIGJhdGNoIHByb2Nlc3NpbmcuXG4gKlxuICogQHBhcmFtICAgeyBPcHRpb25zIH0gW29wdGlvbnMgPSB7fV0gICBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gKiBAcmV0dXJucyB7IChodG1sOiBzdHJpbmcsIG1ldGFkYXRhPzogYW55KSA9PiBzdHJpbmcgfSBQcmUtY29uZmlndXJlZCBjb252ZXJ0ZXIgZnVuY3Rpb24uXG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIGNvbXBpbGUgKG9wdGlvbnMgPSB7fSkge1xuICBvcHRpb25zID0gbWVyZ2VfX2RlZmF1bHRbXCJkZWZhdWx0XCJdKFxuICAgIERFRkFVTFRfT1BUSU9OUyxcbiAgICBvcHRpb25zLFxuICAgIHtcbiAgICAgIGFycmF5TWVyZ2U6IG92ZXJ3cml0ZU1lcmdlLFxuICAgICAgY3VzdG9tTWVyZ2U6IChrZXkpID0+ICgoa2V5ID09PSAnc2VsZWN0b3JzJykgPyBzZWxlY3RvcnNNZXJnZSA6IHVuZGVmaW5lZClcbiAgICB9XG4gICk7XG4gIG9wdGlvbnMuZm9ybWF0dGVycyA9IE9iamVjdC5hc3NpZ24oe30sIGdlbmVyaWNGb3JtYXR0ZXJzLCB0ZXh0Rm9ybWF0dGVycywgb3B0aW9ucy5mb3JtYXR0ZXJzKTtcbiAgb3B0aW9ucy5zZWxlY3RvcnMgPSBtZXJnZUR1cGxpY2F0ZXNQcmVmZXJMYXN0KG9wdGlvbnMuc2VsZWN0b3JzLCAocyA9PiBzLnNlbGVjdG9yKSk7XG5cbiAgaGFuZGxlRGVwcmVjYXRlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgcmV0dXJuIGNvbXBpbGUkMShvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGdpdmVuIEhUTUwgY29udGVudCB0byBwbGFpbiB0ZXh0IHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9ICBodG1sICAgICAgICAgICBIVE1MIGNvbnRlbnQgdG8gY29udmVydC5cbiAqIEBwYXJhbSAgIHsgT3B0aW9ucyB9IFtvcHRpb25zID0ge31dIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAqIEBwYXJhbSAgIHsgYW55IH0gICAgIFttZXRhZGF0YV0gICAgIE9wdGlvbmFsIG1ldGFkYXRhIGZvciBIVE1MIGRvY3VtZW50LCBmb3IgdXNlIGluIGZvcm1hdHRlcnMuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9ICAgICAgICAgICAgICAgICBQbGFpbiB0ZXh0IHN0cmluZy5cbiAqIEBzdGF0aWNcbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgeyBjb252ZXJ0IH0gPSByZXF1aXJlKCdodG1sLXRvLXRleHQnKTtcbiAqIGNvbnN0IHRleHQgPSBjb252ZXJ0KCc8aDE+SGVsbG8gV29ybGQ8L2gxPicsIHtcbiAqICAgd29yZHdyYXA6IDEzMFxuICogfSk7XG4gKiBjb25zb2xlLmxvZyh0ZXh0KTsgLy8gSEVMTE8gV09STERcbiAqL1xuZnVuY3Rpb24gY29udmVydCAoaHRtbCwgb3B0aW9ucyA9IHt9LCBtZXRhZGF0YSA9IHVuZGVmaW5lZCkge1xuICByZXR1cm4gY29tcGlsZShvcHRpb25zKShodG1sLCBtZXRhZGF0YSk7XG59XG5cbi8qKlxuICogTWFwIHByZXZpb3VzbHkgZXhpc3RpbmcgYW5kIG5vdyBkZXByZWNhdGVkIG9wdGlvbnMgdG8gdGhlIG5ldyBvcHRpb25zIGxheW91dC5cbiAqIFRoaXMgaXMgYSBzdWJqZWN0IGZvciBjbGVhbnVwIGluIG1ham9yIHJlbGVhc2VzLlxuICpcbiAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAqL1xuZnVuY3Rpb24gaGFuZGxlRGVwcmVjYXRlZE9wdGlvbnMgKG9wdGlvbnMpIHtcbiAgaWYgKG9wdGlvbnMudGFncykge1xuICAgIGNvbnN0IHRhZ0RlZmluaXRpb25zID0gT2JqZWN0LmVudHJpZXMob3B0aW9ucy50YWdzKS5tYXAoXG4gICAgICAoW3NlbGVjdG9yLCBkZWZpbml0aW9uXSkgPT4gKHsgLi4uZGVmaW5pdGlvbiwgc2VsZWN0b3I6IHNlbGVjdG9yIHx8ICcqJyB9KVxuICAgICk7XG4gICAgb3B0aW9ucy5zZWxlY3RvcnMucHVzaCguLi50YWdEZWZpbml0aW9ucyk7XG4gICAgb3B0aW9ucy5zZWxlY3RvcnMgPSBtZXJnZUR1cGxpY2F0ZXNQcmVmZXJMYXN0KG9wdGlvbnMuc2VsZWN0b3JzLCAocyA9PiBzLnNlbGVjdG9yKSk7XG4gIH1cblxuICBmdW5jdGlvbiBzZXQgKG9iaiwgcGF0aCwgdmFsdWUpIHtcbiAgICBjb25zdCB2YWx1ZUtleSA9IHBhdGgucG9wKCk7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgcGF0aCkge1xuICAgICAgbGV0IG5lc3RlZCA9IG9ialtrZXldO1xuICAgICAgaWYgKCFuZXN0ZWQpIHtcbiAgICAgICAgbmVzdGVkID0ge307XG4gICAgICAgIG9ialtrZXldID0gbmVzdGVkO1xuICAgICAgfVxuICAgICAgb2JqID0gbmVzdGVkO1xuICAgIH1cbiAgICBvYmpbdmFsdWVLZXldID0gdmFsdWU7XG4gIH1cblxuICBpZiAob3B0aW9uc1snYmFzZUVsZW1lbnQnXSkge1xuICAgIGNvbnN0IGJhc2VFbGVtZW50ID0gb3B0aW9uc1snYmFzZUVsZW1lbnQnXTtcbiAgICBzZXQoXG4gICAgICBvcHRpb25zLFxuICAgICAgWydiYXNlRWxlbWVudHMnLCAnc2VsZWN0b3JzJ10sXG4gICAgICAoQXJyYXkuaXNBcnJheShiYXNlRWxlbWVudCkgPyBiYXNlRWxlbWVudCA6IFtiYXNlRWxlbWVudF0pXG4gICAgKTtcbiAgfVxuICBpZiAob3B0aW9uc1sncmV0dXJuRG9tQnlEZWZhdWx0J10gIT09IHVuZGVmaW5lZCkge1xuICAgIHNldChvcHRpb25zLCBbJ2Jhc2VFbGVtZW50cycsICdyZXR1cm5Eb21CeURlZmF1bHQnXSwgb3B0aW9uc1sncmV0dXJuRG9tQnlEZWZhdWx0J10pO1xuICB9XG5cbiAgZm9yIChjb25zdCBkZWZpbml0aW9uIG9mIG9wdGlvbnMuc2VsZWN0b3JzKSB7XG4gICAgaWYgKGRlZmluaXRpb24uZm9ybWF0ID09PSAnYW5jaG9yJyAmJiBnZXQoZGVmaW5pdGlvbiwgWydvcHRpb25zJywgJ25vTGlua0JyYWNrZXRzJ10pKSB7XG4gICAgICBzZXQoZGVmaW5pdGlvbiwgWydvcHRpb25zJywgJ2xpbmtCcmFja2V0cyddLCBmYWxzZSk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydHMuY29tcGlsZSA9IGNvbXBpbGU7XG5leHBvcnRzLmNvbnZlcnQgPSBjb252ZXJ0O1xuZXhwb3J0cy5odG1sVG9UZXh0ID0gY29udmVydDtcbiJdLCJuYW1lcyI6W10sImlnbm9yZUxpc3QiOlswXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///(action-browser)/./node_modules/html-to-text/lib/html-to-text.cjs\n");
/***/ }),
/***/ "(rsc)/./node_modules/html-to-text/lib/html-to-text.cjs":
/*!********************************************************!*\
!*** ./node_modules/html-to-text/lib/html-to-text.cjs ***!
\********************************************************/
/***/ ((__unused_webpack_module, exports, __webpack_require__) => {
eval("\n\nObject.defineProperty(exports, \"__esModule\", ({ value: true }));\n\nvar pluginHtmlparser2 = __webpack_require__(/*! @selderee/plugin-htmlparser2 */ \"(rsc)/./node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.cjs\");\nvar htmlparser2 = __webpack_require__(/*! htmlparser2 */ \"(rsc)/./node_modules/htmlparser2/lib/index.js\");\nvar selderee = __webpack_require__(/*! selderee */ \"(rsc)/./node_modules/selderee/lib/selderee.cjs\");\nvar merge = __webpack_require__(/*! deepmerge */ \"(rsc)/./node_modules/deepmerge/dist/cjs.js\");\nvar domSerializer = __webpack_require__(/*! dom-serializer */ \"(rsc)/./node_modules/dom-serializer/lib/index.js\");\n\nfunction _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }\n\nvar merge__default = /*#__PURE__*/_interopDefaultLegacy(merge);\n\n/**\n * Make a recursive function that will only run to a given depth\n * and switches to an alternative function at that depth. \\\n * No limitation if `n` is `undefined` (Just wraps `f` in that case).\n *\n * @param { number | undefined } n Allowed depth of recursion. `undefined` for no limitation.\n * @param { Function } f Function that accepts recursive callback as the first argument.\n * @param { Function } [g] Function to run instead, when maximum depth was reached. Do nothing by default.\n * @returns { Function }\n */\nfunction limitedDepthRecursive (n, f, g = () => undefined) {\n if (n === undefined) {\n const f1 = function (...args) { return f(f1, ...args); };\n return f1;\n }\n if (n >= 0) {\n return function (...args) { return f(limitedDepthRecursive(n - 1, f, g), ...args); };\n }\n return g;\n}\n\n/**\n * Return the same string or a substring with\n * the given character occurrences removed from each side.\n *\n * @param { string } str A string to trim.\n * @param { string } char A character to be trimmed.\n * @returns { string }\n */\nfunction trimCharacter (str, char) {\n let start = 0;\n let end = str.length;\n while (start < end && str[start] === char) { ++start; }\n while (end > start && str[end - 1] === char) { --end; }\n return (start > 0 || end < str.length)\n ? str.substring(start, end)\n : str;\n}\n\n/**\n * Return the same string or a substring with\n * the given character occurrences removed from the end only.\n *\n * @param { string } str A string to trim.\n * @param { string } char A character to be trimmed.\n * @returns { string }\n */\nfunction trimCharacterEnd (str, char) {\n let end = str.length;\n while (end > 0 && str[end - 1] === char) { --end; }\n return (end < str.length)\n ? str.substring(0, end)\n : str;\n}\n\n/**\n * Return a new string will all characters replaced with unicode escape sequences.\n * This extreme kind of escaping can used to be safely compose regular expressions.\n *\n * @param { string } str A string to escape.\n * @returns { string } A string of unicode escape sequences.\n */\nfunction unicodeEscape (str) {\n return str.replace(/[\\s\\S]/g, c => '\\\\u' + c.charCodeAt().toString(16).padStart(4, '0'));\n}\n\n/**\n * Deduplicate an array by a given key callback.\n * Item properties are merged recursively and with the preference for last defined values.\n * Of items with the same key, merged item takes the place of the last item,\n * others are omitted.\n *\n * @param { any[] } items An array to deduplicate.\n * @param { (x: any) => string } getKey Callback to get a value that distinguishes unique items.\n * @returns { any[] }\n */\nfunction mergeDuplicatesPreferLast (items, getKey) {\n const map = new Map();\n for (let i = items.length; i-- > 0;) {\n const item = items[i];\n const key = getKey(item);\n map.set(\n key,\n (map.has(key))\n ? merge__default[\"default\"](item, map.get(key), { arrayMerge: overwriteMerge$1 })\n : item\n );\n }\n return [...map.values()].reverse();\n}\n\nconst overwriteMerge$1 = (acc, src, options) => [...src];\n\n/**\n * Get a nested property from an object.\n *\n * @param { object } obj The object to query for the value.\n * @param { string[] } path The path to the property.\n * @returns { any }\n */\nfunction get (obj, path) {\n for (const key of path) {\n if (!obj) { return undefined; }\n obj = obj[key];\n }\n return obj;\n}\n\n/**\n * Convert a number into alphabetic sequence representation (Sequence without zeroes).\n *\n * For example: `a, ..., z, aa, ..., zz, aaa, ...`.\n *\n * @param { number } num Number to convert. Must be >= 1.\n * @param { string } [baseChar = 'a'] Character for 1 in the sequence.\n * @param { number } [base = 26] Number of characters in the sequence.\n * @returns { string }\n */\nfunction numberToLetterSequence (num, baseChar = 'a', base = 26) {\n const digits = [];\n do {\n num -= 1;\n digits.push(num % base);\n num = (num / base) >> 0; // quick `floor`\n } while (num > 0);\n const baseCode = baseChar.charCodeAt(0);\n return digits\n .reverse()\n .map(n => String.fromCharCode(baseCode + n))\n .join('');\n}\n\nconst I = ['I', 'X', 'C', 'M'];\nconst V = ['V', 'L', 'D'];\n\n/**\n * Convert a number to it's Roman representation. No large numbers extension.\n *\n * @param { number } num Number to convert. `0 < num <= 3999`.\n * @returns { string }\n */\nfunction numberToRoman (num) {\n return [...(num) + '']\n .map(n => +n)\n .reverse()\n .map((v, i) => ((v % 5 < 4)\n ? (v < 5 ? '' : V[i]) + I[i].repeat(v % 5)\n : I[i] + (v < 5 ? V[i] : I[i + 1])))\n .reverse()\n .join('');\n}\n\n/**\n * Helps to build text from words.\n */\nclass InlineTextBuilder {\n /**\n * Creates an instance of InlineTextBuilder.\n *\n * If `maxLineLength` is not provided then it is either `options.wordwrap` or unlimited.\n *\n * @param { Options } options HtmlToText options.\n * @param { number } [ maxLineLength ] This builder will try to wrap text to fit this line length.\n */\n constructor (options, maxLineLength = undefined) {\n /** @type { string[][] } */\n this.lines = [];\n /** @type { string[] } */\n this.nextLineWords = [];\n this.maxLineLength = maxLineLength || options.wordwrap || Number.MAX_VALUE;\n this.nextLineAvailableChars = this.maxLineLength;\n this.wrapCharacters = get(options, ['longWordSplit', 'wrapCharacters']) || [];\n this.forceWrapOnLimit = get(options, ['longWordSplit', 'forceWrapOnLimit']) || false;\n\n this.stashedSpace = false;\n this.wordBreakOpportunity = false;\n }\n\n /**\n * Add a new word.\n *\n * @param { string } word A word to add.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n pushWord (word, noWrap = false) {\n if (this.nextLineAvailableChars <= 0 && !noWrap) {\n this.startNewLine();\n }\n const isLineStart = this.nextLineWords.length === 0;\n const cost = word.length + (isLineStart ? 0 : 1);\n if ((cost <= this.nextLineAvailableChars) || noWrap) { // Fits into available budget\n\n this.nextLineWords.push(word);\n this.nextLineAvailableChars -= cost;\n\n } else { // Does not fit - try to split the word\n\n // The word is moved to a new line - prefer to wrap between words.\n const [first, ...rest] = this.splitLongWord(word);\n if (!isLineStart) { this.startNewLine(); }\n this.nextLineWords.push(first);\n this.nextLineAvailableChars -= first.length;\n for (const part of rest) {\n this.startNewLine();\n this.nextLineWords.push(part);\n this.nextLineAvailableChars -= part.length;\n }\n\n }\n }\n\n /**\n * Pop a word from the currently built line.\n * This doesn't affect completed lines.\n *\n * @returns { string }\n */\n popWord () {\n const lastWord = this.nextLineWords.pop();\n if (lastWord !== undefined) {\n const isLineStart = this.nextLineWords.length === 0;\n const cost = lastWord.length + (isLineStart ? 0 : 1);\n this.nextLineAvailableChars += cost;\n }\n return lastWord;\n }\n\n /**\n * Concat a word to the last word already in the builder.\n * Adds a new word in case there are no words yet in the last line.\n *\n * @param { string } word A word to be concatenated.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n concatWord (word, noWrap = false) {\n if (this.wordBreakOpportunity && word.length > this.nextLineAvailableChars) {\n this.pushWord(word, noWrap);\n this.wordBreakOpportunity = false;\n } else {\n const lastWord = this.popWord();\n this.pushWord((lastWord) ? lastWord.concat(word) : word, noWrap);\n }\n }\n\n /**\n * Add current line (and more empty lines if provided argument > 1) to the list of complete lines and start a new one.\n *\n * @param { number } n Number of line breaks that will be added to the resulting string.\n */\n startNewLine (n = 1) {\n this.lines.push(this.nextLineWords);\n if (n > 1) {\n this.lines.push(...Array.from({ length: n - 1 }, () => []));\n }\n this.nextLineWords = [];\n this.nextLineAvailableChars = this.maxLineLength;\n }\n\n /**\n * No words in this builder.\n *\n * @returns { boolean }\n */\n isEmpty () {\n return this.lines.length === 0\n && this.nextLineWords.length === 0;\n }\n\n clear () {\n this.lines.length = 0;\n this.nextLineWords.length = 0;\n this.nextLineAvailableChars = this.maxLineLength;\n }\n\n /**\n * Join all lines of words inside the InlineTextBuilder into a complete string.\n *\n * @returns { string }\n */\n toString () {\n return [...this.lines, this.nextLineWords]\n .map(words => words.join(' '))\n .join('\\n');\n }\n\n /**\n * Split a long word up to fit within the word wrap limit.\n * Use either a character to split looking back from the word wrap limit,\n * or truncate to the word wrap limit.\n *\n * @param { string } word Input word.\n * @returns { string[] } Parts of the word.\n */\n splitLongWord (word) {\n const parts = [];\n let idx = 0;\n while (word.length > this.maxLineLength) {\n\n const firstLine = word.substring(0, this.maxLineLength);\n const remainingChars = word.substring(this.maxLineLength);\n\n const splitIndex = firstLine.lastIndexOf(this.wrapCharacters[idx]);\n\n if (splitIndex > -1) { // Found a character to split on\n\n word = firstLine.substring(splitIndex + 1) + remainingChars;\n parts.push(firstLine.substring(0, splitIndex + 1));\n\n } else { // Not found a character to split on\n\n idx++;\n if (idx < this.wrapCharacters.length) { // There is next character to try\n\n word = firstLine + remainingChars;\n\n } else { // No more characters to try\n\n if (this.forceWrapOnLimit) {\n parts.push(firstLine);\n word = remainingChars;\n if (word.length > this.maxLineLength) {\n continue;\n }\n } else {\n word = firstLine + remainingChars;\n }\n break;\n\n }\n\n }\n\n }\n parts.push(word); // Add remaining part to array\n return parts;\n }\n}\n\n/* eslint-disable max-classes-per-file */\n\n\nclass StackItem {\n constructor (next = null) { this.next = next; }\n\n getRoot () { return (this.next) ? this.next : this; }\n}\n\nclass BlockStackItem extends StackItem {\n constructor (options, next = null, leadingLineBreaks = 1, maxLineLength = undefined) {\n super(next);\n this.leadingLineBreaks = leadingLineBreaks;\n this.inlineTextBuilder = new InlineTextBuilder(options, maxLineLength);\n this.rawText = '';\n this.stashedLineBreaks = 0;\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass ListStackItem extends BlockStackItem {\n constructor (\n options,\n next = null,\n {\n interRowLineBreaks = 1,\n leadingLineBreaks = 2,\n maxLineLength = undefined,\n maxPrefixLength = 0,\n prefixAlign = 'left',\n } = {}\n ) {\n super(options, next, leadingLineBreaks, maxLineLength);\n this.maxPrefixLength = maxPrefixLength;\n this.prefixAlign = prefixAlign;\n this.interRowLineBreaks = interRowLineBreaks;\n }\n}\n\nclass ListItemStackItem extends BlockStackItem {\n constructor (\n options,\n next = null,\n {\n leadingLineBreaks = 1,\n maxLineLength = undefined,\n prefix = '',\n } = {}\n ) {\n super(options, next, leadingLineBreaks, maxLineLength);\n this.prefix = prefix;\n }\n}\n\nclass TableStackItem extends StackItem {\n constructor (next = null) {\n super(next);\n this.rows = [];\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TableRowStackItem extends StackItem {\n constructor (next = null) {\n super(next);\n this.cells = [];\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TableCellStackItem extends StackItem {\n constructor (options, next = null, maxColumnWidth = undefined) {\n super(next);\n this.inlineTextBuilder = new InlineTextBuilder(options, maxColumnWidth);\n this.rawText = '';\n this.stashedLineBreaks = 0;\n this.isPre = next && next.isPre;\n this.isNoWrap = next && next.isNoWrap;\n }\n}\n\nclass TransformerStackItem extends StackItem {\n constructor (next = null, transform) {\n super(next);\n this.transform = transform;\n }\n}\n\nfunction charactersToCodes (str) {\n return [...str]\n .map(c => '\\\\u' + c.charCodeAt(0).toString(16).padStart(4, '0'))\n .join('');\n}\n\n/**\n * Helps to handle HTML whitespaces.\n *\n * @class WhitespaceProcessor\n */\nclass WhitespaceProcessor {\n\n /**\n * Creates an instance of WhitespaceProcessor.\n *\n * @param { Options } options HtmlToText options.\n * @memberof WhitespaceProcessor\n */\n constructor (options) {\n this.whitespaceChars = (options.preserveNewlines)\n ? options.whitespaceCharacters.replace(/\\n/g, '')\n : options.whitespaceCharacters;\n const whitespaceCodes = charactersToCodes(this.whitespaceChars);\n this.leadingWhitespaceRe = new RegExp(`^[${whitespaceCodes}]`);\n this.trailingWhitespaceRe = new RegExp(`[${whitespaceCodes}]$`);\n this.allWhitespaceOrEmptyRe = new RegExp(`^[${whitespaceCodes}]*$`);\n this.newlineOrNonWhitespaceRe = new RegExp(`(\\\\n|[^\\\\n${whitespaceCodes}])`, 'g');\n this.newlineOrNonNewlineStringRe = new RegExp(`(\\\\n|[^\\\\n]+)`, 'g');\n\n if (options.preserveNewlines) {\n\n const wordOrNewlineRe = new RegExp(`\\\\n|[^\\\\n${whitespaceCodes}]+`, 'gm');\n\n /**\n * Shrink whitespaces and wrap text, add to the builder.\n *\n * @param { string } text Input text.\n * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.\n * @param { (str: string) => string } [ transform ] A transform to be applied to words.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n this.shrinkWrapAdd = function (text, inlineTextBuilder, transform = (str => str), noWrap = false) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = wordOrNewlineRe.exec(text);\n if (m) {\n anyMatch = true;\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else if (previouslyStashedSpace || this.testLeadingWhitespace(text)) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n } else {\n inlineTextBuilder.concatWord(transform(m[0]), noWrap);\n }\n while ((m = wordOrNewlineRe.exec(text)) !== null) {\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n }\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch) || (this.testTrailingWhitespace(text));\n // No need to stash a space in case last added item was a new line,\n // but that won't affect anything later anyway.\n };\n\n } else {\n\n const wordRe = new RegExp(`[^${whitespaceCodes}]+`, 'g');\n\n this.shrinkWrapAdd = function (text, inlineTextBuilder, transform = (str => str), noWrap = false) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = wordRe.exec(text);\n if (m) {\n anyMatch = true;\n if (previouslyStashedSpace || this.testLeadingWhitespace(text)) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n } else {\n inlineTextBuilder.concatWord(transform(m[0]), noWrap);\n }\n while ((m = wordRe.exec(text)) !== null) {\n inlineTextBuilder.pushWord(transform(m[0]), noWrap);\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch) || this.testTrailingWhitespace(text);\n };\n\n }\n }\n\n /**\n * Add text with only minimal processing.\n * Everything between newlines considered a single word.\n * No whitespace is trimmed.\n * Not affected by preserveNewlines option - `\\n` always starts a new line.\n *\n * `noWrap` argument is `true` by default - this won't start a new line\n * even if there is not enough space left in the current line.\n *\n * @param { string } text Input text.\n * @param { InlineTextBuilder } inlineTextBuilder A builder to receive processed text.\n * @param { boolean } [noWrap] Don't wrap text even if the line is too long.\n */\n addLiteral (text, inlineTextBuilder, noWrap = true) {\n if (!text) { return; }\n const previouslyStashedSpace = inlineTextBuilder.stashedSpace;\n let anyMatch = false;\n let m = this.newlineOrNonNewlineStringRe.exec(text);\n if (m) {\n anyMatch = true;\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else if (previouslyStashedSpace) {\n inlineTextBuilder.pushWord(m[0], noWrap);\n } else {\n inlineTextBuilder.concatWord(m[0], noWrap);\n }\n while ((m = this.newlineOrNonNewlineStringRe.exec(text)) !== null) {\n if (m[0] === '\\n') {\n inlineTextBuilder.startNewLine();\n } else {\n inlineTextBuilder.pushWord(m[0], noWrap);\n }\n }\n }\n inlineTextBuilder.stashedSpace = (previouslyStashedSpace && !anyMatch);\n }\n\n /**\n * Test whether the given text starts with HTML whitespace character.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testLeadingWhitespace (text) {\n return this.leadingWhitespaceRe.test(text);\n }\n\n /**\n * Test whether the given text ends with HTML whitespace character.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testTrailingWhitespace (text) {\n return this.trailingWhitespaceRe.test(text);\n }\n\n /**\n * Test whether the given text contains any non-whitespace characters.\n *\n * @param { string } text The string to test.\n * @returns { boolean }\n */\n testContainsWords (text) {\n return !this.allWhitespaceOrEmptyRe.test(text);\n }\n\n /**\n * Return the number of newlines if there are no words.\n *\n * If any word is found then return zero regardless of the actual number of newlines.\n *\n * @param { string } text Input string.\n * @returns { number }\n */\n countNewlinesNoWords (text) {\n this.newlineOrNonWhitespaceRe.lastIndex = 0;\n let counter = 0;\n let match;\n while ((match = this.newlineOrNonWhitespaceRe.exec(text)) !== null) {\n if (match[0] === '\\n') {\n counter++;\n } else {\n return 0;\n }\n }\n return counter;\n }\n\n}\n\n/**\n * Helps to build text from inline and block elements.\n *\n * @class BlockTextBuilder\n */\nclass BlockTextBuilder {\n\n /**\n * Creates an instance of BlockTextBuilder.\n *\n * @param { Options } options HtmlToText options.\n * @param { import('selderee').Picker<DomNode, TagDefinition> } picker Selectors decision tree picker.\n * @param { any} [metadata] Optional metadata for HTML document, for use in formatters.\n */\n constructor (options, picker, metadata = undefined) {\n this.options = options;\n this.picker = picker;\n this.metadata = metadata;\n this.whitespaceProcessor = new WhitespaceProcessor(options);\n /** @type { StackItem } */\n this._stackItem = new BlockStackItem(options);\n /** @type { TransformerStackItem } */\n this._wordTransformer = undefined;\n }\n\n /**\n * Put a word-by-word transform function onto the transformations stack.\n *\n * Mainly used for uppercasing. Can be bypassed to add unformatted text such as URLs.\n *\n * Word transformations applied before wrapping.\n *\n * @param { (str: string) => string } wordTransform Word transformation function.\n */\n pushWordTransform (wordTransform) {\n this._wordTransformer = new TransformerStackItem(this._wordTransformer, wordTransform);\n }\n\n /**\n * Remove a function from the word transformations stack.\n *\n * @returns { (str: string) => string } A function that was removed.\n */\n popWordTransform () {\n if (!this._wordTransformer) { return undefined; }\n const transform = this._wordTransformer.transform;\n this._wordTransformer = this._wordTransformer.next;\n return transform;\n }\n\n /**\n * Ignore wordwrap option in followup inline additions and disable automatic wrapping.\n */\n startNoWrap () {\n this._stackItem.isNoWrap = true;\n }\n\n /**\n * Return automatic wrapping to behavior defined by options.\n */\n stopNoWrap () {\n this._stackItem.isNoWrap = false;\n }\n\n /** @returns { (str: string) => string } */\n _getCombinedWordTransformer () {\n const wt = (this._wordTransformer)\n ? ((str) => applyTransformer(str, this._wordTransformer))\n : undefined;\n const ce = this.options.encodeCharacters;\n return (wt)\n ? ((ce) ? (str) => ce(wt(str)) : wt)\n : ce;\n }\n\n _popStackItem () {\n const item = this._stackItem;\n this._stackItem = item.next;\n return item;\n }\n\n /**\n * Add a line break into currently built block.\n */\n addLineBreak () {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n if (this._stackItem.isPre) {\n this._stackItem.rawText += '\\n';\n } else {\n this._stackItem.inlineTextBuilder.startNewLine();\n }\n }\n\n /**\n * Allow to break line in case directly following text will not fit.\n */\n addWordBreakOpportunity () {\n if (\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n ) {\n this._stackItem.inlineTextBuilder.wordBreakOpportunity = true;\n }\n }\n\n /**\n * Add a node inline into the currently built block.\n *\n * @param { string } str\n * Text content of a node to add.\n *\n * @param { object } [param1]\n * Object holding the parameters of the operation.\n *\n * @param { boolean } [param1.noWordTransform]\n * Ignore word transformers if there are any.\n * Don't encode characters as well.\n * (Use this for things like URL addresses).\n */\n addInline (str, { noWordTransform = false } = {}) {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n\n if (this._stackItem.isPre) {\n this._stackItem.rawText += str;\n return;\n }\n\n if (\n str.length === 0 || // empty string\n (\n this._stackItem.stashedLineBreaks && // stashed linebreaks make whitespace irrelevant\n !this.whitespaceProcessor.testContainsWords(str) // no words to add\n )\n ) { return; }\n\n if (this.options.preserveNewlines) {\n const newlinesNumber = this.whitespaceProcessor.countNewlinesNoWords(str);\n if (newlinesNumber > 0) {\n this._stackItem.inlineTextBuilder.startNewLine(newlinesNumber);\n // keep stashedLineBreaks unchanged\n return;\n }\n }\n\n if (this._stackItem.stashedLineBreaks) {\n this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);\n }\n this.whitespaceProcessor.shrinkWrapAdd(\n str,\n this._stackItem.inlineTextBuilder,\n (noWordTransform) ? undefined : this._getCombinedWordTransformer(),\n this._stackItem.isNoWrap\n );\n this._stackItem.stashedLineBreaks = 0; // inline text doesn't introduce line breaks\n }\n\n /**\n * Add a string inline into the currently built block.\n *\n * Use this for markup elements that don't have to adhere\n * to text layout rules.\n *\n * @param { string } str Text to add.\n */\n addLiteral (str) {\n if (!(\n this._stackItem instanceof BlockStackItem\n || this._stackItem instanceof ListItemStackItem\n || this._stackItem instanceof TableCellStackItem\n )) { return; }\n\n if (str.length === 0) { return; }\n\n if (this._stackItem.isPre) {\n this._stackItem.rawText += str;\n return;\n }\n\n if (this._stackItem.stashedLineBreaks) {\n this._stackItem.inlineTextBuilder.startNewLine(this._stackItem.stashedLineBreaks);\n }\n this.whitespaceProcessor.addLiteral(\n str,\n this._stackItem.inlineTextBuilder,\n this._stackItem.isNoWrap\n );\n this._stackItem.stashedLineBreaks = 0;\n }\n\n /**\n * Start building a new block.\n *\n * @param { object } [param0]\n * Object holding the parameters of the block.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This block should have at least this number of line breaks to separate it from any preceding block.\n *\n * @param { number } [param0.reservedLineLength]\n * Reserve this number of characters on each line for block markup.\n *\n * @param { boolean } [param0.isPre]\n * Should HTML whitespace be preserved inside this block.\n */\n openBlock ({ leadingLineBreaks = 1, reservedLineLength = 0, isPre = false } = {}) {\n const maxLineLength = Math.max(20, this._stackItem.inlineTextBuilder.maxLineLength - reservedLineLength);\n this._stackItem = new BlockStackItem(\n this.options,\n this._stackItem,\n leadingLineBreaks,\n maxLineLength\n );\n if (isPre) { this._stackItem.isPre = true; }\n }\n\n /**\n * Finalize currently built block, add it's content to the parent block.\n *\n * @param { object } [param0]\n * Object holding the parameters of the block.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This block should have at least this number of line breaks to separate it from any following block.\n *\n * @param { (str: string) => string } [param0.blockTransform]\n * A function to transform the block text before adding to the parent block.\n * This happens after word wrap and should be used in combination with reserved line length\n * in order to keep line lengths correct.\n * Used for whole block markup.\n */\n closeBlock ({ trailingLineBreaks = 1, blockTransform = undefined } = {}) {\n const block = this._popStackItem();\n const blockText = (blockTransform) ? blockTransform(getText(block)) : getText(block);\n addText(this._stackItem, blockText, block.leadingLineBreaks, Math.max(block.stashedLineBreaks, trailingLineBreaks));\n }\n\n /**\n * Start building a new list.\n *\n * @param { object } [param0]\n * Object holding the parameters of the list.\n *\n * @param { number } [param0.maxPrefixLength]\n * Length of the longest list item prefix.\n * If not supplied or too small then list items won't be aligned properly.\n *\n * @param { 'left' | 'right' } [param0.prefixAlign]\n * Specify how prefixes of different lengths have to be aligned\n * within a column.\n *\n * @param { number } [param0.interRowLineBreaks]\n * Minimum number of line breaks between list items.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This list should have at least this number of line breaks to separate it from any preceding block.\n */\n openList ({ maxPrefixLength = 0, prefixAlign = 'left', interRowLineBreaks = 1, leadingLineBreaks = 2 } = {}) {\n this._stackItem = new ListStackItem(this.options, this._stackItem, {\n interRowLineBreaks: interRowLineBreaks,\n leadingLineBreaks: leadingLineBreaks,\n maxLineLength: this._stackItem.inlineTextBuilder.maxLineLength,\n maxPrefixLength: maxPrefixLength,\n prefixAlign: prefixAlign\n });\n }\n\n /**\n * Start building a new list item.\n *\n * @param {object} param0\n * Object holding the parameters of the list item.\n *\n * @param { string } [param0.prefix]\n * Prefix for this list item (item number, bullet point, etc).\n */\n openListItem ({ prefix = '' } = {}) {\n if (!(this._stackItem instanceof ListStackItem)) {\n throw new Error('Can\\'t add a list item to something that is not a list! Check the formatter.');\n }\n const list = this._stackItem;\n const prefixLength = Math.max(prefix.length, list.maxPrefixLength);\n const maxLineLength = Math.max(20, list.inlineTextBuilder.maxLineLength - prefixLength);\n this._stackItem = new ListItemStackItem(this.options, list, {\n prefix: prefix,\n maxLineLength: maxLineLength,\n leadingLineBreaks: list.interRowLineBreaks\n });\n }\n\n /**\n * Finalize currently built list item, add it's content to the parent list.\n */\n closeListItem () {\n const listItem = this._popStackItem();\n const list = listItem.next;\n\n const prefixLength = Math.max(listItem.prefix.length, list.maxPrefixLength);\n const spacing = '\\n' + ' '.repeat(prefixLength);\n const prefix = (list.prefixAlign === 'right')\n ? listItem.prefix.padStart(prefixLength)\n : listItem.prefix.padEnd(prefixLength);\n const text = prefix + getText(listItem).replace(/\\n/g, spacing);\n\n addText(\n list,\n text,\n listItem.leadingLineBreaks,\n Math.max(listItem.stashedLineBreaks, list.interRowLineBreaks)\n );\n }\n\n /**\n * Finalize currently built list, add it's content to the parent block.\n *\n * @param { object } param0\n * Object holding the parameters of the list.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This list should have at least this number of line breaks to separate it from any following block.\n */\n closeList ({ trailingLineBreaks = 2 } = {}) {\n const list = this._popStackItem();\n const text = getText(list);\n if (text) {\n addText(this._stackItem, text, list.leadingLineBreaks, trailingLineBreaks);\n }\n }\n\n /**\n * Start building a table.\n */\n openTable () {\n this._stackItem = new TableStackItem(this._stackItem);\n }\n\n /**\n * Start building a table row.\n */\n openTableRow () {\n if (!(this._stackItem instanceof TableStackItem)) {\n throw new Error('Can\\'t add a table row to something that is not a table! Check the formatter.');\n }\n this._stackItem = new TableRowStackItem(this._stackItem);\n }\n\n /**\n * Start building a table cell.\n *\n * @param { object } [param0]\n * Object holding the parameters of the cell.\n *\n * @param { number } [param0.maxColumnWidth]\n * Wrap cell content to this width. Fall back to global wordwrap value if undefined.\n */\n openTableCell ({ maxColumnWidth = undefined } = {}) {\n if (!(this._stackItem instanceof TableRowStackItem)) {\n throw new Error('Can\\'t add a table cell to something that is not a table row! Check the formatter.');\n }\n this._stackItem = new TableCellStackItem(this.options, this._stackItem, maxColumnWidth);\n }\n\n /**\n * Finalize currently built table cell and add it to parent table row's cells.\n *\n * @param { object } [param0]\n * Object holding the parameters of the cell.\n *\n * @param { number } [param0.colspan] How many columns this cell should occupy.\n * @param { number } [param0.rowspan] How many rows this cell should occupy.\n */\n closeTableCell ({ colspan = 1, rowspan = 1 } = {}) {\n const cell = this._popStackItem();\n const text = trimCharacter(getText(cell), '\\n');\n cell.next.cells.push({ colspan: colspan, rowspan: rowspan, text: text });\n }\n\n /**\n * Finalize currently built table row and add it to parent table's rows.\n */\n closeTableRow () {\n const row = this._popStackItem();\n row.next.rows.push(row.cells);\n }\n\n /**\n * Finalize currently built table and add the rendered text to the parent block.\n *\n * @param { object } param0\n * Object holding the parameters of the table.\n *\n * @param { TablePrinter } param0.tableToString\n * A function to convert a table of stringified cells into a complete table.\n *\n * @param { number } [param0.leadingLineBreaks]\n * This table should have at least this number of line breaks to separate if from any preceding block.\n *\n * @param { number } [param0.trailingLineBreaks]\n * This table should have at least this number of line breaks to separate it from any following block.\n */\n closeTable ({ tableToString, leadingLineBreaks = 2, trailingLineBreaks = 2 }) {\n const table = this._popStackItem();\n const output = tableToString(table.rows);\n if (output) {\n addText(this._stackItem, output, leadingLineBreaks, trailingLineBreaks);\n }\n }\n\n /**\n * Return the rendered text content of this builder.\n *\n * @returns { string }\n */\n toString () {\n return getText(this._stackItem.getRoot());\n // There should only be the root item if everything is closed properly.\n }\n\n}\n\nfunction getText (stackItem) {\n if (!(\n stackItem instanceof BlockStackItem\n || stackItem instanceof ListItemStackItem\n || stackItem instanceof TableCellStackItem\n )) {\n throw new Error('Only blocks, list items and table cells can be requested for text contents.');\n }\n return (stackItem.inlineTextBuilder.isEmpty())\n ? stackItem.rawText\n : stackItem.rawText + stackItem.inlineTextBuilder.toString();\n}\n\nfunction addText (stackItem, text, leadingLineBreaks, trailingLineBreaks) {\n if (!(\n stackItem instanceof BlockStackItem\n || stackItem instanceof ListItemStackItem\n || stackItem instanceof TableCellStackItem\n )) {\n throw new Error('Only blocks, list items and table cells can contain text.');\n }\n const parentText = getText(stackItem);\n const lineBreaks = Math.max(stackItem.stashedLineBreaks, leadingLineBreaks);\n stackItem.inlineTextBuilder.clear();\n if (parentText) {\n stackItem.rawText = parentText + '\\n'.repeat(lineBreaks) + text;\n } else {\n stackItem.rawText = text;\n stackItem.leadingLineBreaks = lineBreaks;\n }\n stackItem.stashedLineBreaks = trailingLineBreaks;\n}\n\n/**\n * @param { string } str A string to transform.\n * @param { TransformerStackItem } transformer A transformer item (with possible continuation).\n * @returns { string }\n */\nfunction applyTransformer (str, transformer) {\n return ((transformer) ? applyTransformer(transformer.transform(str), transformer.next) : str);\n}\n\n/**\n * Compile selectors into a decision tree,\n * return a function intended for batch processing.\n *\n * @param { Options } [options = {}] HtmlToText options (defaults, formatters, user options merged, deduplicated).\n * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.\n * @static\n */\nfunction compile$1 (options = {}) {\n const selectorsWithoutFormat = options.selectors.filter(s => !s.format);\n if (selectorsWithoutFormat.length) {\n throw new Error(\n 'Following selectors have no specified format: ' +\n selectorsWithoutFormat.map(s => `\\`${s.selector}\\``).join(', ')\n );\n }\n const picker = new selderee.DecisionTree(\n options.selectors.map(s => [s.selector, s])\n ).build(pluginHtmlparser2.hp2Builder);\n\n if (typeof options.encodeCharacters !== 'function') {\n options.encodeCharacters = makeReplacerFromDict(options.encodeCharacters);\n }\n\n const baseSelectorsPicker = new selderee.DecisionTree(\n options.baseElements.selectors.map((s, i) => [s, i + 1])\n ).build(pluginHtmlparser2.hp2Builder);\n function findBaseElements (dom) {\n return findBases(dom, options, baseSelectorsPicker);\n }\n\n const limitedWalk = limitedDepthRecursive(\n options.limits.maxDepth,\n recursiveWalk,\n function (dom, builder) {\n builder.addInline(options.limits.ellipsis || '');\n }\n );\n\n return function (html, metadata = undefined) {\n return process(html, metadata, options, picker, findBaseElements, limitedWalk);\n };\n}\n\n\n/**\n * Convert given HTML according to preprocessed options.\n *\n * @param { string } html HTML content to convert.\n * @param { any } metadata Optional metadata for HTML document, for use in formatters.\n * @param { Options } options HtmlToText options (preprocessed).\n * @param { import('selderee').Picker<DomNode, TagDefinition> } picker\n * Tag definition picker for DOM nodes processing.\n * @param { (dom: DomNode[]) => DomNode[] } findBaseElements\n * Function to extract elements from HTML DOM\n * that will only be present in the output text.\n * @param { RecursiveCallback } walk Recursive callback.\n * @returns { string }\n */\nfunction process (html, metadata, options, picker, findBaseElements, walk) {\n const maxInputLength = options.limits.maxInputLength;\n if (maxInputLength && html && html.length > maxInputLength) {\n console.warn(\n `Input length ${html.length} is above allowed limit of ${maxInputLength}. Truncating without ellipsis.`\n );\n html = html.substring(0, maxInputLength);\n }\n\n const document = htmlparser2.parseDocument(html, { decodeEntities: options.decodeEntities });\n const bases = findBaseElements(document.children);\n const builder = new BlockTextBuilder(options, picker, metadata);\n walk(bases, builder);\n return builder.toString();\n}\n\n\nfunction findBases (dom, options, baseSelectorsPicker) {\n const results = [];\n\n function recursiveWalk (walk, /** @type { DomNode[] } */ dom) {\n dom = dom.slice(0, options.limits.maxChildNodes);\n for (const elem of dom) {\n if (elem.type !== 'tag') {\n continue;\n }\n const pickedSelectorIndex = baseSelectorsPicker.pick1(elem);\n if (pickedSelectorIndex > 0) {\n results.push({ selectorIndex: pickedSelectorIndex, element: elem });\n } else if (elem.children) {\n walk(elem.children);\n }\n if (results.length >= options.limits.maxBaseElements) {\n return;\n }\n }\n }\n\n const limitedWalk = limitedDepthRecursive(\n options.limits.maxDepth,\n recursiveWalk\n );\n limitedWalk(dom);\n\n if (options.baseElements.orderBy !== 'occurrence') { // 'selectors'\n results.sort((a, b) => a.selectorIndex - b.selectorIndex);\n }\n return (options.baseElements.returnDomByDefault && results.length === 0)\n ? dom\n : results.map(x => x.element);\n}\n\n/**\n * Function to walk through DOM nodes and accumulate their string representations.\n *\n * @param { RecursiveCallback } walk Recursive callback.\n * @param { DomNode[] } [dom] Nodes array to process.\n * @param { BlockTextBuilder } builder Passed around to accumulate output text.\n * @private\n */\nfunction recursiveWalk (walk, dom, builder) {\n if (!dom) { return; }\n\n const options = builder.options;\n\n const tooManyChildNodes = dom.length > options.limits.maxChildNodes;\n if (tooManyChildNodes) {\n dom = dom.slice(0, options.limits.maxChildNodes);\n dom.push({\n data: options.limits.ellipsis,\n type: 'text'\n });\n }\n\n for (const elem of dom) {\n switch (elem.type) {\n case 'text': {\n builder.addInline(elem.data);\n break;\n }\n case 'tag': {\n const tagDefinition = builder.picker.pick1(elem);\n const format = options.formatters[tagDefinition.format];\n format(elem, walk, builder, tagDefinition.options || {});\n break;\n }\n }\n }\n\n return;\n}\n\n/**\n * @param { Object<string,string | false> } dict\n * A dictionary where keys are characters to replace\n * and values are replacement strings.\n *\n * First code point from dict keys is used.\n * Compound emojis with ZWJ are not supported (not until Node 16).\n *\n * @returns { ((str: string) => string) | undefined }\n */\nfunction makeReplacerFromDict (dict) {\n if (!dict || Object.keys(dict).length === 0) {\n return undefined;\n }\n /** @type { [string, string][] } */\n const entries = Object.entries(dict).filter(([, v]) => v !== false);\n const regex = new RegExp(\n entries\n .map(([c]) => `(${unicodeEscape([...c][0])})`)\n .join('|'),\n 'g'\n );\n const values = entries.map(([, v]) => v);\n const replacer = (m, ...cgs) => values[cgs.findIndex(cg => cg)];\n return (str) => str.replace(regex, replacer);\n}\n\n/**\n * Dummy formatter that discards the input and does nothing.\n *\n * @type { FormatCallback }\n */\nfunction formatSkip (elem, walk, builder, formatOptions) {\n /* do nothing */\n}\n\n/**\n * Insert the given string literal inline instead of a tag.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineString (elem, walk, builder, formatOptions) {\n builder.addLiteral(formatOptions.string || '');\n}\n\n/**\n * Insert a block with the given string literal instead of a tag.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockString (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.addLiteral(formatOptions.string || '');\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process an inline-level element.\n *\n * @type { FormatCallback }\n */\nfunction formatInline (elem, walk, builder, formatOptions) {\n walk(elem.children, builder);\n}\n\n/**\n * Process a block-level container.\n *\n * @type { FormatCallback }\n */\nfunction formatBlock$1 (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\nfunction renderOpenTag (elem) {\n const attrs = (elem.attribs && elem.attribs.length)\n ? ' ' + Object.entries(elem.attribs)\n .map(([k, v]) => ((v === '') ? k : `${k}=${v.replace(/\"/g, '&quot;')}`))\n .join(' ')\n : '';\n return `<${elem.name}${attrs}>`;\n}\n\nfunction renderCloseTag (elem) {\n return `</${elem.name}>`;\n}\n\n/**\n * Render an element as inline HTML tag, walk through it's children.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineTag (elem, walk, builder, formatOptions) {\n builder.startNoWrap();\n builder.addLiteral(renderOpenTag(elem));\n builder.stopNoWrap();\n walk(elem.children, builder);\n builder.startNoWrap();\n builder.addLiteral(renderCloseTag(elem));\n builder.stopNoWrap();\n}\n\n/**\n * Render an element as HTML block bag, walk through it's children.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockTag (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.startNoWrap();\n builder.addLiteral(renderOpenTag(elem));\n builder.stopNoWrap();\n walk(elem.children, builder);\n builder.startNoWrap();\n builder.addLiteral(renderCloseTag(elem));\n builder.stopNoWrap();\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Render an element with all it's children as inline HTML.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineHtml (elem, walk, builder, formatOptions) {\n builder.startNoWrap();\n builder.addLiteral(\n domSerializer.render(elem, { decodeEntities: builder.options.decodeEntities })\n );\n builder.stopNoWrap();\n}\n\n/**\n * Render an element with all it's children as HTML block.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockHtml (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.startNoWrap();\n builder.addLiteral(\n domSerializer.render(elem, { decodeEntities: builder.options.decodeEntities })\n );\n builder.stopNoWrap();\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Render inline element wrapped with given strings.\n *\n * @type { FormatCallback }\n */\nfunction formatInlineSurround (elem, walk, builder, formatOptions) {\n builder.addLiteral(formatOptions.prefix || '');\n walk(elem.children, builder);\n builder.addLiteral(formatOptions.suffix || '');\n}\n\nvar genericFormatters = /*#__PURE__*/Object.freeze({\n __proto__: null,\n block: formatBlock$1,\n blockHtml: formatBlockHtml,\n blockString: formatBlockString,\n blockTag: formatBlockTag,\n inline: formatInline,\n inlineHtml: formatInlineHtml,\n inlineString: formatInlineString,\n inlineSurround: formatInlineSurround,\n inlineTag: formatInlineTag,\n skip: formatSkip\n});\n\nfunction getRow (matrix, j) {\n if (!matrix[j]) { matrix[j] = []; }\n return matrix[j];\n}\n\nfunction findFirstVacantIndex (row, x = 0) {\n while (row[x]) { x++; }\n return x;\n}\n\nfunction transposeInPlace (matrix, maxSize) {\n for (let i = 0; i < maxSize; i++) {\n const rowI = getRow(matrix, i);\n for (let j = 0; j < i; j++) {\n const rowJ = getRow(matrix, j);\n if (rowI[j] || rowJ[i]) {\n const temp = rowI[j];\n rowI[j] = rowJ[i];\n rowJ[i] = temp;\n }\n }\n }\n}\n\nfunction putCellIntoLayout (cell, layout, baseRow, baseCol) {\n for (let r = 0; r < cell.rowspan; r++) {\n const layoutRow = getRow(layout, baseRow + r);\n for (let c = 0; c < cell.colspan; c++) {\n layoutRow[baseCol + c] = cell;\n }\n }\n}\n\nfunction getOrInitOffset (offsets, index) {\n if (offsets[index] === undefined) {\n offsets[index] = (index === 0) ? 0 : 1 + getOrInitOffset(offsets, index - 1);\n }\n return offsets[index];\n}\n\nfunction updateOffset (offsets, base, span, value) {\n offsets[base + span] = Math.max(\n getOrInitOffset(offsets, base + span),\n getOrInitOffset(offsets, base) + value\n );\n}\n\n/**\n * Render a table into a string.\n * Cells can contain multiline text and span across multiple rows and columns.\n *\n * Modifies cells to add lines array.\n *\n * @param { TablePrinterCell[][] } tableRows Table to render.\n * @param { number } rowSpacing Number of spaces between columns.\n * @param { number } colSpacing Number of empty lines between rows.\n * @returns { string }\n */\nfunction tableToString (tableRows, rowSpacing, colSpacing) {\n const layout = [];\n let colNumber = 0;\n const rowNumber = tableRows.length;\n const rowOffsets = [0];\n // Fill the layout table and row offsets row-by-row.\n for (let j = 0; j < rowNumber; j++) {\n const layoutRow = getRow(layout, j);\n const cells = tableRows[j];\n let x = 0;\n for (let i = 0; i < cells.length; i++) {\n const cell = cells[i];\n x = findFirstVacantIndex(layoutRow, x);\n putCellIntoLayout(cell, layout, j, x);\n x += cell.colspan;\n cell.lines = cell.text.split('\\n');\n const cellHeight = cell.lines.length;\n updateOffset(rowOffsets, j, cell.rowspan, cellHeight + rowSpacing);\n }\n colNumber = (layoutRow.length > colNumber) ? layoutRow.length : colNumber;\n }\n\n transposeInPlace(layout, (rowNumber > colNumber) ? rowNumber : colNumber);\n\n const outputLines = [];\n const colOffsets = [0];\n // Fill column offsets and output lines column-by-column.\n for (let x = 0; x < colNumber; x++) {\n let y = 0;\n let cell;\n const rowsInThisColumn = Math.min(rowNumber, layout[x].length);\n while (y < rowsInThisColumn) {\n cell = layout[x][y];\n if (cell) {\n if (!cell.rendered) {\n let cellWidth = 0;\n for (let j = 0; j < cell.lines.length; j++) {\n const line = cell.lines[j];\n const lineOffset = rowOffsets[y] + j;\n outputLines[lineOffset] = (outputLines[lineOffset] || '').padEnd(colOffsets[x]) + line;\n cellWidth = (line.length > cellWidth) ? line.length : cellWidth;\n }\n updateOffset(colOffsets, x, cell.colspan, cellWidth + colSpacing);\n cell.rendered = true;\n }\n y += cell.rowspan;\n } else {\n const lineOffset = rowOffsets[y];\n outputLines[lineOffset] = (outputLines[lineOffset] || '');\n y++;\n }\n }\n }\n\n return outputLines.join('\\n');\n}\n\n/**\n * Process a line-break.\n *\n * @type { FormatCallback }\n */\nfunction formatLineBreak (elem, walk, builder, formatOptions) {\n builder.addLineBreak();\n}\n\n/**\n * Process a `wbr` tag (word break opportunity).\n *\n * @type { FormatCallback }\n */\nfunction formatWbr (elem, walk, builder, formatOptions) {\n builder.addWordBreakOpportunity();\n}\n\n/**\n * Process a horizontal line.\n *\n * @type { FormatCallback }\n */\nfunction formatHorizontalLine (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n builder.addInline('-'.repeat(formatOptions.length || builder.options.wordwrap || 40));\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a paragraph.\n *\n * @type { FormatCallback }\n */\nfunction formatParagraph (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a preformatted content.\n *\n * @type { FormatCallback }\n */\nfunction formatPre (elem, walk, builder, formatOptions) {\n builder.openBlock({\n isPre: true,\n leadingLineBreaks: formatOptions.leadingLineBreaks || 2\n });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a heading.\n *\n * @type { FormatCallback }\n */\nfunction formatHeading (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks || 2 });\n if (formatOptions.uppercase !== false) {\n builder.pushWordTransform(str => str.toUpperCase());\n walk(elem.children, builder);\n builder.popWordTransform();\n } else {\n walk(elem.children, builder);\n }\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks || 2 });\n}\n\n/**\n * Process a blockquote.\n *\n * @type { FormatCallback }\n */\nfunction formatBlockquote (elem, walk, builder, formatOptions) {\n builder.openBlock({\n leadingLineBreaks: formatOptions.leadingLineBreaks || 2,\n reservedLineLength: 2\n });\n walk(elem.children, builder);\n builder.closeBlock({\n trailingLineBreaks: formatOptions.trailingLineBreaks || 2,\n blockTransform: str => ((formatOptions.trimEmptyLines !== false) ? trimCharacter(str, '\\n') : str)\n .split('\\n')\n .map(line => '> ' + line)\n .join('\\n')\n });\n}\n\nfunction withBrackets (str, brackets) {\n if (!brackets) { return str; }\n\n const lbr = (typeof brackets[0] === 'string')\n ? brackets[0]\n : '[';\n const rbr = (typeof brackets[1] === 'string')\n ? brackets[1]\n : ']';\n return lbr + str + rbr;\n}\n\nfunction pathRewrite (path, rewriter, baseUrl, metadata, elem) {\n const modifiedPath = (typeof rewriter === 'function')\n ? rewriter(path, metadata, elem)\n : path;\n return (modifiedPath[0] === '/' && baseUrl)\n ? trimCharacterEnd(baseUrl, '/') + modifiedPath\n : modifiedPath;\n}\n\n/**\n * Process an image.\n *\n * @type { FormatCallback }\n */\nfunction formatImage (elem, walk, builder, formatOptions) {\n const attribs = elem.attribs || {};\n const alt = (attribs.alt)\n ? attribs.alt\n : '';\n const src = (!attribs.src)\n ? ''\n : pathRewrite(attribs.src, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);\n const text = (!src)\n ? alt\n : (!alt)\n ? withBrackets(src, formatOptions.linkBrackets)\n : alt + ' ' + withBrackets(src, formatOptions.linkBrackets);\n\n builder.addInline(text, { noWordTransform: true });\n}\n\n// a img baseUrl\n// a img pathRewrite\n// a img linkBrackets\n\n// a ignoreHref: false\n// ignoreText ?\n// a noAnchorUrl: true\n// can be replaced with selector\n// a hideLinkHrefIfSameAsText: false\n// how to compare, what to show (text, href, normalized) ?\n// a mailto protocol removed without options\n\n// a protocols: mailto, tel, ...\n// can be matched with selector?\n\n// anchors, protocols - only if no pathRewrite fn is provided\n\n// normalize-url ?\n\n// a\n// a[href^=\"#\"] - format:skip by default\n// a[href^=\"mailto:\"] - ?\n\n/**\n * Process an anchor.\n *\n * @type { FormatCallback }\n */\nfunction formatAnchor (elem, walk, builder, formatOptions) {\n function getHref () {\n if (formatOptions.ignoreHref) { return ''; }\n if (!elem.attribs || !elem.attribs.href) { return ''; }\n let href = elem.attribs.href.replace(/^mailto:/, '');\n if (formatOptions.noAnchorUrl && href[0] === '#') { return ''; }\n href = pathRewrite(href, formatOptions.pathRewrite, formatOptions.baseUrl, builder.metadata, elem);\n return href;\n }\n const href = getHref();\n if (!href) {\n walk(elem.children, builder);\n } else {\n let text = '';\n builder.pushWordTransform(\n str => {\n if (str) { text += str; }\n return str;\n }\n );\n walk(elem.children, builder);\n builder.popWordTransform();\n\n const hideSameLink = formatOptions.hideLinkHrefIfSameAsText && href === text;\n if (!hideSameLink) {\n builder.addInline(\n (!text)\n ? href\n : ' ' + withBrackets(href, formatOptions.linkBrackets),\n { noWordTransform: true }\n );\n }\n }\n}\n\n/**\n * @param { DomNode } elem List items with their prefixes.\n * @param { RecursiveCallback } walk Recursive callback to process child nodes.\n * @param { BlockTextBuilder } builder Passed around to accumulate output text.\n * @param { FormatOptions } formatOptions Options specific to a formatter.\n * @param { () => string } nextPrefixCallback Function that returns increasing index each time it is called.\n */\nfunction formatList (elem, walk, builder, formatOptions, nextPrefixCallback) {\n const isNestedList = get(elem, ['parent', 'name']) === 'li';\n\n // With Roman numbers, index length is not as straightforward as with Arabic numbers or letters,\n // so the dumb length comparison is the most robust way to get the correct value.\n let maxPrefixLength = 0;\n const listItems = (elem.children || [])\n // it might be more accurate to check only for html spaces here, but no significant benefit\n .filter(child => child.type !== 'text' || !/^\\s*$/.test(child.data))\n .map(function (child) {\n if (child.name !== 'li') {\n return { node: child, prefix: '' };\n }\n const prefix = (isNestedList)\n ? nextPrefixCallback().trimStart()\n : nextPrefixCallback();\n if (prefix.length > maxPrefixLength) { maxPrefixLength = prefix.length; }\n return { node: child, prefix: prefix };\n });\n if (!listItems.length) { return; }\n\n builder.openList({\n interRowLineBreaks: 1,\n leadingLineBreaks: isNestedList ? 1 : (formatOptions.leadingLineBreaks || 2),\n maxPrefixLength: maxPrefixLength,\n prefixAlign: 'left'\n });\n\n for (const { node, prefix } of listItems) {\n builder.openListItem({ prefix: prefix });\n walk([node], builder);\n builder.closeListItem();\n }\n\n builder.closeList({ trailingLineBreaks: isNestedList ? 1 : (formatOptions.trailingLineBreaks || 2) });\n}\n\n/**\n * Process an unordered list.\n *\n * @type { FormatCallback }\n */\nfunction formatUnorderedList (elem, walk, builder, formatOptions) {\n const prefix = formatOptions.itemPrefix || ' * ';\n return formatList(elem, walk, builder, formatOptions, () => prefix);\n}\n\n/**\n * Process an ordered list.\n *\n * @type { FormatCallback }\n */\nfunction formatOrderedList (elem, walk, builder, formatOptions) {\n let nextIndex = Number(elem.attribs.start || '1');\n const indexFunction = getOrderedListIndexFunction(elem.attribs.type);\n const nextPrefixCallback = () => ' ' + indexFunction(nextIndex++) + '. ';\n return formatList(elem, walk, builder, formatOptions, nextPrefixCallback);\n}\n\n/**\n * Return a function that can be used to generate index markers of a specified format.\n *\n * @param { string } [olType='1'] Marker type.\n * @returns { (i: number) => string }\n */\nfunction getOrderedListIndexFunction (olType = '1') {\n switch (olType) {\n case 'a': return (i) => numberToLetterSequence(i, 'a');\n case 'A': return (i) => numberToLetterSequence(i, 'A');\n case 'i': return (i) => numberToRoman(i).toLowerCase();\n case 'I': return (i) => numberToRoman(i);\n case '1':\n default: return (i) => (i).toString();\n }\n}\n\n/**\n * Given a list of class and ID selectors (prefixed with '.' and '#'),\n * return them as separate lists of names without prefixes.\n *\n * @param { string[] } selectors Class and ID selectors (`[\".class\", \"#id\"]` etc).\n * @returns { { classes: string[], ids: string[] } }\n */\nfunction splitClassesAndIds (selectors) {\n const classes = [];\n const ids = [];\n for (const selector of selectors) {\n if (selector.startsWith('.')) {\n classes.push(selector.substring(1));\n } else if (selector.startsWith('#')) {\n ids.push(selector.substring(1));\n }\n }\n return { classes: classes, ids: ids };\n}\n\nfunction isDataTable (attr, tables) {\n if (tables === true) { return true; }\n if (!attr) { return false; }\n\n const { classes, ids } = splitClassesAndIds(tables);\n const attrClasses = (attr['class'] || '').split(' ');\n const attrIds = (attr['id'] || '').split(' ');\n\n return attrClasses.some(x => classes.includes(x)) || attrIds.some(x => ids.includes(x));\n}\n\n/**\n * Process a table (either as a container or as a data table, depending on options).\n *\n * @type { FormatCallback }\n */\nfunction formatTable (elem, walk, builder, formatOptions) {\n return isDataTable(elem.attribs, builder.options.tables)\n ? formatDataTable(elem, walk, builder, formatOptions)\n : formatBlock(elem, walk, builder, formatOptions);\n}\n\nfunction formatBlock (elem, walk, builder, formatOptions) {\n builder.openBlock({ leadingLineBreaks: formatOptions.leadingLineBreaks });\n walk(elem.children, builder);\n builder.closeBlock({ trailingLineBreaks: formatOptions.trailingLineBreaks });\n}\n\n/**\n * Process a data table.\n *\n * @type { FormatCallback }\n */\nfunction formatDataTable (elem, walk, builder, formatOptions) {\n builder.openTable();\n elem.children.forEach(walkTable);\n builder.closeTable({\n tableToString: (rows) => tableToString(rows, formatOptions.rowSpacing ?? 0, formatOptions.colSpacing ?? 3),\n leadingLineBreaks: formatOptions.leadingLineBreaks,\n trailingLineBreaks: formatOptions.trailingLineBreaks\n });\n\n function formatCell (cellNode) {\n const colspan = +get(cellNode, ['attribs', 'colspan']) || 1;\n const rowspan = +get(cellNode, ['attribs', 'rowspan']) || 1;\n builder.openTableCell({ maxColumnWidth: formatOptions.maxColumnWidth });\n walk(cellNode.children, builder);\n builder.closeTableCell({ colspan: colspan, rowspan: rowspan });\n }\n\n function walkTable (elem) {\n if (elem.type !== 'tag') { return; }\n\n const formatHeaderCell = (formatOptions.uppercaseHeaderCells !== false)\n ? (cellNode) => {\n builder.pushWordTransform(str => str.toUpperCase());\n formatCell(cellNode);\n builder.popWordTransform();\n }\n : formatCell;\n\n switch (elem.name) {\n case 'thead':\n case 'tbody':\n case 'tfoot':\n case 'center':\n elem.children.forEach(walkTable);\n return;\n\n case 'tr': {\n builder.openTableRow();\n for (const childOfTr of elem.children) {\n if (childOfTr.type !== 'tag') { continue; }\n switch (childOfTr.name) {\n case 'th': {\n formatHeaderCell(childOfTr);\n break;\n }\n case 'td': {\n formatCell(childOfTr);\n break;\n }\n // do nothing\n }\n }\n builder.closeTableRow();\n break;\n }\n // do nothing\n }\n }\n}\n\nvar textFormatters = /*#__PURE__*/Object.freeze({\n __proto__: null,\n anchor: formatAnchor,\n blockquote: formatBlockquote,\n dataTable: formatDataTable,\n heading: formatHeading,\n horizontalLine: formatHorizontalLine,\n image: formatImage,\n lineBreak: formatLineBreak,\n orderedList: formatOrderedList,\n paragraph: formatParagraph,\n pre: formatPre,\n table: formatTable,\n unorderedList: formatUnorderedList,\n wbr: formatWbr\n});\n\n/**\n * Default options.\n *\n * @constant\n * @type { Options }\n * @default\n * @private\n */\nconst DEFAULT_OPTIONS = {\n baseElements: {\n selectors: [ 'body' ],\n orderBy: 'selectors', // 'selectors' | 'occurrence'\n returnDomByDefault: true\n },\n decodeEntities: true,\n encodeCharacters: {},\n formatters: {},\n limits: {\n ellipsis: '...',\n maxBaseElements: undefined,\n maxChildNodes: undefined,\n maxDepth: undefined,\n maxInputLength: (1 << 24) // 16_777_216\n },\n longWordSplit: {\n forceWrapOnLimit: false,\n wrapCharacters: []\n },\n preserveNewlines: false,\n selectors: [\n { selector: '*', format: 'inline' },\n {\n selector: 'a',\n format: 'anchor',\n options: {\n baseUrl: null,\n hideLinkHrefIfSameAsText: false,\n ignoreHref: false,\n linkBrackets: ['[', ']'],\n noAnchorUrl: true\n }\n },\n { selector: 'article', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'aside', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'blockquote',\n format: 'blockquote',\n options: { leadingLineBreaks: 2, trailingLineBreaks: 2, trimEmptyLines: true }\n },\n { selector: 'br', format: 'lineBreak' },\n { selector: 'div', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'footer', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'form', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'h1', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h2', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h3', format: 'heading', options: { leadingLineBreaks: 3, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h4', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h5', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'h6', format: 'heading', options: { leadingLineBreaks: 2, trailingLineBreaks: 2, uppercase: true } },\n { selector: 'header', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'hr',\n format: 'horizontalLine',\n options: { leadingLineBreaks: 2, length: undefined, trailingLineBreaks: 2 }\n },\n {\n selector: 'img',\n format: 'image',\n options: { baseUrl: null, linkBrackets: ['[', ']'] }\n },\n { selector: 'main', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n { selector: 'nav', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'ol',\n format: 'orderedList',\n options: { leadingLineBreaks: 2, trailingLineBreaks: 2 }\n },\n { selector: 'p', format: 'paragraph', options: { leadingLineBreaks: 2, trailingLineBreaks: 2 } },\n { selector: 'pre', format: 'pre', options: { leadingLineBreaks: 2, trailingLineBreaks: 2 } },\n { selector: 'section', format: 'block', options: { leadingLineBreaks: 1, trailingLineBreaks: 1 } },\n {\n selector: 'table',\n format: 'table',\n options: {\n colSpacing: 3,\n leadingLineBreaks: 2,\n maxColumnWidth: 60,\n rowSpacing: 0,\n trailingLineBreaks: 2,\n uppercaseHeaderCells: true\n }\n },\n {\n selector: 'ul',\n format: 'unorderedList',\n options: { itemPrefix: ' * ', leadingLineBreaks: 2, trailingLineBreaks: 2 }\n },\n { selector: 'wbr', format: 'wbr' },\n ],\n tables: [], // deprecated\n whitespaceCharacters: ' \\t\\r\\n\\f\\u200b',\n wordwrap: 80\n};\n\nconst concatMerge = (acc, src, options) => [...acc, ...src];\nconst overwriteMerge = (acc, src, options) => [...src];\nconst selectorsMerge = (acc, src, options) => (\n (acc.some(s => typeof s === 'object'))\n ? concatMerge(acc, src) // selectors\n : overwriteMerge(acc, src) // baseElements.selectors\n);\n\n/**\n * Preprocess options, compile selectors into a decision tree,\n * return a function intended for batch processing.\n *\n * @param { Options } [options = {}] HtmlToText options.\n * @returns { (html: string, metadata?: any) => string } Pre-configured converter function.\n * @static\n */\nfunction compile (options = {}) {\n options = merge__default[\"default\"](\n DEFAULT_OPTIONS,\n options,\n {\n arrayMerge: overwriteMerge,\n customMerge: (key) => ((key === 'selectors') ? selectorsMerge : undefined)\n }\n );\n options.formatters = Object.assign({}, genericFormatters, textFormatters, options.formatters);\n options.selectors = mergeDuplicatesPreferLast(options.selectors, (s => s.selector));\n\n handleDeprecatedOptions(options);\n\n return compile$1(options);\n}\n\n/**\n * Convert given HTML content to plain text string.\n *\n * @param { string } html HTML content to convert.\n * @param { Options } [options = {}] HtmlToText options.\n * @param { any } [metadata] Optional metadata for HTML document, for use in formatters.\n * @returns { string } Plain text string.\n * @static\n *\n * @example\n * const { convert } = require('html-to-text');\n * const text = convert('<h1>Hello World</h1>', {\n * wordwrap: 130\n * });\n * console.log(text); // HELLO WORLD\n */\nfunction convert (html, options = {}, metadata = undefined) {\n return compile(options)(html, metadata);\n}\n\n/**\n * Map previously existing and now deprecated options to the new options layout.\n * This is a subject for cleanup in major releases.\n *\n * @param { Options } options HtmlToText options.\n */\nfunction handleDeprecatedOptions (options) {\n if (options.tags) {\n const tagDefinitions = Object.entries(options.tags).map(\n ([selector, definition]) => ({ ...definition, selector: selector || '*' })\n );\n options.selectors.push(...tagDefinitions);\n options.selectors = mergeDuplicatesPreferLast(options.selectors, (s => s.selector));\n }\n\n function set (obj, path, value) {\n const valueKey = path.pop();\n for (const key of path) {\n let nested = obj[key];\n if (!nested) {\n nested = {};\n obj[key] = nested;\n }\n obj = nested;\n }\n obj[valueKey] = value;\n }\n\n if (options['baseElement']) {\n const baseElement = options['baseElement'];\n set(\n options,\n ['baseElements', 'selectors'],\n (Array.isArray(baseElement) ? baseElement : [baseElement])\n );\n }\n if (options['returnDomByDefault'] !== undefined) {\n set(options, ['baseElements', 'returnDomByDefault'], options['returnDomByDefault']);\n }\n\n for (const definition of options.selectors) {\n if (definition.format === 'anchor' && get(definition, ['options', 'noLinkBrackets'])) {\n set(definition, ['options', 'linkBrackets'], false);\n }\n }\n}\n\nexports.compile = compile;\nexports.convert = convert;\nexports.htmlToText = convert;\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKHJzYykvLi9ub2RlX21vZHVsZXMvaHRtbC10by10ZXh0L2xpYi9odG1sLXRvLXRleHQuY2pzIiwibWFwcGluZ3MiOiJBQUFhOztBQUViLDhDQUE2QyxFQUFFLGFBQWEsRUFBQzs7QUFFN0Qsd0JBQXdCLG1CQUFPLENBQUMsMkdBQThCO0FBQzlELGtCQUFrQixtQkFBTyxDQUFDLGtFQUFhO0FBQ3ZDLGVBQWUsbUJBQU8sQ0FBQyxnRUFBVTtBQUNqQyxZQUFZLG1CQUFPLENBQUMsNkRBQVc7QUFDL0Isb0JBQW9CLG1CQUFPLENBQUMsd0VBQWdCOztBQUU1QyxxQ0FBcUMsNERBQTREOztBQUVqRzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQztBQUNwQztBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0M7QUFDL0MsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxxQkFBcUI7QUFDakMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QixRQUFRO0FBQ3JDO0FBQ0E7QUFDQTtBQUNB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QUN2QztBQUNBO0FBQ0E7QUFDQSxXQUFXLFVBQVU7QUFDckI7QUFDQTtBQUNBLElBQUk7QUFDSixzQkFBc0I7QUFDdEI7QUFDQSxvQ0FBb0M7QUFDcEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksVUFBVTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQywwQ0FBMEM7QUFDL0U7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGVBQWU7QUFDZixlQUFlO0FBQ2Ysa0JBQWtCIiwic291cmNlcyI6WyIvaG9tZS9hbG1hL25leHRnZW4vTmVhaC1tYWlsL25vZGVfbW9kdWxlcy9odG1sLXRvLXRleHQvbGliL2h0bWwtdG8tdGV4dC5janMiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG5PYmplY3QuZGVmaW5lUHJvcGVydHkoZXhwb3J0cywgJ19fZXNNb2R1bGUnLCB7IHZhbHVlOiB0cnVlIH0pO1xuXG52YXIgcGx1Z2luSHRtbHBhcnNlcjIgPSByZXF1aXJlKCdAc2VsZGVyZWUvcGx1Z2luLWh0bWxwYXJzZXIyJyk7XG52YXIgaHRtbHBhcnNlcjIgPSByZXF1aXJlKCdodG1scGFyc2VyMicpO1xudmFyIHNlbGRlcmVlID0gcmVxdWlyZSgnc2VsZGVyZWUnKTtcbnZhciBtZXJnZSA9IHJlcXVpcmUoJ2RlZXBtZXJnZScpO1xudmFyIGRvbVNlcmlhbGl6ZXIgPSByZXF1aXJlKCdkb20tc2VyaWFsaXplcicpO1xuXG5mdW5jdGlvbiBfaW50ZXJvcERlZmF1bHRMZWdhY3kgKGUpIHsgcmV0dXJuIGUgJiYgdHlwZW9mIGUgPT09ICdvYmplY3QnICYmICdkZWZhdWx0JyBpbiBlID8gZSA6IHsgJ2RlZmF1bHQnOiBlIH07IH1cblxudmFyIG1lcmdlX19kZWZhdWx0ID0gLyojX19QVVJFX18qL19pbnRlcm9wRGVmYXVsdExlZ2FjeShtZXJnZSk7XG5cbi8qKlxuICogTWFrZSBhIHJlY3Vyc2l2ZSBmdW5jdGlvbiB0aGF0IHdpbGwgb25seSBydW4gdG8gYSBnaXZlbiBkZXB0aFxuICogYW5kIHN3aXRjaGVzIHRvIGFuIGFsdGVybmF0aXZlIGZ1bmN0aW9uIGF0IHRoYXQgZGVwdGguIFxcXG4gKiBObyBsaW1pdGF0aW9uIGlmIGBuYCBpcyBgdW5kZWZpbmVkYCAoSnVzdCB3cmFwcyBgZmAgaW4gdGhhdCBjYXNlKS5cbiAqXG4gKiBAcGFyYW0gICB7IG51bWJlciB8IHVuZGVmaW5lZCB9IG4gICBBbGxvd2VkIGRlcHRoIG9mIHJlY3Vyc2lvbi4gYHVuZGVmaW5lZGAgZm9yIG5vIGxpbWl0YXRpb24uXG4gKiBAcGFyYW0gICB7IEZ1bmN0aW9uIH0gICAgICAgICAgIGYgICBGdW5jdGlvbiB0aGF0IGFjY2VwdHMgcmVjdXJzaXZlIGNhbGxiYWNrIGFzIHRoZSBmaXJzdCBhcmd1bWVudC5cbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSAgICAgICAgICAgW2ddIEZ1bmN0aW9uIHRvIHJ1biBpbnN0ZWFkLCB3aGVuIG1heGltdW0gZGVwdGggd2FzIHJlYWNoZWQuIERvIG5vdGhpbmcgYnkgZGVmYXVsdC5cbiAqIEByZXR1cm5zIHsgRnVuY3Rpb24gfVxuICovXG5mdW5jdGlvbiBsaW1pdGVkRGVwdGhSZWN1cnNpdmUgKG4sIGYsIGcgPSAoKSA9PiB1bmRlZmluZWQpIHtcbiAgaWYgKG4gPT09IHVuZGVmaW5lZCkge1xuICAgIGNvbnN0IGYxID0gZnVuY3Rpb24gKC4uLmFyZ3MpIHsgcmV0dXJuIGYoZjEsIC4uLmFyZ3MpOyB9O1xuICAgIHJldHVybiBmMTtcbiAgfVxuICBpZiAobiA+PSAwKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uICguLi5hcmdzKSB7IHJldHVybiBmKGxpbWl0ZWREZXB0aFJlY3Vyc2l2ZShuIC0gMSwgZiwgZyksIC4uLmFyZ3MpOyB9O1xuICB9XG4gIHJldHVybiBnO1xufVxuXG4vKipcbiAqIFJldHVybiB0aGUgc2FtZSBzdHJpbmcgb3IgYSBzdWJzdHJpbmcgd2l0aFxuICogdGhlIGdpdmVuIGNoYXJhY3RlciBvY2N1cnJlbmNlcyByZW1vdmVkIGZyb20gZWFjaCBzaWRlLlxuICpcbiAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gc3RyICBBIHN0cmluZyB0byB0cmltLlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSBjaGFyIEEgY2hhcmFjdGVyIHRvIGJlIHRyaW1tZWQuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIHRyaW1DaGFyYWN0ZXIgKHN0ciwgY2hhcikge1xuICBsZXQgc3RhcnQgPSAwO1xuICBsZXQgZW5kID0gc3RyLmxlbmd0aDtcbiAgd2hpbGUgKHN0YXJ0IDwgZW5kICYmIHN0cltzdGFydF0gPT09IGNoYXIpIHsgKytzdGFydDsgfVxuICB3aGlsZSAoZW5kID4gc3RhcnQgJiYgc3RyW2VuZCAtIDFdID09PSBjaGFyKSB7IC0tZW5kOyB9XG4gIHJldHVybiAoc3RhcnQgPiAwIHx8IGVuZCA8IHN0ci5sZW5ndGgpXG4gICAgPyBzdHIuc3Vic3RyaW5nKHN0YXJ0LCBlbmQpXG4gICAgOiBzdHI7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBzYW1lIHN0cmluZyBvciBhIHN1YnN0cmluZyB3aXRoXG4gKiB0aGUgZ2l2ZW4gY2hhcmFjdGVyIG9jY3VycmVuY2VzIHJlbW92ZWQgZnJvbSB0aGUgZW5kIG9ubHkuXG4gKlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSBzdHIgIEEgc3RyaW5nIHRvIHRyaW0uXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IGNoYXIgQSBjaGFyYWN0ZXIgdG8gYmUgdHJpbW1lZC5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gdHJpbUNoYXJhY3RlckVuZCAoc3RyLCBjaGFyKSB7XG4gIGxldCBlbmQgPSBzdHIubGVuZ3RoO1xuICB3aGlsZSAoZW5kID4gMCAmJiBzdHJbZW5kIC0gMV0gPT09IGNoYXIpIHsgLS1lbmQ7IH1cbiAgcmV0dXJuIChlbmQgPCBzdHIubGVuZ3RoKVxuICAgID8gc3RyLnN1YnN0cmluZygwLCBlbmQpXG4gICAgOiBzdHI7XG59XG5cbi8qKlxuICogUmV0dXJuIGEgbmV3IHN0cmluZyB3aWxsIGFsbCBjaGFyYWN0ZXJzIHJlcGxhY2VkIHdpdGggdW5pY29kZSBlc2NhcGUgc2VxdWVuY2VzLlxuICogVGhpcyBleHRyZW1lIGtpbmQgb2YgZXNjYXBpbmcgY2FuIHVzZWQgdG8gYmUgc2FmZWx5IGNvbXBvc2UgcmVndWxhciBleHByZXNzaW9ucy5cbiAqXG4gKiBAcGFyYW0geyBzdHJpbmcgfSBzdHIgQSBzdHJpbmcgdG8gZXNjYXBlLlxuICogQHJldHVybnMgeyBzdHJpbmcgfSBBIHN0cmluZyBvZiB1bmljb2RlIGVzY2FwZSBzZXF1ZW5jZXMuXG4gKi9cbmZ1bmN0aW9uIHVuaWNvZGVFc2NhcGUgKHN0cikge1xuICByZXR1cm4gc3RyLnJlcGxhY2UoL1tcXHNcXFNdL2csIGMgPT4gJ1xcXFx1JyArIGMuY2hhckNvZGVBdCgpLnRvU3RyaW5nKDE2KS5wYWRTdGFydCg0LCAnMCcpKTtcbn1cblxuLyoqXG4gKiBEZWR1cGxpY2F0ZSBhbiBhcnJheSBieSBhIGdpdmVuIGtleSBjYWxsYmFjay5cbiAqIEl0ZW0gcHJvcGVydGllcyBhcmUgbWVyZ2VkIHJlY3Vyc2l2ZWx5IGFuZCB3aXRoIHRoZSBwcmVmZXJlbmNlIGZvciBsYXN0IGRlZmluZWQgdmFsdWVzLlxuICogT2YgaXRlbXMgd2l0aCB0aGUgc2FtZSBrZXksIG1lcmdlZCBpdGVtIHRha2VzIHRoZSBwbGFjZSBvZiB0aGUgbGFzdCBpdGVtLFxuICogb3RoZXJzIGFyZSBvbWl0dGVkLlxuICpcbiAqIEBwYXJhbSB7IGFueVtdIH0gaXRlbXMgQW4gYXJyYXkgdG8gZGVkdXBsaWNhdGUuXG4gKiBAcGFyYW0geyAoeDogYW55KSA9PiBzdHJpbmcgfSBnZXRLZXkgQ2FsbGJhY2sgdG8gZ2V0IGEgdmFsdWUgdGhhdCBkaXN0aW5ndWlzaGVzIHVuaXF1ZSBpdGVtcy5cbiAqIEByZXR1cm5zIHsgYW55W10gfVxuICovXG5mdW5jdGlvbiBtZXJnZUR1cGxpY2F0ZXNQcmVmZXJMYXN0IChpdGVtcywgZ2V0S2V5KSB7XG4gIGNvbnN0IG1hcCA9IG5ldyBNYXAoKTtcbiAgZm9yIChsZXQgaSA9IGl0ZW1zLmxlbmd0aDsgaS0tID4gMDspIHtcbiAgICBjb25zdCBpdGVtID0gaXRlbXNbaV07XG4gICAgY29uc3Qga2V5ID0gZ2V0S2V5KGl0ZW0pO1xuICAgIG1hcC5zZXQoXG4gICAgICBrZXksXG4gICAgICAobWFwLmhhcyhrZXkpKVxuICAgICAgICA/IG1lcmdlX19kZWZhdWx0W1wiZGVmYXVsdFwiXShpdGVtLCBtYXAuZ2V0KGtleSksIHsgYXJyYXlNZXJnZTogb3ZlcndyaXRlTWVyZ2UkMSB9KVxuICAgICAgICA6IGl0ZW1cbiAgICApO1xuICB9XG4gIHJldHVybiBbLi4ubWFwLnZhbHVlcygpXS5yZXZlcnNlKCk7XG59XG5cbmNvbnN0IG92ZXJ3cml0ZU1lcmdlJDEgPSAoYWNjLCBzcmMsIG9wdGlvbnMpID0+IFsuLi5zcmNdO1xuXG4vKipcbiAqIEdldCBhIG5lc3RlZCBwcm9wZXJ0eSBmcm9tIGFuIG9iamVjdC5cbiAqXG4gKiBAcGFyYW0gICB7IG9iamVjdCB9ICAgb2JqICBUaGUgb2JqZWN0IHRvIHF1ZXJ5IGZvciB0aGUgdmFsdWUuXG4gKiBAcGFyYW0gICB7IHN0cmluZ1tdIH0gcGF0aCBUaGUgcGF0aCB0byB0aGUgcHJvcGVydHkuXG4gKiBAcmV0dXJucyB7IGFueSB9XG4gKi9cbmZ1bmN0aW9uIGdldCAob2JqLCBwYXRoKSB7XG4gIGZvciAoY29uc3Qga2V5IG9mIHBhdGgpIHtcbiAgICBpZiAoIW9iaikgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG4gICAgb2JqID0gb2JqW2tleV07XG4gIH1cbiAgcmV0dXJuIG9iajtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGEgbnVtYmVyIGludG8gYWxwaGFiZXRpYyBzZXF1ZW5jZSByZXByZXNlbnRhdGlvbiAoU2VxdWVuY2Ugd2l0aG91dCB6ZXJvZXMpLlxuICpcbiAqIEZvciBleGFtcGxlOiBgYSwgLi4uLCB6LCBhYSwgLi4uLCB6eiwgYWFhLCAuLi5gLlxuICpcbiAqIEBwYXJhbSAgIHsgbnVtYmVyIH0gbnVtICAgICAgICAgICAgICBOdW1iZXIgdG8gY29udmVydC4gTXVzdCBiZSA+PSAxLlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSBbYmFzZUNoYXIgPSAnYSddIENoYXJhY3RlciBmb3IgMSBpbiB0aGUgc2VxdWVuY2UuXG4gKiBAcGFyYW0gICB7IG51bWJlciB9IFtiYXNlID0gMjZdICAgICAgTnVtYmVyIG9mIGNoYXJhY3RlcnMgaW4gdGhlIHNlcXVlbmNlLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiBudW1iZXJUb0xldHRlclNlcXVlbmNlIChudW0sIGJhc2VDaGFyID0gJ2EnLCBiYXNlID0gMjYpIHtcbiAgY29uc3QgZGlnaXRzID0gW107XG4gIGRvIHtcbiAgICBudW0gLT0gMTtcbiAgICBkaWdpdHMucHVzaChudW0gJSBiYXNlKTtcbiAgICBudW0gPSAobnVtIC8gYmFzZSkgPj4gMDsgLy8gcXVpY2sgYGZsb29yYFxuICB9IHdoaWxlIChudW0gPiAwKTtcbiAgY29uc3QgYmFzZUNvZGUgPSBiYXNlQ2hhci5jaGFyQ29kZUF0KDApO1xuICByZXR1cm4gZGlnaXRzXG4gICAgLnJldmVyc2UoKVxuICAgIC5tYXAobiA9PiBTdHJpbmcuZnJvbUNoYXJDb2RlKGJhc2VDb2RlICsgbikpXG4gICAgLmpvaW4oJycpO1xufVxuXG5jb25zdCBJID0gWydJJywgJ1gnLCAnQycsICdNJ107XG5jb25zdCBWID0gWydWJywgJ0wnLCAnRCddO1xuXG4vKipcbiAqIENvbnZlcnQgYSBudW1iZXIgdG8gaXQncyBSb21hbiByZXByZXNlbnRhdGlvbi4gTm8gbGFyZ2UgbnVtYmVycyBleHRlbnNpb24uXG4gKlxuICogQHBhcmFtICAgeyBudW1iZXIgfSBudW0gTnVtYmVyIHRvIGNvbnZlcnQuIGAwIDwgbnVtIDw9IDM5OTlgLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiBudW1iZXJUb1JvbWFuIChudW0pIHtcbiAgcmV0dXJuIFsuLi4obnVtKSArICcnXVxuICAgIC5tYXAobiA9PiArbilcbiAgICAucmV2ZXJzZSgpXG4gICAgLm1hcCgodiwgaSkgPT4gKCh2ICUgNSA8IDQpXG4gICAgICA/ICh2IDwgNSA/ICcnIDogVltpXSkgKyBJW2ldLnJlcGVhdCh2ICUgNSlcbiAgICAgIDogSVtpXSArICh2IDwgNSA/IFZbaV0gOiBJW2kgKyAxXSkpKVxuICAgIC5yZXZlcnNlKClcbiAgICAuam9pbignJyk7XG59XG5cbi8qKlxuICogSGVscHMgdG8gYnVpbGQgdGV4dCBmcm9tIHdvcmRzLlxuICovXG5jbGFzcyBJbmxpbmVUZXh0QnVpbGRlciB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIElubGluZVRleHRCdWlsZGVyLlxuICAgKlxuICAgKiBJZiBgbWF4TGluZUxlbmd0aGAgaXMgbm90IHByb3ZpZGVkIHRoZW4gaXQgaXMgZWl0aGVyIGBvcHRpb25zLndvcmR3cmFwYCBvciB1bmxpbWl0ZWQuXG4gICAqXG4gICAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zICAgICAgICAgICBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7IG51bWJlciB9ICBbIG1heExpbmVMZW5ndGggXSBUaGlzIGJ1aWxkZXIgd2lsbCB0cnkgdG8gd3JhcCB0ZXh0IHRvIGZpdCB0aGlzIGxpbmUgbGVuZ3RoLlxuICAgKi9cbiAgY29uc3RydWN0b3IgKG9wdGlvbnMsIG1heExpbmVMZW5ndGggPSB1bmRlZmluZWQpIHtcbiAgICAvKiogQHR5cGUgeyBzdHJpbmdbXVtdIH0gKi9cbiAgICB0aGlzLmxpbmVzID0gW107XG4gICAgLyoqIEB0eXBlIHsgc3RyaW5nW10gfSAgICovXG4gICAgdGhpcy5uZXh0TGluZVdvcmRzID0gW107XG4gICAgdGhpcy5tYXhMaW5lTGVuZ3RoID0gbWF4TGluZUxlbmd0aCB8fCBvcHRpb25zLndvcmR3cmFwIHx8IE51bWJlci5NQVhfVkFMVUU7XG4gICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzID0gdGhpcy5tYXhMaW5lTGVuZ3RoO1xuICAgIHRoaXMud3JhcENoYXJhY3RlcnMgPSBnZXQob3B0aW9ucywgWydsb25nV29yZFNwbGl0JywgJ3dyYXBDaGFyYWN0ZXJzJ10pIHx8IFtdO1xuICAgIHRoaXMuZm9yY2VXcmFwT25MaW1pdCA9IGdldChvcHRpb25zLCBbJ2xvbmdXb3JkU3BsaXQnLCAnZm9yY2VXcmFwT25MaW1pdCddKSB8fCBmYWxzZTtcblxuICAgIHRoaXMuc3Rhc2hlZFNwYWNlID0gZmFsc2U7XG4gICAgdGhpcy53b3JkQnJlYWtPcHBvcnR1bml0eSA9IGZhbHNlO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5ldyB3b3JkLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSB3b3JkIEEgd29yZCB0byBhZGQuXG4gICAqIEBwYXJhbSB7IGJvb2xlYW4gfSBbbm9XcmFwXSBEb24ndCB3cmFwIHRleHQgZXZlbiBpZiB0aGUgbGluZSBpcyB0b28gbG9uZy5cbiAgICovXG4gIHB1c2hXb3JkICh3b3JkLCBub1dyYXAgPSBmYWxzZSkge1xuICAgIGlmICh0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgPD0gMCAmJiAhbm9XcmFwKSB7XG4gICAgICB0aGlzLnN0YXJ0TmV3TGluZSgpO1xuICAgIH1cbiAgICBjb25zdCBpc0xpbmVTdGFydCA9IHRoaXMubmV4dExpbmVXb3Jkcy5sZW5ndGggPT09IDA7XG4gICAgY29uc3QgY29zdCA9IHdvcmQubGVuZ3RoICsgKGlzTGluZVN0YXJ0ID8gMCA6IDEpO1xuICAgIGlmICgoY29zdCA8PSB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMpIHx8IG5vV3JhcCkgeyAvLyBGaXRzIGludG8gYXZhaWxhYmxlIGJ1ZGdldFxuXG4gICAgICB0aGlzLm5leHRMaW5lV29yZHMucHVzaCh3b3JkKTtcbiAgICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyAtPSBjb3N0O1xuXG4gICAgfSBlbHNlIHsgLy8gRG9lcyBub3QgZml0IC0gdHJ5IHRvIHNwbGl0IHRoZSB3b3JkXG5cbiAgICAgIC8vIFRoZSB3b3JkIGlzIG1vdmVkIHRvIGEgbmV3IGxpbmUgLSBwcmVmZXIgdG8gd3JhcCBiZXR3ZWVuIHdvcmRzLlxuICAgICAgY29uc3QgW2ZpcnN0LCAuLi5yZXN0XSA9IHRoaXMuc3BsaXRMb25nV29yZCh3b3JkKTtcbiAgICAgIGlmICghaXNMaW5lU3RhcnQpIHsgdGhpcy5zdGFydE5ld0xpbmUoKTsgfVxuICAgICAgdGhpcy5uZXh0TGluZVdvcmRzLnB1c2goZmlyc3QpO1xuICAgICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzIC09IGZpcnN0Lmxlbmd0aDtcbiAgICAgIGZvciAoY29uc3QgcGFydCBvZiByZXN0KSB7XG4gICAgICAgIHRoaXMuc3RhcnROZXdMaW5lKCk7XG4gICAgICAgIHRoaXMubmV4dExpbmVXb3Jkcy5wdXNoKHBhcnQpO1xuICAgICAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgLT0gcGFydC5sZW5ndGg7XG4gICAgICB9XG5cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUG9wIGEgd29yZCBmcm9tIHRoZSBjdXJyZW50bHkgYnVpbHQgbGluZS5cbiAgICogVGhpcyBkb2Vzbid0IGFmZmVjdCBjb21wbGV0ZWQgbGluZXMuXG4gICAqXG4gICAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAgICovXG4gIHBvcFdvcmQgKCkge1xuICAgIGNvbnN0IGxhc3RXb3JkID0gdGhpcy5uZXh0TGluZVdvcmRzLnBvcCgpO1xuICAgIGlmIChsYXN0V29yZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBjb25zdCBpc0xpbmVTdGFydCA9IHRoaXMubmV4dExpbmVXb3Jkcy5sZW5ndGggPT09IDA7XG4gICAgICBjb25zdCBjb3N0ID0gbGFzdFdvcmQubGVuZ3RoICsgKGlzTGluZVN0YXJ0ID8gMCA6IDEpO1xuICAgICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzICs9IGNvc3Q7XG4gICAgfVxuICAgIHJldHVybiBsYXN0V29yZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb25jYXQgYSB3b3JkIHRvIHRoZSBsYXN0IHdvcmQgYWxyZWFkeSBpbiB0aGUgYnVpbGRlci5cbiAgICogQWRkcyBhIG5ldyB3b3JkIGluIGNhc2UgdGhlcmUgYXJlIG5vIHdvcmRzIHlldCBpbiB0aGUgbGFzdCBsaW5lLlxuICAgKlxuICAgKiBAcGFyYW0geyBzdHJpbmcgfSB3b3JkIEEgd29yZCB0byBiZSBjb25jYXRlbmF0ZWQuXG4gICAqIEBwYXJhbSB7IGJvb2xlYW4gfSBbbm9XcmFwXSBEb24ndCB3cmFwIHRleHQgZXZlbiBpZiB0aGUgbGluZSBpcyB0b28gbG9uZy5cbiAgICovXG4gIGNvbmNhdFdvcmQgKHdvcmQsIG5vV3JhcCA9IGZhbHNlKSB7XG4gICAgaWYgKHRoaXMud29yZEJyZWFrT3Bwb3J0dW5pdHkgJiYgd29yZC5sZW5ndGggPiB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMpIHtcbiAgICAgIHRoaXMucHVzaFdvcmQod29yZCwgbm9XcmFwKTtcbiAgICAgIHRoaXMud29yZEJyZWFrT3Bwb3J0dW5pdHkgPSBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgY29uc3QgbGFzdFdvcmQgPSB0aGlzLnBvcFdvcmQoKTtcbiAgICAgIHRoaXMucHVzaFdvcmQoKGxhc3RXb3JkKSA/IGxhc3RXb3JkLmNvbmNhdCh3b3JkKSA6IHdvcmQsIG5vV3JhcCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBjdXJyZW50IGxpbmUgKGFuZCBtb3JlIGVtcHR5IGxpbmVzIGlmIHByb3ZpZGVkIGFyZ3VtZW50ID4gMSkgdG8gdGhlIGxpc3Qgb2YgY29tcGxldGUgbGluZXMgYW5kIHN0YXJ0IGEgbmV3IG9uZS5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gbiBOdW1iZXIgb2YgbGluZSBicmVha3MgdGhhdCB3aWxsIGJlIGFkZGVkIHRvIHRoZSByZXN1bHRpbmcgc3RyaW5nLlxuICAgKi9cbiAgc3RhcnROZXdMaW5lIChuID0gMSkge1xuICAgIHRoaXMubGluZXMucHVzaCh0aGlzLm5leHRMaW5lV29yZHMpO1xuICAgIGlmIChuID4gMSkge1xuICAgICAgdGhpcy5saW5lcy5wdXNoKC4uLkFycmF5LmZyb20oeyBsZW5ndGg6IG4gLSAxIH0sICgpID0+IFtdKSk7XG4gICAgfVxuICAgIHRoaXMubmV4dExpbmVXb3JkcyA9IFtdO1xuICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyA9IHRoaXMubWF4TGluZUxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBObyB3b3JkcyBpbiB0aGlzIGJ1aWxkZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHsgYm9vbGVhbiB9XG4gICAqL1xuICBpc0VtcHR5ICgpIHtcbiAgICByZXR1cm4gdGhpcy5saW5lcy5sZW5ndGggPT09IDBcbiAgICAgICAgJiYgdGhpcy5uZXh0TGluZVdvcmRzLmxlbmd0aCA9PT0gMDtcbiAgfVxuXG4gIGNsZWFyICgpIHtcbiAgICB0aGlzLmxpbmVzLmxlbmd0aCA9IDA7XG4gICAgdGhpcy5uZXh0TGluZVdvcmRzLmxlbmd0aCA9IDA7XG4gICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzID0gdGhpcy5tYXhMaW5lTGVuZ3RoO1xuICB9XG5cbiAgLyoqXG4gICAqIEpvaW4gYWxsIGxpbmVzIG9mIHdvcmRzIGluc2lkZSB0aGUgSW5saW5lVGV4dEJ1aWxkZXIgaW50byBhIGNvbXBsZXRlIHN0cmluZy5cbiAgICpcbiAgICogQHJldHVybnMgeyBzdHJpbmcgfVxuICAgKi9cbiAgdG9TdHJpbmcgKCkge1xuICAgIHJldHVybiBbLi4udGhpcy5saW5lcywgdGhpcy5uZXh0TGluZVdvcmRzXVxuICAgICAgLm1hcCh3b3JkcyA9PiB3b3Jkcy5qb2luKCcgJykpXG4gICAgICAuam9pbignXFxuJyk7XG4gIH1cblxuICAvKipcbiAgICogU3BsaXQgYSBsb25nIHdvcmQgdXAgdG8gZml0IHdpdGhpbiB0aGUgd29yZCB3cmFwIGxpbWl0LlxuICAgKiBVc2UgZWl0aGVyIGEgY2hhcmFjdGVyIHRvIHNwbGl0IGxvb2tpbmcgYmFjayBmcm9tIHRoZSB3b3JkIHdyYXAgbGltaXQsXG4gICAqIG9yIHRydW5jYXRlIHRvIHRoZSB3b3JkIHdyYXAgbGltaXQuXG4gICAqXG4gICAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gICB3b3JkIElucHV0IHdvcmQuXG4gICAqIEByZXR1cm5zIHsgc3RyaW5nW10gfSAgICAgIFBhcnRzIG9mIHRoZSB3b3JkLlxuICAgKi9cbiAgc3BsaXRMb25nV29yZCAod29yZCkge1xuICAgIGNvbnN0IHBhcnRzID0gW107XG4gICAgbGV0IGlkeCA9IDA7XG4gICAgd2hpbGUgKHdvcmQubGVuZ3RoID4gdGhpcy5tYXhMaW5lTGVuZ3RoKSB7XG5cbiAgICAgIGNvbnN0IGZpcnN0TGluZSA9IHdvcmQuc3Vic3RyaW5nKDAsIHRoaXMubWF4TGluZUxlbmd0aCk7XG4gICAgICBjb25zdCByZW1haW5pbmdDaGFycyA9IHdvcmQuc3Vic3RyaW5nKHRoaXMubWF4TGluZUxlbmd0aCk7XG5cbiAgICAgIGNvbnN0IHNwbGl0SW5kZXggPSBmaXJzdExpbmUubGFzdEluZGV4T2YodGhpcy53cmFwQ2hhcmFjdGVyc1tpZHhdKTtcblxuICAgICAgaWYgKHNwbGl0SW5kZXggPiAtMSkgeyAvLyBGb3VuZCBhIGNoYXJhY3RlciB0byBzcGxpdCBvblxuXG4gICAgICAgIHdvcmQgPSBmaXJzdExpbmUuc3Vic3RyaW5nKHNwbGl0SW5kZXggKyAxKSArIHJlbWFpbmluZ0NoYXJzO1xuICAgICAgICBwYXJ0cy5wdXNoKGZpcnN0TGluZS5zdWJzdHJpbmcoMCwgc3BsaXRJbmRleCArIDEpKTtcblxuICAgICAgfSBlbHNlIHsgLy8gTm90IGZvdW5kIGEgY2hhcmFjdGVyIHRvIHNwbGl0IG9uXG5cbiAgICAgICAgaWR4Kys7XG4gICAgICAgIGlmIChpZHggPCB0aGlzLndyYXBDaGFyYWN0ZXJzLmxlbmd0aCkgeyAvLyBUaGVyZSBpcyBuZXh0IGNoYXJhY3RlciB0byB0cnlcblxuICAgICAgICAgIHdvcmQgPSBmaXJzdExpbmUgKyByZW1haW5pbmdDaGFycztcblxuICAgICAgICB9IGVsc2UgeyAvLyBObyBtb3JlIGNoYXJhY3RlcnMgdG8gdHJ5XG5cbiAgICAgICAgICBpZiAodGhpcy5mb3JjZVdyYXBPbkxpbWl0KSB7XG4gICAgICAgICAgICBwYXJ0cy5wdXNoKGZpcnN0TGluZSk7XG4gICAgICAgICAgICB3b3JkID0gcmVtYWluaW5nQ2hhcnM7XG4gICAgICAgICAgICBpZiAod29yZC5sZW5ndGggPiB0aGlzLm1heExpbmVMZW5ndGgpIHtcbiAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHdvcmQgPSBmaXJzdExpbmUgKyByZW1haW5pbmdDaGFycztcbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgfVxuXG4gICAgICB9XG5cbiAgICB9XG4gICAgcGFydHMucHVzaCh3b3JkKTsgLy8gQWRkIHJlbWFpbmluZyBwYXJ0IHRvIGFycmF5XG4gICAgcmV0dXJuIHBhcnRzO1xuICB9XG59XG5cbi8qIGVzbGludC1kaXNhYmxlIG1heC1jbGFzc2VzLXBlci1maWxlICovXG5cblxuY2xhc3MgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG5leHQgPSBudWxsKSB7IHRoaXMubmV4dCA9IG5leHQ7IH1cblxuICBnZXRSb290ICgpIHsgcmV0dXJuICh0aGlzLm5leHQpID8gdGhpcy5uZXh0IDogdGhpczsgfVxufVxuXG5jbGFzcyBCbG9ja1N0YWNrSXRlbSBleHRlbmRzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChvcHRpb25zLCBuZXh0ID0gbnVsbCwgbGVhZGluZ0xpbmVCcmVha3MgPSAxLCBtYXhMaW5lTGVuZ3RoID0gdW5kZWZpbmVkKSB7XG4gICAgc3VwZXIobmV4dCk7XG4gICAgdGhpcy5sZWFkaW5nTGluZUJyZWFrcyA9IGxlYWRpbmdMaW5lQnJlYWtzO1xuICAgIHRoaXMuaW5saW5lVGV4dEJ1aWxkZXIgPSBuZXcgSW5saW5lVGV4dEJ1aWxkZXIob3B0aW9ucywgbWF4TGluZUxlbmd0aCk7XG4gICAgdGhpcy5yYXdUZXh0ID0gJyc7XG4gICAgdGhpcy5zdGFzaGVkTGluZUJyZWFrcyA9IDA7XG4gICAgdGhpcy5pc1ByZSA9IG5leHQgJiYgbmV4dC5pc1ByZTtcbiAgICB0aGlzLmlzTm9XcmFwID0gbmV4dCAmJiBuZXh0LmlzTm9XcmFwO1xuICB9XG59XG5cbmNsYXNzIExpc3RTdGFja0l0ZW0gZXh0ZW5kcyBCbG9ja1N0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChcbiAgICBvcHRpb25zLFxuICAgIG5leHQgPSBudWxsLFxuICAgIHtcbiAgICAgIGludGVyUm93TGluZUJyZWFrcyA9IDEsXG4gICAgICBsZWFkaW5nTGluZUJyZWFrcyA9IDIsXG4gICAgICBtYXhMaW5lTGVuZ3RoID0gdW5kZWZpbmVkLFxuICAgICAgbWF4UHJlZml4TGVuZ3RoID0gMCxcbiAgICAgIHByZWZpeEFsaWduID0gJ2xlZnQnLFxuICAgIH0gPSB7fVxuICApIHtcbiAgICBzdXBlcihvcHRpb25zLCBuZXh0LCBsZWFkaW5nTGluZUJyZWFrcywgbWF4TGluZUxlbmd0aCk7XG4gICAgdGhpcy5tYXhQcmVmaXhMZW5ndGggPSBtYXhQcmVmaXhMZW5ndGg7XG4gICAgdGhpcy5wcmVmaXhBbGlnbiA9IHByZWZpeEFsaWduO1xuICAgIHRoaXMuaW50ZXJSb3dMaW5lQnJlYWtzID0gaW50ZXJSb3dMaW5lQnJlYWtzO1xuICB9XG59XG5cbmNsYXNzIExpc3RJdGVtU3RhY2tJdGVtIGV4dGVuZHMgQmxvY2tTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAoXG4gICAgb3B0aW9ucyxcbiAgICBuZXh0ID0gbnVsbCxcbiAgICB7XG4gICAgICBsZWFkaW5nTGluZUJyZWFrcyA9IDEsXG4gICAgICBtYXhMaW5lTGVuZ3RoID0gdW5kZWZpbmVkLFxuICAgICAgcHJlZml4ID0gJycsXG4gICAgfSA9IHt9XG4gICkge1xuICAgIHN1cGVyKG9wdGlvbnMsIG5leHQsIGxlYWRpbmdMaW5lQnJlYWtzLCBtYXhMaW5lTGVuZ3RoKTtcbiAgICB0aGlzLnByZWZpeCA9IHByZWZpeDtcbiAgfVxufVxuXG5jbGFzcyBUYWJsZVN0YWNrSXRlbSBleHRlbmRzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChuZXh0ID0gbnVsbCkge1xuICAgIHN1cGVyKG5leHQpO1xuICAgIHRoaXMucm93cyA9IFtdO1xuICAgIHRoaXMuaXNQcmUgPSBuZXh0ICYmIG5leHQuaXNQcmU7XG4gICAgdGhpcy5pc05vV3JhcCA9IG5leHQgJiYgbmV4dC5pc05vV3JhcDtcbiAgfVxufVxuXG5jbGFzcyBUYWJsZVJvd1N0YWNrSXRlbSBleHRlbmRzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChuZXh0ID0gbnVsbCkge1xuICAgIHN1cGVyKG5leHQpO1xuICAgIHRoaXMuY2VsbHMgPSBbXTtcbiAgICB0aGlzLmlzUHJlID0gbmV4dCAmJiBuZXh0LmlzUHJlO1xuICAgIHRoaXMuaXNOb1dyYXAgPSBuZXh0ICYmIG5leHQuaXNOb1dyYXA7XG4gIH1cbn1cblxuY2xhc3MgVGFibGVDZWxsU3RhY2tJdGVtIGV4dGVuZHMgU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKG9wdGlvbnMsIG5leHQgPSBudWxsLCBtYXhDb2x1bW5XaWR0aCA9IHVuZGVmaW5lZCkge1xuICAgIHN1cGVyKG5leHQpO1xuICAgIHRoaXMuaW5saW5lVGV4dEJ1aWxkZXIgPSBuZXcgSW5saW5lVGV4dEJ1aWxkZXIob3B0aW9ucywgbWF4Q29sdW1uV2lkdGgpO1xuICAgIHRoaXMucmF3VGV4dCA9ICcnO1xuICAgIHRoaXMuc3Rhc2hlZExpbmVCcmVha3MgPSAwO1xuICAgIHRoaXMuaXNQcmUgPSBuZXh0ICYmIG5leHQuaXNQcmU7XG4gICAgdGhpcy5pc05vV3JhcCA9IG5leHQgJiYgbmV4dC5pc05vV3JhcDtcbiAgfVxufVxuXG5jbGFzcyBUcmFuc2Zvcm1lclN0YWNrSXRlbSBleHRlbmRzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChuZXh0ID0gbnVsbCwgdHJhbnNmb3JtKSB7XG4gICAgc3VwZXIobmV4dCk7XG4gICAgdGhpcy50cmFuc2Zvcm0gPSB0cmFuc2Zvcm07XG4gIH1cbn1cblxuZnVuY3Rpb24gY2hhcmFjdGVyc1RvQ29kZXMgKHN0cikge1xuICByZXR1cm4gWy4uLnN0cl1cbiAgICAubWFwKGMgPT4gJ1xcXFx1JyArIGMuY2hhckNvZGVBdCgwKS50b1N0cmluZygxNikucGFkU3RhcnQoNCwgJzAnKSlcbiAgICAuam9pbignJyk7XG59XG5cbi8qKlxuICogSGVscHMgdG8gaGFuZGxlIEhUTUwgd2hpdGVzcGFjZXMuXG4gKlxuICogQGNsYXNzIFdoaXRlc3BhY2VQcm9jZXNzb3JcbiAqL1xuY2xhc3MgV2hpdGVzcGFjZVByb2Nlc3NvciB7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgV2hpdGVzcGFjZVByb2Nlc3Nvci5cbiAgICpcbiAgICogQHBhcmFtIHsgT3B0aW9ucyB9IG9wdGlvbnMgICAgSHRtbFRvVGV4dCBvcHRpb25zLlxuICAgKiBAbWVtYmVyb2YgV2hpdGVzcGFjZVByb2Nlc3NvclxuICAgKi9cbiAgY29uc3RydWN0b3IgKG9wdGlvbnMpIHtcbiAgICB0aGlzLndoaXRlc3BhY2VDaGFycyA9IChvcHRpb25zLnByZXNlcnZlTmV3bGluZXMpXG4gICAgICA/IG9wdGlvbnMud2hpdGVzcGFjZUNoYXJhY3RlcnMucmVwbGFjZSgvXFxuL2csICcnKVxuICAgICAgOiBvcHRpb25zLndoaXRlc3BhY2VDaGFyYWN0ZXJzO1xuICAgIGNvbnN0IHdoaXRlc3BhY2VDb2RlcyA9IGNoYXJhY3RlcnNUb0NvZGVzKHRoaXMud2hpdGVzcGFjZUNoYXJzKTtcbiAgICB0aGlzLmxlYWRpbmdXaGl0ZXNwYWNlUmUgPSBuZXcgUmVnRXhwKGBeWyR7d2hpdGVzcGFjZUNvZGVzfV1gKTtcbiAgICB0aGlzLnRyYWlsaW5nV2hpdGVzcGFjZVJlID0gbmV3IFJlZ0V4cChgWyR7d2hpdGVzcGFjZUNvZGVzfV0kYCk7XG4gICAgdGhpcy5hbGxXaGl0ZXNwYWNlT3JFbXB0eVJlID0gbmV3IFJlZ0V4cChgXlske3doaXRlc3BhY2VDb2Rlc31dKiRgKTtcbiAgICB0aGlzLm5ld2xpbmVPck5vbldoaXRlc3BhY2VSZSA9IG5ldyBSZWdFeHAoYChcXFxcbnxbXlxcXFxuJHt3aGl0ZXNwYWNlQ29kZXN9XSlgLCAnZycpO1xuICAgIHRoaXMubmV3bGluZU9yTm9uTmV3bGluZVN0cmluZ1JlID0gbmV3IFJlZ0V4cChgKFxcXFxufFteXFxcXG5dKylgLCAnZycpO1xuXG4gICAgaWYgKG9wdGlvbnMucHJlc2VydmVOZXdsaW5lcykge1xuXG4gICAgICBjb25zdCB3b3JkT3JOZXdsaW5lUmUgPSBuZXcgUmVnRXhwKGBcXFxcbnxbXlxcXFxuJHt3aGl0ZXNwYWNlQ29kZXN9XStgLCAnZ20nKTtcblxuICAgICAgLyoqXG4gICAgICAgKiBTaHJpbmsgd2hpdGVzcGFjZXMgYW5kIHdyYXAgdGV4dCwgYWRkIHRvIHRoZSBidWlsZGVyLlxuICAgICAgICpcbiAgICAgICAqIEBwYXJhbSB7IHN0cmluZyB9ICAgICAgICAgICAgICAgICAgdGV4dCAgICAgICAgICAgICAgSW5wdXQgdGV4dC5cbiAgICAgICAqIEBwYXJhbSB7IElubGluZVRleHRCdWlsZGVyIH0gICAgICAgaW5saW5lVGV4dEJ1aWxkZXIgQSBidWlsZGVyIHRvIHJlY2VpdmUgcHJvY2Vzc2VkIHRleHQuXG4gICAgICAgKiBAcGFyYW0geyAoc3RyOiBzdHJpbmcpID0+IHN0cmluZyB9IFsgdHJhbnNmb3JtIF0gICAgIEEgdHJhbnNmb3JtIHRvIGJlIGFwcGxpZWQgdG8gd29yZHMuXG4gICAgICAgKiBAcGFyYW0geyBib29sZWFuIH0gICAgICAgICAgICAgICAgIFtub1dyYXBdIERvbid0IHdyYXAgdGV4dCBldmVuIGlmIHRoZSBsaW5lIGlzIHRvbyBsb25nLlxuICAgICAgICovXG4gICAgICB0aGlzLnNocmlua1dyYXBBZGQgPSBmdW5jdGlvbiAodGV4dCwgaW5saW5lVGV4dEJ1aWxkZXIsIHRyYW5zZm9ybSA9IChzdHIgPT4gc3RyKSwgbm9XcmFwID0gZmFsc2UpIHtcbiAgICAgICAgaWYgKCF0ZXh0KSB7IHJldHVybjsgfVxuICAgICAgICBjb25zdCBwcmV2aW91c2x5U3Rhc2hlZFNwYWNlID0gaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlO1xuICAgICAgICBsZXQgYW55TWF0Y2ggPSBmYWxzZTtcbiAgICAgICAgbGV0IG0gPSB3b3JkT3JOZXdsaW5lUmUuZXhlYyh0ZXh0KTtcbiAgICAgICAgaWYgKG0pIHtcbiAgICAgICAgICBhbnlNYXRjaCA9IHRydWU7XG4gICAgICAgICAgaWYgKG1bMF0gPT09ICdcXG4nKSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUoKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgfHwgdGhpcy50ZXN0TGVhZGluZ1doaXRlc3BhY2UodGV4dCkpIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuY29uY2F0V29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHdoaWxlICgobSA9IHdvcmRPck5ld2xpbmVSZS5leGVjKHRleHQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKG1bMF0gPT09ICdcXG4nKSB7XG4gICAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSgpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2UgPSAocHJldmlvdXNseVN0YXNoZWRTcGFjZSAmJiAhYW55TWF0Y2gpIHx8ICh0aGlzLnRlc3RUcmFpbGluZ1doaXRlc3BhY2UodGV4dCkpO1xuICAgICAgICAvLyBObyBuZWVkIHRvIHN0YXNoIGEgc3BhY2UgaW4gY2FzZSBsYXN0IGFkZGVkIGl0ZW0gd2FzIGEgbmV3IGxpbmUsXG4gICAgICAgIC8vIGJ1dCB0aGF0IHdvbid0IGFmZmVjdCBhbnl0aGluZyBsYXRlciBhbnl3YXkuXG4gICAgICB9O1xuXG4gICAgfSBlbHNlIHtcblxuICAgICAgY29uc3Qgd29yZFJlID0gbmV3IFJlZ0V4cChgW14ke3doaXRlc3BhY2VDb2Rlc31dK2AsICdnJyk7XG5cbiAgICAgIHRoaXMuc2hyaW5rV3JhcEFkZCA9IGZ1bmN0aW9uICh0ZXh0LCBpbmxpbmVUZXh0QnVpbGRlciwgdHJhbnNmb3JtID0gKHN0ciA9PiBzdHIpLCBub1dyYXAgPSBmYWxzZSkge1xuICAgICAgICBpZiAoIXRleHQpIHsgcmV0dXJuOyB9XG4gICAgICAgIGNvbnN0IHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgPSBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2U7XG4gICAgICAgIGxldCBhbnlNYXRjaCA9IGZhbHNlO1xuICAgICAgICBsZXQgbSA9IHdvcmRSZS5leGVjKHRleHQpO1xuICAgICAgICBpZiAobSkge1xuICAgICAgICAgIGFueU1hdGNoID0gdHJ1ZTtcbiAgICAgICAgICBpZiAocHJldmlvdXNseVN0YXNoZWRTcGFjZSB8fCB0aGlzLnRlc3RMZWFkaW5nV2hpdGVzcGFjZSh0ZXh0KSkge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5jb25jYXRXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgd2hpbGUgKChtID0gd29yZFJlLmV4ZWModGV4dCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZSA9IChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlICYmICFhbnlNYXRjaCkgfHwgdGhpcy50ZXN0VHJhaWxpbmdXaGl0ZXNwYWNlKHRleHQpO1xuICAgICAgfTtcblxuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgdGV4dCB3aXRoIG9ubHkgbWluaW1hbCBwcm9jZXNzaW5nLlxuICAgKiBFdmVyeXRoaW5nIGJldHdlZW4gbmV3bGluZXMgY29uc2lkZXJlZCBhIHNpbmdsZSB3b3JkLlxuICAgKiBObyB3aGl0ZXNwYWNlIGlzIHRyaW1tZWQuXG4gICAqIE5vdCBhZmZlY3RlZCBieSBwcmVzZXJ2ZU5ld2xpbmVzIG9wdGlvbiAtIGBcXG5gIGFsd2F5cyBzdGFydHMgYSBuZXcgbGluZS5cbiAgICpcbiAgICogYG5vV3JhcGAgYXJndW1lbnQgaXMgYHRydWVgIGJ5IGRlZmF1bHQgLSB0aGlzIHdvbid0IHN0YXJ0IGEgbmV3IGxpbmVcbiAgICogZXZlbiBpZiB0aGVyZSBpcyBub3QgZW5vdWdoIHNwYWNlIGxlZnQgaW4gdGhlIGN1cnJlbnQgbGluZS5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gICAgICAgICAgICB0ZXh0ICAgICAgICAgICAgICBJbnB1dCB0ZXh0LlxuICAgKiBAcGFyYW0geyBJbmxpbmVUZXh0QnVpbGRlciB9IGlubGluZVRleHRCdWlsZGVyIEEgYnVpbGRlciB0byByZWNlaXZlIHByb2Nlc3NlZCB0ZXh0LlxuICAgKiBAcGFyYW0geyBib29sZWFuIH0gICAgICAgICAgIFtub1dyYXBdIERvbid0IHdyYXAgdGV4dCBldmVuIGlmIHRoZSBsaW5lIGlzIHRvbyBsb25nLlxuICAgKi9cbiAgYWRkTGl0ZXJhbCAodGV4dCwgaW5saW5lVGV4dEJ1aWxkZXIsIG5vV3JhcCA9IHRydWUpIHtcbiAgICBpZiAoIXRleHQpIHsgcmV0dXJuOyB9XG4gICAgY29uc3QgcHJldmlvdXNseVN0YXNoZWRTcGFjZSA9IGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZTtcbiAgICBsZXQgYW55TWF0Y2ggPSBmYWxzZTtcbiAgICBsZXQgbSA9IHRoaXMubmV3bGluZU9yTm9uTmV3bGluZVN0cmluZ1JlLmV4ZWModGV4dCk7XG4gICAgaWYgKG0pIHtcbiAgICAgIGFueU1hdGNoID0gdHJ1ZTtcbiAgICAgIGlmIChtWzBdID09PSAnXFxuJykge1xuICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUoKTtcbiAgICAgIH0gZWxzZSBpZiAocHJldmlvdXNseVN0YXNoZWRTcGFjZSkge1xuICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZChtWzBdLCBub1dyYXApO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuY29uY2F0V29yZChtWzBdLCBub1dyYXApO1xuICAgICAgfVxuICAgICAgd2hpbGUgKChtID0gdGhpcy5uZXdsaW5lT3JOb25OZXdsaW5lU3RyaW5nUmUuZXhlYyh0ZXh0KSkgIT09IG51bGwpIHtcbiAgICAgICAgaWYgKG1bMF0gPT09ICdcXG4nKSB7XG4gICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQobVswXSwgbm9XcmFwKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2UgPSAocHJldmlvdXNseVN0YXNoZWRTcGFjZSAmJiAhYW55TWF0Y2gpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRlc3Qgd2hldGhlciB0aGUgZ2l2ZW4gdGV4dCBzdGFydHMgd2l0aCBIVE1MIHdoaXRlc3BhY2UgY2hhcmFjdGVyLlxuICAgKlxuICAgKiBAcGFyYW0gICB7IHN0cmluZyB9ICB0ZXh0ICBUaGUgc3RyaW5nIHRvIHRlc3QuXG4gICAqIEByZXR1cm5zIHsgYm9vbGVhbiB9XG4gICAqL1xuICB0ZXN0TGVhZGluZ1doaXRlc3BhY2UgKHRleHQpIHtcbiAgICByZXR1cm4gdGhpcy5sZWFkaW5nV2hpdGVzcGFjZVJlLnRlc3QodGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogVGVzdCB3aGV0aGVyIHRoZSBnaXZlbiB0ZXh0IGVuZHMgd2l0aCBIVE1MIHdoaXRlc3BhY2UgY2hhcmFjdGVyLlxuICAgKlxuICAgKiBAcGFyYW0gICB7IHN0cmluZyB9ICB0ZXh0ICBUaGUgc3RyaW5nIHRvIHRlc3QuXG4gICAqIEByZXR1cm5zIHsgYm9vbGVhbiB9XG4gICAqL1xuICB0ZXN0VHJhaWxpbmdXaGl0ZXNwYWNlICh0ZXh0KSB7XG4gICAgcmV0dXJuIHRoaXMudHJhaWxpbmdXaGl0ZXNwYWNlUmUudGVzdCh0ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0IHdoZXRoZXIgdGhlIGdpdmVuIHRleHQgY29udGFpbnMgYW55IG5vbi13aGl0ZXNwYWNlIGNoYXJhY3RlcnMuXG4gICAqXG4gICAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gIHRleHQgIFRoZSBzdHJpbmcgdG8gdGVzdC5cbiAgICogQHJldHVybnMgeyBib29sZWFuIH1cbiAgICovXG4gIHRlc3RDb250YWluc1dvcmRzICh0ZXh0KSB7XG4gICAgcmV0dXJuICF0aGlzLmFsbFdoaXRlc3BhY2VPckVtcHR5UmUudGVzdCh0ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIG51bWJlciBvZiBuZXdsaW5lcyBpZiB0aGVyZSBhcmUgbm8gd29yZHMuXG4gICAqXG4gICAqIElmIGFueSB3b3JkIGlzIGZvdW5kIHRoZW4gcmV0dXJuIHplcm8gcmVnYXJkbGVzcyBvZiB0aGUgYWN0dWFsIG51bWJlciBvZiBuZXdsaW5lcy5cbiAgICpcbiAgICogQHBhcmFtICAgeyBzdHJpbmcgfSAgdGV4dCAgSW5wdXQgc3RyaW5nLlxuICAgKiBAcmV0dXJucyB7IG51bWJlciB9XG4gICAqL1xuICBjb3VudE5ld2xpbmVzTm9Xb3JkcyAodGV4dCkge1xuICAgIHRoaXMubmV3bGluZU9yTm9uV2hpdGVzcGFjZVJlLmxhc3RJbmRleCA9IDA7XG4gICAgbGV0IGNvdW50ZXIgPSAwO1xuICAgIGxldCBtYXRjaDtcbiAgICB3aGlsZSAoKG1hdGNoID0gdGhpcy5uZXdsaW5lT3JOb25XaGl0ZXNwYWNlUmUuZXhlYyh0ZXh0KSkgIT09IG51bGwpIHtcbiAgICAgIGlmIChtYXRjaFswXSA9PT0gJ1xcbicpIHtcbiAgICAgICAgY291bnRlcisrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBjb3VudGVyO1xuICB9XG5cbn1cblxuLyoqXG4gKiBIZWxwcyB0byBidWlsZCB0ZXh0IGZyb20gaW5saW5lIGFuZCBibG9jayBlbGVtZW50cy5cbiAqXG4gKiBAY2xhc3MgQmxvY2tUZXh0QnVpbGRlclxuICovXG5jbGFzcyBCbG9ja1RleHRCdWlsZGVyIHtcblxuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBCbG9ja1RleHRCdWlsZGVyLlxuICAgKlxuICAgKiBAcGFyYW0geyBPcHRpb25zIH0gb3B0aW9ucyBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7IGltcG9ydCgnc2VsZGVyZWUnKS5QaWNrZXI8RG9tTm9kZSwgVGFnRGVmaW5pdGlvbj4gfSBwaWNrZXIgU2VsZWN0b3JzIGRlY2lzaW9uIHRyZWUgcGlja2VyLlxuICAgKiBAcGFyYW0geyBhbnl9IFttZXRhZGF0YV0gT3B0aW9uYWwgbWV0YWRhdGEgZm9yIEhUTUwgZG9jdW1lbnQsIGZvciB1c2UgaW4gZm9ybWF0dGVycy5cbiAgICovXG4gIGNvbnN0cnVjdG9yIChvcHRpb25zLCBwaWNrZXIsIG1ldGFkYXRhID0gdW5kZWZpbmVkKSB7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9ucztcbiAgICB0aGlzLnBpY2tlciA9IHBpY2tlcjtcbiAgICB0aGlzLm1ldGFkYXRhID0gbWV0YWRhdGE7XG4gICAgdGhpcy53aGl0ZXNwYWNlUHJvY2Vzc29yID0gbmV3IFdoaXRlc3BhY2VQcm9jZXNzb3Iob3B0aW9ucyk7XG4gICAgLyoqIEB0eXBlIHsgU3RhY2tJdGVtIH0gKi9cbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgQmxvY2tTdGFja0l0ZW0ob3B0aW9ucyk7XG4gICAgLyoqIEB0eXBlIHsgVHJhbnNmb3JtZXJTdGFja0l0ZW0gfSAqL1xuICAgIHRoaXMuX3dvcmRUcmFuc2Zvcm1lciA9IHVuZGVmaW5lZDtcbiAgfVxuXG4gIC8qKlxuICAgKiBQdXQgYSB3b3JkLWJ5LXdvcmQgdHJhbnNmb3JtIGZ1bmN0aW9uIG9udG8gdGhlIHRyYW5zZm9ybWF0aW9ucyBzdGFjay5cbiAgICpcbiAgICogTWFpbmx5IHVzZWQgZm9yIHVwcGVyY2FzaW5nLiBDYW4gYmUgYnlwYXNzZWQgdG8gYWRkIHVuZm9ybWF0dGVkIHRleHQgc3VjaCBhcyBVUkxzLlxuICAgKlxuICAgKiBXb3JkIHRyYW5zZm9ybWF0aW9ucyBhcHBsaWVkIGJlZm9yZSB3cmFwcGluZy5cbiAgICpcbiAgICogQHBhcmFtIHsgKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcgfSB3b3JkVHJhbnNmb3JtIFdvcmQgdHJhbnNmb3JtYXRpb24gZnVuY3Rpb24uXG4gICAqL1xuICBwdXNoV29yZFRyYW5zZm9ybSAod29yZFRyYW5zZm9ybSkge1xuICAgIHRoaXMuX3dvcmRUcmFuc2Zvcm1lciA9IG5ldyBUcmFuc2Zvcm1lclN0YWNrSXRlbSh0aGlzLl93b3JkVHJhbnNmb3JtZXIsIHdvcmRUcmFuc2Zvcm0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFJlbW92ZSBhIGZ1bmN0aW9uIGZyb20gdGhlIHdvcmQgdHJhbnNmb3JtYXRpb25zIHN0YWNrLlxuICAgKlxuICAgKiBAcmV0dXJucyB7IChzdHI6IHN0cmluZykgPT4gc3RyaW5nIH0gQSBmdW5jdGlvbiB0aGF0IHdhcyByZW1vdmVkLlxuICAgKi9cbiAgcG9wV29yZFRyYW5zZm9ybSAoKSB7XG4gICAgaWYgKCF0aGlzLl93b3JkVHJhbnNmb3JtZXIpIHsgcmV0dXJuIHVuZGVmaW5lZDsgfVxuICAgIGNvbnN0IHRyYW5zZm9ybSA9IHRoaXMuX3dvcmRUcmFuc2Zvcm1lci50cmFuc2Zvcm07XG4gICAgdGhpcy5fd29yZFRyYW5zZm9ybWVyID0gdGhpcy5fd29yZFRyYW5zZm9ybWVyLm5leHQ7XG4gICAgcmV0dXJuIHRyYW5zZm9ybTtcbiAgfVxuXG4gIC8qKlxuICAgKiBJZ25vcmUgd29yZHdyYXAgb3B0aW9uIGluIGZvbGxvd3VwIGlubGluZSBhZGRpdGlvbnMgYW5kIGRpc2FibGUgYXV0b21hdGljIHdyYXBwaW5nLlxuICAgKi9cbiAgc3RhcnROb1dyYXAgKCkge1xuICAgIHRoaXMuX3N0YWNrSXRlbS5pc05vV3JhcCA9IHRydWU7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIGF1dG9tYXRpYyB3cmFwcGluZyB0byBiZWhhdmlvciBkZWZpbmVkIGJ5IG9wdGlvbnMuXG4gICAqL1xuICBzdG9wTm9XcmFwICgpIHtcbiAgICB0aGlzLl9zdGFja0l0ZW0uaXNOb1dyYXAgPSBmYWxzZTtcbiAgfVxuXG4gIC8qKiBAcmV0dXJucyB7IChzdHI6IHN0cmluZykgPT4gc3RyaW5nIH0gKi9cbiAgX2dldENvbWJpbmVkV29yZFRyYW5zZm9ybWVyICgpIHtcbiAgICBjb25zdCB3dCA9ICh0aGlzLl93b3JkVHJhbnNmb3JtZXIpXG4gICAgICA/ICgoc3RyKSA9PiBhcHBseVRyYW5zZm9ybWVyKHN0ciwgdGhpcy5fd29yZFRyYW5zZm9ybWVyKSlcbiAgICAgIDogdW5kZWZpbmVkO1xuICAgIGNvbnN0IGNlID0gdGhpcy5vcHRpb25zLmVuY29kZUNoYXJhY3RlcnM7XG4gICAgcmV0dXJuICh3dClcbiAgICAgID8gKChjZSkgPyAoc3RyKSA9PiBjZSh3dChzdHIpKSA6IHd0KVxuICAgICAgOiBjZTtcbiAgfVxuXG4gIF9wb3BTdGFja0l0ZW0gKCkge1xuICAgIGNvbnN0IGl0ZW0gPSB0aGlzLl9zdGFja0l0ZW07XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gaXRlbS5uZXh0O1xuICAgIHJldHVybiBpdGVtO1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIGxpbmUgYnJlYWsgaW50byBjdXJyZW50bHkgYnVpbHQgYmxvY2suXG4gICAqL1xuICBhZGRMaW5lQnJlYWsgKCkge1xuICAgIGlmICghKFxuICAgICAgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgICApKSB7IHJldHVybjsgfVxuICAgIGlmICh0aGlzLl9zdGFja0l0ZW0uaXNQcmUpIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5yYXdUZXh0ICs9ICdcXG4nO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKCk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFsbG93IHRvIGJyZWFrIGxpbmUgaW4gY2FzZSBkaXJlY3RseSBmb2xsb3dpbmcgdGV4dCB3aWxsIG5vdCBmaXQuXG4gICAqL1xuICBhZGRXb3JkQnJlYWtPcHBvcnR1bml0eSAoKSB7XG4gICAgaWYgKFxuICAgICAgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgICApIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci53b3JkQnJlYWtPcHBvcnR1bml0eSA9IHRydWU7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIG5vZGUgaW5saW5lIGludG8gdGhlIGN1cnJlbnRseSBidWlsdCBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gc3RyXG4gICAqIFRleHQgY29udGVudCBvZiBhIG5vZGUgdG8gYWRkLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0xXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgb3BlcmF0aW9uLlxuICAgKlxuICAgKiBAcGFyYW0geyBib29sZWFuIH0gW3BhcmFtMS5ub1dvcmRUcmFuc2Zvcm1dXG4gICAqIElnbm9yZSB3b3JkIHRyYW5zZm9ybWVycyBpZiB0aGVyZSBhcmUgYW55LlxuICAgKiBEb24ndCBlbmNvZGUgY2hhcmFjdGVycyBhcyB3ZWxsLlxuICAgKiAoVXNlIHRoaXMgZm9yIHRoaW5ncyBsaWtlIFVSTCBhZGRyZXNzZXMpLlxuICAgKi9cbiAgYWRkSW5saW5lIChzdHIsIHsgbm9Xb3JkVHJhbnNmb3JtID0gZmFsc2UgfSA9IHt9KSB7XG4gICAgaWYgKCEoXG4gICAgICB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICAgICkpIHsgcmV0dXJuOyB9XG5cbiAgICBpZiAodGhpcy5fc3RhY2tJdGVtLmlzUHJlKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0ucmF3VGV4dCArPSBzdHI7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKFxuICAgICAgc3RyLmxlbmd0aCA9PT0gMCB8fCAvLyBlbXB0eSBzdHJpbmdcbiAgICAgIChcbiAgICAgICAgdGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzICYmIC8vIHN0YXNoZWQgbGluZWJyZWFrcyBtYWtlIHdoaXRlc3BhY2UgaXJyZWxldmFudFxuICAgICAgICAhdGhpcy53aGl0ZXNwYWNlUHJvY2Vzc29yLnRlc3RDb250YWluc1dvcmRzKHN0cikgLy8gbm8gd29yZHMgdG8gYWRkXG4gICAgICApXG4gICAgKSB7IHJldHVybjsgfVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wcmVzZXJ2ZU5ld2xpbmVzKSB7XG4gICAgICBjb25zdCBuZXdsaW5lc051bWJlciA9IHRoaXMud2hpdGVzcGFjZVByb2Nlc3Nvci5jb3VudE5ld2xpbmVzTm9Xb3JkcyhzdHIpO1xuICAgICAgaWYgKG5ld2xpbmVzTnVtYmVyID4gMCkge1xuICAgICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKG5ld2xpbmVzTnVtYmVyKTtcbiAgICAgICAgLy8ga2VlcCBzdGFzaGVkTGluZUJyZWFrcyB1bmNoYW5nZWRcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmICh0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MpIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUodGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzKTtcbiAgICB9XG4gICAgdGhpcy53aGl0ZXNwYWNlUHJvY2Vzc29yLnNocmlua1dyYXBBZGQoXG4gICAgICBzdHIsXG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIsXG4gICAgICAobm9Xb3JkVHJhbnNmb3JtKSA/IHVuZGVmaW5lZCA6IHRoaXMuX2dldENvbWJpbmVkV29yZFRyYW5zZm9ybWVyKCksXG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaXNOb1dyYXBcbiAgICApO1xuICAgIHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyA9IDA7IC8vIGlubGluZSB0ZXh0IGRvZXNuJ3QgaW50cm9kdWNlIGxpbmUgYnJlYWtzXG4gIH1cblxuICAvKipcbiAgICogQWRkIGEgc3RyaW5nIGlubGluZSBpbnRvIHRoZSBjdXJyZW50bHkgYnVpbHQgYmxvY2suXG4gICAqXG4gICAqIFVzZSB0aGlzIGZvciBtYXJrdXAgZWxlbWVudHMgdGhhdCBkb24ndCBoYXZlIHRvIGFkaGVyZVxuICAgKiB0byB0ZXh0IGxheW91dCBydWxlcy5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gc3RyIFRleHQgdG8gYWRkLlxuICAgKi9cbiAgYWRkTGl0ZXJhbCAoc3RyKSB7XG4gICAgaWYgKCEoXG4gICAgICB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICAgICkpIHsgcmV0dXJuOyB9XG5cbiAgICBpZiAoc3RyLmxlbmd0aCA9PT0gMCkgeyByZXR1cm47IH1cblxuICAgIGlmICh0aGlzLl9zdGFja0l0ZW0uaXNQcmUpIHtcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5yYXdUZXh0ICs9IHN0cjtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyk7XG4gICAgfVxuICAgIHRoaXMud2hpdGVzcGFjZVByb2Nlc3Nvci5hZGRMaXRlcmFsKFxuICAgICAgc3RyLFxuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLFxuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlzTm9XcmFwXG4gICAgKTtcbiAgICB0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MgPSAwO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgbmV3IGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0wXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAubGVhZGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgYmxvY2sgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaXQgZnJvbSBhbnkgcHJlY2VkaW5nIGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSAgW3BhcmFtMC5yZXNlcnZlZExpbmVMZW5ndGhdXG4gICAqIFJlc2VydmUgdGhpcyBudW1iZXIgb2YgY2hhcmFjdGVycyBvbiBlYWNoIGxpbmUgZm9yIGJsb2NrIG1hcmt1cC5cbiAgICpcbiAgICogQHBhcmFtIHsgYm9vbGVhbiB9IFtwYXJhbTAuaXNQcmVdXG4gICAqIFNob3VsZCBIVE1MIHdoaXRlc3BhY2UgYmUgcHJlc2VydmVkIGluc2lkZSB0aGlzIGJsb2NrLlxuICAgKi9cbiAgb3BlbkJsb2NrICh7IGxlYWRpbmdMaW5lQnJlYWtzID0gMSwgcmVzZXJ2ZWRMaW5lTGVuZ3RoID0gMCwgaXNQcmUgPSBmYWxzZSB9ID0ge30pIHtcbiAgICBjb25zdCBtYXhMaW5lTGVuZ3RoID0gTWF0aC5tYXgoMjAsIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5tYXhMaW5lTGVuZ3RoIC0gcmVzZXJ2ZWRMaW5lTGVuZ3RoKTtcbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgQmxvY2tTdGFja0l0ZW0oXG4gICAgICB0aGlzLm9wdGlvbnMsXG4gICAgICB0aGlzLl9zdGFja0l0ZW0sXG4gICAgICBsZWFkaW5nTGluZUJyZWFrcyxcbiAgICAgIG1heExpbmVMZW5ndGhcbiAgICApO1xuICAgIGlmIChpc1ByZSkgeyB0aGlzLl9zdGFja0l0ZW0uaXNQcmUgPSB0cnVlOyB9XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IGJsb2NrLCBhZGQgaXQncyBjb250ZW50IHRvIHRoZSBwYXJlbnQgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTBdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC50cmFpbGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgYmxvY2sgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaXQgZnJvbSBhbnkgZm9sbG93aW5nIGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyAoc3RyOiBzdHJpbmcpID0+IHN0cmluZyB9IFtwYXJhbTAuYmxvY2tUcmFuc2Zvcm1dXG4gICAqIEEgZnVuY3Rpb24gdG8gdHJhbnNmb3JtIHRoZSBibG9jayB0ZXh0IGJlZm9yZSBhZGRpbmcgdG8gdGhlIHBhcmVudCBibG9jay5cbiAgICogVGhpcyBoYXBwZW5zIGFmdGVyIHdvcmQgd3JhcCBhbmQgc2hvdWxkIGJlIHVzZWQgaW4gY29tYmluYXRpb24gd2l0aCByZXNlcnZlZCBsaW5lIGxlbmd0aFxuICAgKiBpbiBvcmRlciB0byBrZWVwIGxpbmUgbGVuZ3RocyBjb3JyZWN0LlxuICAgKiBVc2VkIGZvciB3aG9sZSBibG9jayBtYXJrdXAuXG4gICAqL1xuICBjbG9zZUJsb2NrICh7IHRyYWlsaW5nTGluZUJyZWFrcyA9IDEsIGJsb2NrVHJhbnNmb3JtID0gdW5kZWZpbmVkIH0gPSB7fSkge1xuICAgIGNvbnN0IGJsb2NrID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgY29uc3QgYmxvY2tUZXh0ID0gKGJsb2NrVHJhbnNmb3JtKSA/IGJsb2NrVHJhbnNmb3JtKGdldFRleHQoYmxvY2spKSA6IGdldFRleHQoYmxvY2spO1xuICAgIGFkZFRleHQodGhpcy5fc3RhY2tJdGVtLCBibG9ja1RleHQsIGJsb2NrLmxlYWRpbmdMaW5lQnJlYWtzLCBNYXRoLm1heChibG9jay5zdGFzaGVkTGluZUJyZWFrcywgdHJhaWxpbmdMaW5lQnJlYWtzKSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSBuZXcgbGlzdC5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMF1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGxpc3QuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAubWF4UHJlZml4TGVuZ3RoXVxuICAgKiBMZW5ndGggb2YgdGhlIGxvbmdlc3QgbGlzdCBpdGVtIHByZWZpeC5cbiAgICogSWYgbm90IHN1cHBsaWVkIG9yIHRvbyBzbWFsbCB0aGVuIGxpc3QgaXRlbXMgd29uJ3QgYmUgYWxpZ25lZCBwcm9wZXJseS5cbiAgICpcbiAgICogQHBhcmFtIHsgJ2xlZnQnIHwgJ3JpZ2h0JyB9IFtwYXJhbTAucHJlZml4QWxpZ25dXG4gICAqIFNwZWNpZnkgaG93IHByZWZpeGVzIG9mIGRpZmZlcmVudCBsZW5ndGhzIGhhdmUgdG8gYmUgYWxpZ25lZFxuICAgKiB3aXRoaW4gYSBjb2x1bW4uXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAuaW50ZXJSb3dMaW5lQnJlYWtzXVxuICAgKiBNaW5pbXVtIG51bWJlciBvZiBsaW5lIGJyZWFrcyBiZXR3ZWVuIGxpc3QgaXRlbXMuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAubGVhZGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgbGlzdCBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpdCBmcm9tIGFueSBwcmVjZWRpbmcgYmxvY2suXG4gICAqL1xuICBvcGVuTGlzdCAoeyBtYXhQcmVmaXhMZW5ndGggPSAwLCBwcmVmaXhBbGlnbiA9ICdsZWZ0JywgaW50ZXJSb3dMaW5lQnJlYWtzID0gMSwgbGVhZGluZ0xpbmVCcmVha3MgPSAyIH0gPSB7fSkge1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBMaXN0U3RhY2tJdGVtKHRoaXMub3B0aW9ucywgdGhpcy5fc3RhY2tJdGVtLCB7XG4gICAgICBpbnRlclJvd0xpbmVCcmVha3M6IGludGVyUm93TGluZUJyZWFrcyxcbiAgICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBsZWFkaW5nTGluZUJyZWFrcyxcbiAgICAgIG1heExpbmVMZW5ndGg6IHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5tYXhMaW5lTGVuZ3RoLFxuICAgICAgbWF4UHJlZml4TGVuZ3RoOiBtYXhQcmVmaXhMZW5ndGgsXG4gICAgICBwcmVmaXhBbGlnbjogcHJlZml4QWxpZ25cbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIG5ldyBsaXN0IGl0ZW0uXG4gICAqXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBwYXJhbTBcbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGxpc3QgaXRlbS5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gW3BhcmFtMC5wcmVmaXhdXG4gICAqIFByZWZpeCBmb3IgdGhpcyBsaXN0IGl0ZW0gKGl0ZW0gbnVtYmVyLCBidWxsZXQgcG9pbnQsIGV0YykuXG4gICAqL1xuICBvcGVuTGlzdEl0ZW0gKHsgcHJlZml4ID0gJycgfSA9IHt9KSB7XG4gICAgaWYgKCEodGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdFN0YWNrSXRlbSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2FuXFwndCBhZGQgYSBsaXN0IGl0ZW0gdG8gc29tZXRoaW5nIHRoYXQgaXMgbm90IGEgbGlzdCEgQ2hlY2sgdGhlIGZvcm1hdHRlci4nKTtcbiAgICB9XG4gICAgY29uc3QgbGlzdCA9IHRoaXMuX3N0YWNrSXRlbTtcbiAgICBjb25zdCBwcmVmaXhMZW5ndGggPSBNYXRoLm1heChwcmVmaXgubGVuZ3RoLCBsaXN0Lm1heFByZWZpeExlbmd0aCk7XG4gICAgY29uc3QgbWF4TGluZUxlbmd0aCA9IE1hdGgubWF4KDIwLCBsaXN0LmlubGluZVRleHRCdWlsZGVyLm1heExpbmVMZW5ndGggLSBwcmVmaXhMZW5ndGgpO1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBMaXN0SXRlbVN0YWNrSXRlbSh0aGlzLm9wdGlvbnMsIGxpc3QsIHtcbiAgICAgIHByZWZpeDogcHJlZml4LFxuICAgICAgbWF4TGluZUxlbmd0aDogbWF4TGluZUxlbmd0aCxcbiAgICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBsaXN0LmludGVyUm93TGluZUJyZWFrc1xuICAgIH0pO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCBsaXN0IGl0ZW0sIGFkZCBpdCdzIGNvbnRlbnQgdG8gdGhlIHBhcmVudCBsaXN0LlxuICAgKi9cbiAgY2xvc2VMaXN0SXRlbSAoKSB7XG4gICAgY29uc3QgbGlzdEl0ZW0gPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICBjb25zdCBsaXN0ID0gbGlzdEl0ZW0ubmV4dDtcblxuICAgIGNvbnN0IHByZWZpeExlbmd0aCA9IE1hdGgubWF4KGxpc3RJdGVtLnByZWZpeC5sZW5ndGgsIGxpc3QubWF4UHJlZml4TGVuZ3RoKTtcbiAgICBjb25zdCBzcGFjaW5nID0gJ1xcbicgKyAnICcucmVwZWF0KHByZWZpeExlbmd0aCk7XG4gICAgY29uc3QgcHJlZml4ID0gKGxpc3QucHJlZml4QWxpZ24gPT09ICdyaWdodCcpXG4gICAgICA/IGxpc3RJdGVtLnByZWZpeC5wYWRTdGFydChwcmVmaXhMZW5ndGgpXG4gICAgICA6IGxpc3RJdGVtLnByZWZpeC5wYWRFbmQocHJlZml4TGVuZ3RoKTtcbiAgICBjb25zdCB0ZXh0ID0gcHJlZml4ICsgZ2V0VGV4dChsaXN0SXRlbSkucmVwbGFjZSgvXFxuL2csIHNwYWNpbmcpO1xuXG4gICAgYWRkVGV4dChcbiAgICAgIGxpc3QsXG4gICAgICB0ZXh0LFxuICAgICAgbGlzdEl0ZW0ubGVhZGluZ0xpbmVCcmVha3MsXG4gICAgICBNYXRoLm1heChsaXN0SXRlbS5zdGFzaGVkTGluZUJyZWFrcywgbGlzdC5pbnRlclJvd0xpbmVCcmVha3MpXG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgbGlzdCwgYWRkIGl0J3MgY29udGVudCB0byB0aGUgcGFyZW50IGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBwYXJhbTBcbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGxpc3QuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAudHJhaWxpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIGxpc3Qgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaXQgZnJvbSBhbnkgZm9sbG93aW5nIGJsb2NrLlxuICAgKi9cbiAgY2xvc2VMaXN0ICh7IHRyYWlsaW5nTGluZUJyZWFrcyA9IDIgfSA9IHt9KSB7XG4gICAgY29uc3QgbGlzdCA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIGNvbnN0IHRleHQgPSBnZXRUZXh0KGxpc3QpO1xuICAgIGlmICh0ZXh0KSB7XG4gICAgICBhZGRUZXh0KHRoaXMuX3N0YWNrSXRlbSwgdGV4dCwgbGlzdC5sZWFkaW5nTGluZUJyZWFrcywgdHJhaWxpbmdMaW5lQnJlYWtzKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSB0YWJsZS5cbiAgICovXG4gIG9wZW5UYWJsZSAoKSB7XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IFRhYmxlU3RhY2tJdGVtKHRoaXMuX3N0YWNrSXRlbSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSB0YWJsZSByb3cuXG4gICAqL1xuICBvcGVuVGFibGVSb3cgKCkge1xuICAgIGlmICghKHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlU3RhY2tJdGVtKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGFkZCBhIHRhYmxlIHJvdyB0byBzb21ldGhpbmcgdGhhdCBpcyBub3QgYSB0YWJsZSEgQ2hlY2sgdGhlIGZvcm1hdHRlci4nKTtcbiAgICB9XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IFRhYmxlUm93U3RhY2tJdGVtKHRoaXMuX3N0YWNrSXRlbSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSB0YWJsZSBjZWxsLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0wXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgY2VsbC5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5tYXhDb2x1bW5XaWR0aF1cbiAgICogV3JhcCBjZWxsIGNvbnRlbnQgdG8gdGhpcyB3aWR0aC4gRmFsbCBiYWNrIHRvIGdsb2JhbCB3b3Jkd3JhcCB2YWx1ZSBpZiB1bmRlZmluZWQuXG4gICAqL1xuICBvcGVuVGFibGVDZWxsICh7IG1heENvbHVtbldpZHRoID0gdW5kZWZpbmVkIH0gPSB7fSkge1xuICAgIGlmICghKHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlUm93U3RhY2tJdGVtKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdDYW5cXCd0IGFkZCBhIHRhYmxlIGNlbGwgdG8gc29tZXRoaW5nIHRoYXQgaXMgbm90IGEgdGFibGUgcm93ISBDaGVjayB0aGUgZm9ybWF0dGVyLicpO1xuICAgIH1cbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgVGFibGVDZWxsU3RhY2tJdGVtKHRoaXMub3B0aW9ucywgdGhpcy5fc3RhY2tJdGVtLCBtYXhDb2x1bW5XaWR0aCk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IHRhYmxlIGNlbGwgYW5kIGFkZCBpdCB0byBwYXJlbnQgdGFibGUgcm93J3MgY2VsbHMuXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTBdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBjZWxsLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLmNvbHNwYW5dIEhvdyBtYW55IGNvbHVtbnMgdGhpcyBjZWxsIHNob3VsZCBvY2N1cHkuXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAucm93c3Bhbl0gSG93IG1hbnkgcm93cyB0aGlzIGNlbGwgc2hvdWxkIG9jY3VweS5cbiAgICovXG4gIGNsb3NlVGFibGVDZWxsICh7IGNvbHNwYW4gPSAxLCByb3dzcGFuID0gMSB9ID0ge30pIHtcbiAgICBjb25zdCBjZWxsID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgY29uc3QgdGV4dCA9IHRyaW1DaGFyYWN0ZXIoZ2V0VGV4dChjZWxsKSwgJ1xcbicpO1xuICAgIGNlbGwubmV4dC5jZWxscy5wdXNoKHsgY29sc3BhbjogY29sc3Bhbiwgcm93c3Bhbjogcm93c3BhbiwgdGV4dDogdGV4dCB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgdGFibGUgcm93IGFuZCBhZGQgaXQgdG8gcGFyZW50IHRhYmxlJ3Mgcm93cy5cbiAgICovXG4gIGNsb3NlVGFibGVSb3cgKCkge1xuICAgIGNvbnN0IHJvdyA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIHJvdy5uZXh0LnJvd3MucHVzaChyb3cuY2VsbHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCB0YWJsZSBhbmQgYWRkIHRoZSByZW5kZXJlZCB0ZXh0IHRvIHRoZSBwYXJlbnQgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IHBhcmFtMFxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgdGFibGUuXG4gICAqXG4gICAqIEBwYXJhbSB7IFRhYmxlUHJpbnRlciB9IHBhcmFtMC50YWJsZVRvU3RyaW5nXG4gICAqIEEgZnVuY3Rpb24gdG8gY29udmVydCBhIHRhYmxlIG9mIHN0cmluZ2lmaWVkIGNlbGxzIGludG8gYSBjb21wbGV0ZSB0YWJsZS5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5sZWFkaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyB0YWJsZSBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpZiBmcm9tIGFueSBwcmVjZWRpbmcgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAudHJhaWxpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIHRhYmxlIHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGl0IGZyb20gYW55IGZvbGxvd2luZyBibG9jay5cbiAgICovXG4gIGNsb3NlVGFibGUgKHsgdGFibGVUb1N0cmluZywgbGVhZGluZ0xpbmVCcmVha3MgPSAyLCB0cmFpbGluZ0xpbmVCcmVha3MgPSAyIH0pIHtcbiAgICBjb25zdCB0YWJsZSA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIGNvbnN0IG91dHB1dCA9IHRhYmxlVG9TdHJpbmcodGFibGUucm93cyk7XG4gICAgaWYgKG91dHB1dCkge1xuICAgICAgYWRkVGV4dCh0aGlzLl9zdGFja0l0ZW0sIG91dHB1dCwgbGVhZGluZ0xpbmVCcmVha3MsIHRyYWlsaW5nTGluZUJyZWFrcyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiB0aGUgcmVuZGVyZWQgdGV4dCBjb250ZW50IG9mIHRoaXMgYnVpbGRlci5cbiAgICpcbiAgICogQHJldHVybnMgeyBzdHJpbmcgfVxuICAgKi9cbiAgdG9TdHJpbmcgKCkge1xuICAgIHJldHVybiBnZXRUZXh0KHRoaXMuX3N0YWNrSXRlbS5nZXRSb290KCkpO1xuICAgIC8vIFRoZXJlIHNob3VsZCBvbmx5IGJlIHRoZSByb290IGl0ZW0gaWYgZXZlcnl0aGluZyBpcyBjbG9zZWQgcHJvcGVybHkuXG4gIH1cblxufVxuXG5mdW5jdGlvbiBnZXRUZXh0IChzdGFja0l0ZW0pIHtcbiAgaWYgKCEoXG4gICAgc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICB8fCBzdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgIHx8IHN0YWNrSXRlbSBpbnN0YW5jZW9mIFRhYmxlQ2VsbFN0YWNrSXRlbVxuICApKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKCdPbmx5IGJsb2NrcywgbGlzdCBpdGVtcyBhbmQgdGFibGUgY2VsbHMgY2FuIGJlIHJlcXVlc3RlZCBmb3IgdGV4dCBjb250ZW50cy4nKTtcbiAgfVxuICByZXR1cm4gKHN0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlci5pc0VtcHR5KCkpXG4gICAgPyBzdGFja0l0ZW0ucmF3VGV4dFxuICAgIDogc3RhY2tJdGVtLnJhd1RleHQgKyBzdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIudG9TdHJpbmcoKTtcbn1cblxuZnVuY3Rpb24gYWRkVGV4dCAoc3RhY2tJdGVtLCB0ZXh0LCBsZWFkaW5nTGluZUJyZWFrcywgdHJhaWxpbmdMaW5lQnJlYWtzKSB7XG4gIGlmICghKFxuICAgIHN0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgfHwgc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICB8fCBzdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignT25seSBibG9ja3MsIGxpc3QgaXRlbXMgYW5kIHRhYmxlIGNlbGxzIGNhbiBjb250YWluIHRleHQuJyk7XG4gIH1cbiAgY29uc3QgcGFyZW50VGV4dCA9IGdldFRleHQoc3RhY2tJdGVtKTtcbiAgY29uc3QgbGluZUJyZWFrcyA9IE1hdGgubWF4KHN0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcywgbGVhZGluZ0xpbmVCcmVha3MpO1xuICBzdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuY2xlYXIoKTtcbiAgaWYgKHBhcmVudFRleHQpIHtcbiAgICBzdGFja0l0ZW0ucmF3VGV4dCA9IHBhcmVudFRleHQgKyAnXFxuJy5yZXBlYXQobGluZUJyZWFrcykgKyB0ZXh0O1xuICB9IGVsc2Uge1xuICAgIHN0YWNrSXRlbS5yYXdUZXh0ID0gdGV4dDtcbiAgICBzdGFja0l0ZW0ubGVhZGluZ0xpbmVCcmVha3MgPSBsaW5lQnJlYWtzO1xuICB9XG4gIHN0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyA9IHRyYWlsaW5nTGluZUJyZWFrcztcbn1cblxuLyoqXG4gKiBAcGFyYW0geyBzdHJpbmcgfSBzdHIgQSBzdHJpbmcgdG8gdHJhbnNmb3JtLlxuICogQHBhcmFtIHsgVHJhbnNmb3JtZXJTdGFja0l0ZW0gfSB0cmFuc2Zvcm1lciBBIHRyYW5zZm9ybWVyIGl0ZW0gKHdpdGggcG9zc2libGUgY29udGludWF0aW9uKS5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gYXBwbHlUcmFuc2Zvcm1lciAoc3RyLCB0cmFuc2Zvcm1lcikge1xuICByZXR1cm4gKCh0cmFuc2Zvcm1lcikgPyBhcHBseVRyYW5zZm9ybWVyKHRyYW5zZm9ybWVyLnRyYW5zZm9ybShzdHIpLCB0cmFuc2Zvcm1lci5uZXh0KSA6IHN0cik7XG59XG5cbi8qKlxuICogQ29tcGlsZSBzZWxlY3RvcnMgaW50byBhIGRlY2lzaW9uIHRyZWUsXG4gKiByZXR1cm4gYSBmdW5jdGlvbiBpbnRlbmRlZCBmb3IgYmF0Y2ggcHJvY2Vzc2luZy5cbiAqXG4gKiBAcGFyYW0gICB7IE9wdGlvbnMgfSBbb3B0aW9ucyA9IHt9XSAgIEh0bWxUb1RleHQgb3B0aW9ucyAoZGVmYXVsdHMsIGZvcm1hdHRlcnMsIHVzZXIgb3B0aW9ucyBtZXJnZWQsIGRlZHVwbGljYXRlZCkuXG4gKiBAcmV0dXJucyB7IChodG1sOiBzdHJpbmcsIG1ldGFkYXRhPzogYW55KSA9PiBzdHJpbmcgfSBQcmUtY29uZmlndXJlZCBjb252ZXJ0ZXIgZnVuY3Rpb24uXG4gKiBAc3RhdGljXG4gKi9cbmZ1bmN0aW9uIGNvbXBpbGUkMSAob3B0aW9ucyA9IHt9KSB7XG4gIGNvbnN0IHNlbGVjdG9yc1dpdGhvdXRGb3JtYXQgPSBvcHRpb25zLnNlbGVjdG9ycy5maWx0ZXIocyA9PiAhcy5mb3JtYXQpO1xuICBpZiAoc2VsZWN0b3JzV2l0aG91dEZvcm1hdC5sZW5ndGgpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoXG4gICAgICAnRm9sbG93aW5nIHNlbGVjdG9ycyBoYXZlIG5vIHNwZWNpZmllZCBmb3JtYXQ6ICcgK1xuICAgICAgc2VsZWN0b3JzV2l0aG91dEZvcm1hdC5tYXAocyA9PiBgXFxgJHtzLnNlbGVjdG9yfVxcYGApLmpvaW4oJywgJylcbiAgICApO1xuICB9XG4gIGNvbnN0IHBpY2tlciA9IG5ldyBzZWxkZXJlZS5EZWNpc2lvblRyZWUoXG4gICAgb3B0aW9ucy5zZWxlY3RvcnMubWFwKHMgPT4gW3Muc2VsZWN0b3IsIHNdKVxuICApLmJ1aWxkKHBsdWdpbkh0bWxwYXJzZXIyLmhwMkJ1aWxkZXIpO1xuXG4gIGlmICh0eXBlb2Ygb3B0aW9ucy5lbmNvZGVDaGFyYWN0ZXJzICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgb3B0aW9ucy5lbmNvZGVDaGFyYWN0ZXJzID0gbWFrZVJlcGxhY2VyRnJvbURpY3Qob3B0aW9ucy5lbmNvZGVDaGFyYWN0ZXJzKTtcbiAgfVxuXG4gIGNvbnN0IGJhc2VTZWxlY3RvcnNQaWNrZXIgPSBuZXcgc2VsZGVyZWUuRGVjaXNpb25UcmVlKFxuICAgIG9wdGlvbnMuYmFzZUVsZW1lbnRzLnNlbGVjdG9ycy5tYXAoKHMsIGkpID0+IFtzLCBpICsgMV0pXG4gICkuYnVpbGQocGx1Z2luSHRtbHBhcnNlcjIuaHAyQnVpbGRlcik7XG4gIGZ1bmN0aW9uIGZpbmRCYXNlRWxlbWVudHMgKGRvbSkge1xuICAgIHJldHVybiBmaW5kQmFzZXMoZG9tLCBvcHRpb25zLCBiYXNlU2VsZWN0b3JzUGlja2VyKTtcbiAgfVxuXG4gIGNvbnN0IGxpbWl0ZWRXYWxrID0gbGltaXRlZERlcHRoUmVjdXJzaXZlKFxuICAgIG9wdGlvbnMubGltaXRzLm1heERlcHRoLFxuICAgIHJlY3Vyc2l2ZVdhbGssXG4gICAgZnVuY3Rpb24gKGRvbSwgYnVpbGRlcikge1xuICAgICAgYnVpbGRlci5hZGRJbmxpbmUob3B0aW9ucy5saW1pdHMuZWxsaXBzaXMgfHwgJycpO1xuICAgIH1cbiAgKTtcblxuICByZXR1cm4gZnVuY3Rpb24gKGh0bWwsIG1ldGFkYXRhID0gdW5kZWZpbmVkKSB7XG4gICAgcmV0dXJuIHByb2Nlc3MoaHRtbCwgbWV0YWRhdGEsIG9wdGlvbnMsIHBpY2tlciwgZmluZEJhc2VFbGVtZW50cywgbGltaXRlZFdhbGspO1xuICB9O1xufVxuXG5cbi8qKlxuICogQ29udmVydCBnaXZlbiBIVE1MIGFjY29yZGluZyB0byBwcmVwcm9jZXNzZWQgb3B0aW9ucy5cbiAqXG4gKiBAcGFyYW0geyBzdHJpbmcgfSBodG1sIEhUTUwgY29udGVudCB0byBjb252ZXJ0LlxuICogQHBhcmFtIHsgYW55IH0gbWV0YWRhdGEgT3B0aW9uYWwgbWV0YWRhdGEgZm9yIEhUTUwgZG9jdW1lbnQsIGZvciB1c2UgaW4gZm9ybWF0dGVycy5cbiAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zIEh0bWxUb1RleHQgb3B0aW9ucyAocHJlcHJvY2Vzc2VkKS5cbiAqIEBwYXJhbSB7IGltcG9ydCgnc2VsZGVyZWUnKS5QaWNrZXI8RG9tTm9kZSwgVGFnRGVmaW5pdGlvbj4gfSBwaWNrZXJcbiAqIFRhZyBkZWZpbml0aW9uIHBpY2tlciBmb3IgRE9NIG5vZGVzIHByb2Nlc3NpbmcuXG4gKiBAcGFyYW0geyAoZG9tOiBEb21Ob2RlW10pID0+IERvbU5vZGVbXSB9IGZpbmRCYXNlRWxlbWVudHNcbiAqIEZ1bmN0aW9uIHRvIGV4dHJhY3QgZWxlbWVudHMgZnJvbSBIVE1MIERPTVxuICogdGhhdCB3aWxsIG9ubHkgYmUgcHJlc2VudCBpbiB0aGUgb3V0cHV0IHRleHQuXG4gKiBAcGFyYW0geyBSZWN1cnNpdmVDYWxsYmFjayB9IHdhbGsgUmVjdXJzaXZlIGNhbGxiYWNrLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiBwcm9jZXNzIChodG1sLCBtZXRhZGF0YSwgb3B0aW9ucywgcGlja2VyLCBmaW5kQmFzZUVsZW1lbnRzLCB3YWxrKSB7XG4gIGNvbnN0IG1heElucHV0TGVuZ3RoID0gb3B0aW9ucy5saW1pdHMubWF4SW5wdXRMZW5ndGg7XG4gIGlmIChtYXhJbnB1dExlbmd0aCAmJiBodG1sICYmIGh0bWwubGVuZ3RoID4gbWF4SW5wdXRMZW5ndGgpIHtcbiAgICBjb25zb2xlLndhcm4oXG4gICAgICBgSW5wdXQgbGVuZ3RoICR7aHRtbC5sZW5ndGh9IGlzIGFib3ZlIGFsbG93ZWQgbGltaXQgb2YgJHttYXhJbnB1dExlbmd0aH0uIFRydW5jYXRpbmcgd2l0aG91dCBlbGxpcHNpcy5gXG4gICAgKTtcbiAgICBodG1sID0gaHRtbC5zdWJzdHJpbmcoMCwgbWF4SW5wdXRMZW5ndGgpO1xuICB9XG5cbiAgY29uc3QgZG9jdW1lbnQgPSBodG1scGFyc2VyMi5wYXJzZURvY3VtZW50KGh0bWwsIHsgZGVjb2RlRW50aXRpZXM6IG9wdGlvbnMuZGVjb2RlRW50aXRpZXMgfSk7XG4gIGNvbnN0IGJhc2VzID0gZmluZEJhc2VFbGVtZW50cyhkb2N1bWVudC5jaGlsZHJlbik7XG4gIGNvbnN0IGJ1aWxkZXIgPSBuZXcgQmxvY2tUZXh0QnVpbGRlcihvcHRpb25zLCBwaWNrZXIsIG1ldGFkYXRhKTtcbiAgd2FsayhiYXNlcywgYnVpbGRlcik7XG4gIHJldHVybiBidWlsZGVyLnRvU3RyaW5nKCk7XG59XG5cblxuZnVuY3Rpb24gZmluZEJhc2VzIChkb20sIG9wdGlvbnMsIGJhc2VTZWxlY3RvcnNQaWNrZXIpIHtcbiAgY29uc3QgcmVzdWx0cyA9IFtdO1xuXG4gIGZ1bmN0aW9uIHJlY3Vyc2l2ZVdhbGsgKHdhbGssIC8qKiBAdHlwZSB7IERvbU5vZGVbXSB9ICovIGRvbSkge1xuICAgIGRvbSA9IGRvbS5zbGljZSgwLCBvcHRpb25zLmxpbWl0cy5tYXhDaGlsZE5vZGVzKTtcbiAgICBmb3IgKGNvbnN0IGVsZW0gb2YgZG9tKSB7XG4gICAgICBpZiAoZWxlbS50eXBlICE9PSAndGFnJykge1xuICAgICAgICBjb250aW51ZTtcbiAgICAgIH1cbiAgICAgIGNvbnN0IHBpY2tlZFNlbGVjdG9ySW5kZXggPSBiYXNlU2VsZWN0b3JzUGlja2VyLnBpY2sxKGVsZW0pO1xuICAgICAgaWYgKHBpY2tlZFNlbGVjdG9ySW5kZXggPiAwKSB7XG4gICAgICAgIHJlc3VsdHMucHVzaCh7IHNlbGVjdG9ySW5kZXg6IHBpY2tlZFNlbGVjdG9ySW5kZXgsIGVsZW1lbnQ6IGVsZW0gfSk7XG4gICAgICB9IGVsc2UgaWYgKGVsZW0uY2hpbGRyZW4pIHtcbiAgICAgICAgd2FsayhlbGVtLmNoaWxkcmVuKTtcbiAgICAgIH1cbiAgICAgIGlmIChyZXN1bHRzLmxlbmd0aCA+PSBvcHRpb25zLmxpbWl0cy5tYXhCYXNlRWxlbWVudHMpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGNvbnN0IGxpbWl0ZWRXYWxrID0gbGltaXRlZERlcHRoUmVjdXJzaXZlKFxuICAgIG9wdGlvbnMubGltaXRzLm1heERlcHRoLFxuICAgIHJlY3Vyc2l2ZVdhbGtcbiAgKTtcbiAgbGltaXRlZFdhbGsoZG9tKTtcblxuICBpZiAob3B0aW9ucy5iYXNlRWxlbWVudHMub3JkZXJCeSAhPT0gJ29jY3VycmVuY2UnKSB7IC8vICdzZWxlY3RvcnMnXG4gICAgcmVzdWx0cy5zb3J0KChhLCBiKSA9PiBhLnNlbGVjdG9ySW5kZXggLSBiLnNlbGVjdG9ySW5kZXgpO1xuICB9XG4gIHJldHVybiAob3B0aW9ucy5iYXNlRWxlbWVudHMucmV0dXJuRG9tQnlEZWZhdWx0ICYmIHJlc3VsdHMubGVuZ3RoID09PSAwKVxuICAgID8gZG9tXG4gICAgOiByZXN1bHRzLm1hcCh4ID0+IHguZWxlbWVudCk7XG59XG5cbi8qKlxuICogRnVuY3Rpb24gdG8gd2FsayB0aHJvdWdoIERPTSBub2RlcyBhbmQgYWNjdW11bGF0ZSB0aGVpciBzdHJpbmcgcmVwcmVzZW50YXRpb25zLlxuICpcbiAqIEBwYXJhbSAgIHsgUmVjdXJzaXZlQ2FsbGJhY2sgfSB3YWxrICAgIFJlY3Vyc2l2ZSBjYWxsYmFjay5cbiAqIEBwYXJhbSAgIHsgRG9tTm9kZVtdIH0gICAgICAgICBbZG9tXSAgIE5vZGVzIGFycmF5IHRvIHByb2Nlc3MuXG4gKiBAcGFyYW0gICB7IEJsb2NrVGV4dEJ1aWxkZXIgfSAgYnVpbGRlciBQYXNzZWQgYXJvdW5kIHRvIGFjY3VtdWxhdGUgb3V0cHV0IHRleHQuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiByZWN1cnNpdmVXYWxrICh3YWxrLCBkb20sIGJ1aWxkZXIpIHtcbiAgaWYgKCFkb20pIHsgcmV0dXJuOyB9XG5cbiAgY29uc3Qgb3B0aW9ucyA9IGJ1aWxkZXIub3B0aW9ucztcblxuICBjb25zdCB0b29NYW55Q2hpbGROb2RlcyA9IGRvbS5sZW5ndGggPiBvcHRpb25zLmxpbWl0cy5tYXhDaGlsZE5vZGVzO1xuICBpZiAodG9vTWFueUNoaWxkTm9kZXMpIHtcbiAgICBkb20gPSBkb20uc2xpY2UoMCwgb3B0aW9ucy5saW1pdHMubWF4Q2hpbGROb2Rlcyk7XG4gICAgZG9tLnB1c2goe1xuICAgICAgZGF0YTogb3B0aW9ucy5saW1pdHMuZWxsaXBzaXMsXG4gICAgICB0eXBlOiAndGV4dCdcbiAgICB9KTtcbiAgfVxuXG4gIGZvciAoY29uc3QgZWxlbSBvZiBkb20pIHtcbiAgICBzd2l0Y2ggKGVsZW0udHlwZSkge1xuICAgICAgY2FzZSAndGV4dCc6IHtcbiAgICAgICAgYnVpbGRlci5hZGRJbmxpbmUoZWxlbS5kYXRhKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBjYXNlICd0YWcnOiB7XG4gICAgICAgIGNvbnN0IHRhZ0RlZmluaXRpb24gPSBidWlsZGVyLnBpY2tlci5waWNrMShlbGVtKTtcbiAgICAgICAgY29uc3QgZm9ybWF0ID0gb3B0aW9ucy5mb3JtYXR0ZXJzW3RhZ0RlZmluaXRpb24uZm9ybWF0XTtcbiAgICAgICAgZm9ybWF0KGVsZW0sIHdhbGssIGJ1aWxkZXIsIHRhZ0RlZmluaXRpb24ub3B0aW9ucyB8fCB7fSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybjtcbn1cblxuLyoqXG4gKiBAcGFyYW0geyBPYmplY3Q8c3RyaW5nLHN0cmluZyB8IGZhbHNlPiB9IGRpY3RcbiAqIEEgZGljdGlvbmFyeSB3aGVyZSBrZXlzIGFyZSBjaGFyYWN0ZXJzIHRvIHJlcGxhY2VcbiAqIGFuZCB2YWx1ZXMgYXJlIHJlcGxhY2VtZW50IHN0cmluZ3MuXG4gKlxuICogRmlyc3QgY29kZSBwb2ludCBmcm9tIGRpY3Qga2V5cyBpcyB1c2VkLlxuICogQ29tcG91bmQgZW1vamlzIHdpdGggWldKIGFyZSBub3Qgc3VwcG9ydGVkIChub3QgdW50aWwgTm9kZSAxNikuXG4gKlxuICogQHJldHVybnMgeyAoKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcpIHwgdW5kZWZpbmVkIH1cbiAqL1xuZnVuY3Rpb24gbWFrZVJlcGxhY2VyRnJvbURpY3QgKGRpY3QpIHtcbiAgaWYgKCFkaWN0IHx8IE9iamVjdC5rZXlzKGRpY3QpLmxlbmd0aCA9PT0gMCkge1xuICAgIHJldHVybiB1bmRlZmluZWQ7XG4gIH1cbiAgLyoqIEB0eXBlIHsgW3N0cmluZywgc3RyaW5nXVtdIH0gKi9cbiAgY29uc3QgZW50cmllcyA9IE9iamVjdC5lbnRyaWVzKGRpY3QpLmZpbHRlcigoWywgdl0pID0+IHYgIT09IGZhbHNlKTtcbiAgY29uc3QgcmVnZXggPSBuZXcgUmVnRXhwKFxuICAgIGVudHJpZXNcbiAgICAgIC5tYXAoKFtjXSkgPT4gYCgke3VuaWNvZGVFc2NhcGUoWy4uLmNdWzBdKX0pYClcbiAgICAgIC5qb2luKCd8JyksXG4gICAgJ2cnXG4gICk7XG4gIGNvbnN0IHZhbHVlcyA9IGVudHJpZXMubWFwKChbLCB2XSkgPT4gdik7XG4gIGNvbnN0IHJlcGxhY2VyID0gKG0sIC4uLmNncykgPT4gdmFsdWVzW2Nncy5maW5kSW5kZXgoY2cgPT4gY2cpXTtcbiAgcmV0dXJuIChzdHIpID0+IHN0ci5yZXBsYWNlKHJlZ2V4LCByZXBsYWNlcik7XG59XG5cbi8qKlxuICogRHVtbXkgZm9ybWF0dGVyIHRoYXQgZGlzY2FyZHMgdGhlIGlucHV0IGFuZCBkb2VzIG5vdGhpbmcuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFNraXAgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgLyogZG8gbm90aGluZyAqL1xufVxuXG4vKipcbiAqIEluc2VydCB0aGUgZ2l2ZW4gc3RyaW5nIGxpdGVyYWwgaW5saW5lIGluc3RlYWQgb2YgYSB0YWcuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdElubGluZVN0cmluZyAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5zdHJpbmcgfHwgJycpO1xufVxuXG4vKipcbiAqIEluc2VydCBhIGJsb2NrIHdpdGggdGhlIGdpdmVuIHN0cmluZyBsaXRlcmFsIGluc3RlYWQgb2YgYSB0YWcuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEJsb2NrU3RyaW5nIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKGZvcm1hdE9wdGlvbnMuc3RyaW5nIHx8ICcnKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYW4gaW5saW5lLWxldmVsIGVsZW1lbnQuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdElubGluZSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBibG9jay1sZXZlbCBjb250YWluZXIuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEJsb2NrJDEgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbmZ1bmN0aW9uIHJlbmRlck9wZW5UYWcgKGVsZW0pIHtcbiAgY29uc3QgYXR0cnMgPSAoZWxlbS5hdHRyaWJzICYmIGVsZW0uYXR0cmlicy5sZW5ndGgpXG4gICAgPyAnICcgKyBPYmplY3QuZW50cmllcyhlbGVtLmF0dHJpYnMpXG4gICAgICAubWFwKChbaywgdl0pID0+ICgodiA9PT0gJycpID8gayA6IGAke2t9PSR7di5yZXBsYWNlKC9cIi9nLCAnJnF1b3Q7Jyl9YCkpXG4gICAgICAuam9pbignICcpXG4gICAgOiAnJztcbiAgcmV0dXJuIGA8JHtlbGVtLm5hbWV9JHthdHRyc30+YDtcbn1cblxuZnVuY3Rpb24gcmVuZGVyQ2xvc2VUYWcgKGVsZW0pIHtcbiAgcmV0dXJuIGA8LyR7ZWxlbS5uYW1lfT5gO1xufVxuXG4vKipcbiAqIFJlbmRlciBhbiBlbGVtZW50IGFzIGlubGluZSBIVE1MIHRhZywgd2FsayB0aHJvdWdoIGl0J3MgY2hpbGRyZW4uXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdElubGluZVRhZyAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChyZW5kZXJPcGVuVGFnKGVsZW0pKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuc3RhcnROb1dyYXAoKTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKHJlbmRlckNsb3NlVGFnKGVsZW0pKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG59XG5cbi8qKlxuICogUmVuZGVyIGFuIGVsZW1lbnQgYXMgSFRNTCBibG9jayBiYWcsIHdhbGsgdGhyb3VnaCBpdCdzIGNoaWxkcmVuLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRCbG9ja1RhZyAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG4gIGJ1aWxkZXIuc3RhcnROb1dyYXAoKTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKHJlbmRlck9wZW5UYWcoZWxlbSkpO1xuICBidWlsZGVyLnN0b3BOb1dyYXAoKTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwocmVuZGVyQ2xvc2VUYWcoZWxlbSkpO1xuICBidWlsZGVyLnN0b3BOb1dyYXAoKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xufVxuXG4vKipcbiAqIFJlbmRlciBhbiBlbGVtZW50IHdpdGggYWxsIGl0J3MgY2hpbGRyZW4gYXMgaW5saW5lIEhUTUwuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdElubGluZUh0bWwgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwoXG4gICAgZG9tU2VyaWFsaXplci5yZW5kZXIoZWxlbSwgeyBkZWNvZGVFbnRpdGllczogYnVpbGRlci5vcHRpb25zLmRlY29kZUVudGl0aWVzIH0pXG4gICk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xufVxuXG4vKipcbiAqIFJlbmRlciBhbiBlbGVtZW50IHdpdGggYWxsIGl0J3MgY2hpbGRyZW4gYXMgSFRNTCBibG9jay5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QmxvY2tIdG1sIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwoXG4gICAgZG9tU2VyaWFsaXplci5yZW5kZXIoZWxlbSwgeyBkZWNvZGVFbnRpdGllczogYnVpbGRlci5vcHRpb25zLmRlY29kZUVudGl0aWVzIH0pXG4gICk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUmVuZGVyIGlubGluZSBlbGVtZW50IHdyYXBwZWQgd2l0aCBnaXZlbiBzdHJpbmdzLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmVTdXJyb3VuZCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5wcmVmaXggfHwgJycpO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5zdWZmaXggfHwgJycpO1xufVxuXG52YXIgZ2VuZXJpY0Zvcm1hdHRlcnMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG4gIF9fcHJvdG9fXzogbnVsbCxcbiAgYmxvY2s6IGZvcm1hdEJsb2NrJDEsXG4gIGJsb2NrSHRtbDogZm9ybWF0QmxvY2tIdG1sLFxuICBibG9ja1N0cmluZzogZm9ybWF0QmxvY2tTdHJpbmcsXG4gIGJsb2NrVGFnOiBmb3JtYXRCbG9ja1RhZyxcbiAgaW5saW5lOiBmb3JtYXRJbmxpbmUsXG4gIGlubGluZUh0bWw6IGZvcm1hdElubGluZUh0bWwsXG4gIGlubGluZVN0cmluZzogZm9ybWF0SW5saW5lU3RyaW5nLFxuICBpbmxpbmVTdXJyb3VuZDogZm9ybWF0SW5saW5lU3Vycm91bmQsXG4gIGlubGluZVRhZzogZm9ybWF0SW5saW5lVGFnLFxuICBza2lwOiBmb3JtYXRTa2lwXG59KTtcblxuZnVuY3Rpb24gZ2V0Um93IChtYXRyaXgsIGopIHtcbiAgaWYgKCFtYXRyaXhbal0pIHsgbWF0cml4W2pdID0gW107IH1cbiAgcmV0dXJuIG1hdHJpeFtqXTtcbn1cblxuZnVuY3Rpb24gZmluZEZpcnN0VmFjYW50SW5kZXggKHJvdywgeCA9IDApIHtcbiAgd2hpbGUgKHJvd1t4XSkgeyB4Kys7IH1cbiAgcmV0dXJuIHg7XG59XG5cbmZ1bmN0aW9uIHRyYW5zcG9zZUluUGxhY2UgKG1hdHJpeCwgbWF4U2l6ZSkge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1heFNpemU7IGkrKykge1xuICAgIGNvbnN0IHJvd0kgPSBnZXRSb3cobWF0cml4LCBpKTtcbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IGk7IGorKykge1xuICAgICAgY29uc3Qgcm93SiA9IGdldFJvdyhtYXRyaXgsIGopO1xuICAgICAgaWYgKHJvd0lbal0gfHwgcm93SltpXSkge1xuICAgICAgICBjb25zdCB0ZW1wID0gcm93SVtqXTtcbiAgICAgICAgcm93SVtqXSA9IHJvd0pbaV07XG4gICAgICAgIHJvd0pbaV0gPSB0ZW1wO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBwdXRDZWxsSW50b0xheW91dCAoY2VsbCwgbGF5b3V0LCBiYXNlUm93LCBiYXNlQ29sKSB7XG4gIGZvciAobGV0IHIgPSAwOyByIDwgY2VsbC5yb3dzcGFuOyByKyspIHtcbiAgICBjb25zdCBsYXlvdXRSb3cgPSBnZXRSb3cobGF5b3V0LCBiYXNlUm93ICsgcik7XG4gICAgZm9yIChsZXQgYyA9IDA7IGMgPCBjZWxsLmNvbHNwYW47IGMrKykge1xuICAgICAgbGF5b3V0Um93W2Jhc2VDb2wgKyBjXSA9IGNlbGw7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGdldE9ySW5pdE9mZnNldCAob2Zmc2V0cywgaW5kZXgpIHtcbiAgaWYgKG9mZnNldHNbaW5kZXhdID09PSB1bmRlZmluZWQpIHtcbiAgICBvZmZzZXRzW2luZGV4XSA9IChpbmRleCA9PT0gMCkgPyAwIDogMSArIGdldE9ySW5pdE9mZnNldChvZmZzZXRzLCBpbmRleCAtIDEpO1xuICB9XG4gIHJldHVybiBvZmZzZXRzW2luZGV4XTtcbn1cblxuZnVuY3Rpb24gdXBkYXRlT2Zmc2V0IChvZmZzZXRzLCBiYXNlLCBzcGFuLCB2YWx1ZSkge1xuICBvZmZzZXRzW2Jhc2UgKyBzcGFuXSA9IE1hdGgubWF4KFxuICAgIGdldE9ySW5pdE9mZnNldChvZmZzZXRzLCBiYXNlICsgc3BhbiksXG4gICAgZ2V0T3JJbml0T2Zmc2V0KG9mZnNldHMsIGJhc2UpICsgdmFsdWVcbiAgKTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYSB0YWJsZSBpbnRvIGEgc3RyaW5nLlxuICogQ2VsbHMgY2FuIGNvbnRhaW4gbXVsdGlsaW5lIHRleHQgYW5kIHNwYW4gYWNyb3NzIG11bHRpcGxlIHJvd3MgYW5kIGNvbHVtbnMuXG4gKlxuICogTW9kaWZpZXMgY2VsbHMgdG8gYWRkIGxpbmVzIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7IFRhYmxlUHJpbnRlckNlbGxbXVtdIH0gdGFibGVSb3dzIFRhYmxlIHRvIHJlbmRlci5cbiAqIEBwYXJhbSB7IG51bWJlciB9IHJvd1NwYWNpbmcgTnVtYmVyIG9mIHNwYWNlcyBiZXR3ZWVuIGNvbHVtbnMuXG4gKiBAcGFyYW0geyBudW1iZXIgfSBjb2xTcGFjaW5nIE51bWJlciBvZiBlbXB0eSBsaW5lcyBiZXR3ZWVuIHJvd3MuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIHRhYmxlVG9TdHJpbmcgKHRhYmxlUm93cywgcm93U3BhY2luZywgY29sU3BhY2luZykge1xuICBjb25zdCBsYXlvdXQgPSBbXTtcbiAgbGV0IGNvbE51bWJlciA9IDA7XG4gIGNvbnN0IHJvd051bWJlciA9IHRhYmxlUm93cy5sZW5ndGg7XG4gIGNvbnN0IHJvd09mZnNldHMgPSBbMF07XG4gIC8vIEZpbGwgdGhlIGxheW91dCB0YWJsZSBhbmQgcm93IG9mZnNldHMgcm93LWJ5LXJvdy5cbiAgZm9yIChsZXQgaiA9IDA7IGogPCByb3dOdW1iZXI7IGorKykge1xuICAgIGNvbnN0IGxheW91dFJvdyA9IGdldFJvdyhsYXlvdXQsIGopO1xuICAgIGNvbnN0IGNlbGxzID0gdGFibGVSb3dzW2pdO1xuICAgIGxldCB4ID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNlbGxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjZWxsID0gY2VsbHNbaV07XG4gICAgICB4ID0gZmluZEZpcnN0VmFjYW50SW5kZXgobGF5b3V0Um93LCB4KTtcbiAgICAgIHB1dENlbGxJbnRvTGF5b3V0KGNlbGwsIGxheW91dCwgaiwgeCk7XG4gICAgICB4ICs9IGNlbGwuY29sc3BhbjtcbiAgICAgIGNlbGwubGluZXMgPSBjZWxsLnRleHQuc3BsaXQoJ1xcbicpO1xuICAgICAgY29uc3QgY2VsbEhlaWdodCA9IGNlbGwubGluZXMubGVuZ3RoO1xuICAgICAgdXBkYXRlT2Zmc2V0KHJvd09mZnNldHMsIGosIGNlbGwucm93c3BhbiwgY2VsbEhlaWdodCArIHJvd1NwYWNpbmcpO1xuICAgIH1cbiAgICBjb2xOdW1iZXIgPSAobGF5b3V0Um93Lmxlbmd0aCA+IGNvbE51bWJlcikgPyBsYXlvdXRSb3cubGVuZ3RoIDogY29sTnVtYmVyO1xuICB9XG5cbiAgdHJhbnNwb3NlSW5QbGFjZShsYXlvdXQsIChyb3dOdW1iZXIgPiBjb2xOdW1iZXIpID8gcm93TnVtYmVyIDogY29sTnVtYmVyKTtcblxuICBjb25zdCBvdXRwdXRMaW5lcyA9IFtdO1xuICBjb25zdCBjb2xPZmZzZXRzID0gWzBdO1xuICAvLyBGaWxsIGNvbHVtbiBvZmZzZXRzIGFuZCBvdXRwdXQgbGluZXMgY29sdW1uLWJ5LWNvbHVtbi5cbiAgZm9yIChsZXQgeCA9IDA7IHggPCBjb2xOdW1iZXI7IHgrKykge1xuICAgIGxldCB5ID0gMDtcbiAgICBsZXQgY2VsbDtcbiAgICBjb25zdCByb3dzSW5UaGlzQ29sdW1uID0gTWF0aC5taW4ocm93TnVtYmVyLCBsYXlvdXRbeF0ubGVuZ3RoKTtcbiAgICB3aGlsZSAoeSA8IHJvd3NJblRoaXNDb2x1bW4pIHtcbiAgICAgIGNlbGwgPSBsYXlvdXRbeF1beV07XG4gICAgICBpZiAoY2VsbCkge1xuICAgICAgICBpZiAoIWNlbGwucmVuZGVyZWQpIHtcbiAgICAgICAgICBsZXQgY2VsbFdpZHRoID0gMDtcbiAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNlbGwubGluZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBjZWxsLmxpbmVzW2pdO1xuICAgICAgICAgICAgY29uc3QgbGluZU9mZnNldCA9IHJvd09mZnNldHNbeV0gKyBqO1xuICAgICAgICAgICAgb3V0cHV0TGluZXNbbGluZU9mZnNldF0gPSAob3V0cHV0TGluZXNbbGluZU9mZnNldF0gfHwgJycpLnBhZEVuZChjb2xPZmZzZXRzW3hdKSArIGxpbmU7XG4gICAgICAgICAgICBjZWxsV2lkdGggPSAobGluZS5sZW5ndGggPiBjZWxsV2lkdGgpID8gbGluZS5sZW5ndGggOiBjZWxsV2lkdGg7XG4gICAgICAgICAgfVxuICAgICAgICAgIHVwZGF0ZU9mZnNldChjb2xPZmZzZXRzLCB4LCBjZWxsLmNvbHNwYW4sIGNlbGxXaWR0aCArIGNvbFNwYWNpbmcpO1xuICAgICAgICAgIGNlbGwucmVuZGVyZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHkgKz0gY2VsbC5yb3dzcGFuO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgbGluZU9mZnNldCA9IHJvd09mZnNldHNbeV07XG4gICAgICAgIG91dHB1dExpbmVzW2xpbmVPZmZzZXRdID0gKG91dHB1dExpbmVzW2xpbmVPZmZzZXRdIHx8ICcnKTtcbiAgICAgICAgeSsrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBvdXRwdXRMaW5lcy5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgbGluZS1icmVhay5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0TGluZUJyZWFrIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuYWRkTGluZUJyZWFrKCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGB3YnJgIHRhZyAod29yZCBicmVhayBvcHBvcnR1bml0eSkuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFdiciAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLmFkZFdvcmRCcmVha09wcG9ydHVuaXR5KCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGhvcml6b250YWwgbGluZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SG9yaXpvbnRhbExpbmUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLmFkZElubGluZSgnLScucmVwZWF0KGZvcm1hdE9wdGlvbnMubGVuZ3RoIHx8IGJ1aWxkZXIub3B0aW9ucy53b3Jkd3JhcCB8fCA0MCkpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIHBhcmFncmFwaC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0UGFyYWdyYXBoIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBwcmVmb3JtYXR0ZWQgY29udGVudC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0UHJlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHtcbiAgICBpc1ByZTogdHJ1ZSxcbiAgICBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyXG4gIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGhlYWRpbmcuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEhlYWRpbmcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBpZiAoZm9ybWF0T3B0aW9ucy51cHBlcmNhc2UgIT09IGZhbHNlKSB7XG4gICAgYnVpbGRlci5wdXNoV29yZFRyYW5zZm9ybShzdHIgPT4gc3RyLnRvVXBwZXJDYXNlKCkpO1xuICAgIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gICAgYnVpbGRlci5wb3BXb3JkVHJhbnNmb3JtKCk7XG4gIH0gZWxzZSB7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgfVxuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGJsb2NrcXVvdGUuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEJsb2NrcXVvdGUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soe1xuICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIsXG4gICAgcmVzZXJ2ZWRMaW5lTGVuZ3RoOiAyXG4gIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soe1xuICAgIHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMixcbiAgICBibG9ja1RyYW5zZm9ybTogc3RyID0+ICgoZm9ybWF0T3B0aW9ucy50cmltRW1wdHlMaW5lcyAhPT0gZmFsc2UpID8gdHJpbUNoYXJhY3RlcihzdHIsICdcXG4nKSA6IHN0cilcbiAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgIC5tYXAobGluZSA9PiAnPiAnICsgbGluZSlcbiAgICAgIC5qb2luKCdcXG4nKVxuICB9KTtcbn1cblxuZnVuY3Rpb24gd2l0aEJyYWNrZXRzIChzdHIsIGJyYWNrZXRzKSB7XG4gIGlmICghYnJhY2tldHMpIHsgcmV0dXJuIHN0cjsgfVxuXG4gIGNvbnN0IGxiciA9ICh0eXBlb2YgYnJhY2tldHNbMF0gPT09ICdzdHJpbmcnKVxuICAgID8gYnJhY2tldHNbMF1cbiAgICA6ICdbJztcbiAgY29uc3QgcmJyID0gKHR5cGVvZiBicmFja2V0c1sxXSA9PT0gJ3N0cmluZycpXG4gICAgPyBicmFja2V0c1sxXVxuICAgIDogJ10nO1xuICByZXR1cm4gbGJyICsgc3RyICsgcmJyO1xufVxuXG5mdW5jdGlvbiBwYXRoUmV3cml0ZSAocGF0aCwgcmV3cml0ZXIsIGJhc2VVcmwsIG1ldGFkYXRhLCBlbGVtKSB7XG4gIGNvbnN0IG1vZGlmaWVkUGF0aCA9ICh0eXBlb2YgcmV3cml0ZXIgPT09ICdmdW5jdGlvbicpXG4gICAgPyByZXdyaXRlcihwYXRoLCBtZXRhZGF0YSwgZWxlbSlcbiAgICA6IHBhdGg7XG4gIHJldHVybiAobW9kaWZpZWRQYXRoWzBdID09PSAnLycgJiYgYmFzZVVybClcbiAgICA/IHRyaW1DaGFyYWN0ZXJFbmQoYmFzZVVybCwgJy8nKSArIG1vZGlmaWVkUGF0aFxuICAgIDogbW9kaWZpZWRQYXRoO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYW4gaW1hZ2UuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEltYWdlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGNvbnN0IGF0dHJpYnMgPSBlbGVtLmF0dHJpYnMgfHwge307XG4gIGNvbnN0IGFsdCA9IChhdHRyaWJzLmFsdClcbiAgICA/IGF0dHJpYnMuYWx0XG4gICAgOiAnJztcbiAgY29uc3Qgc3JjID0gKCFhdHRyaWJzLnNyYylcbiAgICA/ICcnXG4gICAgOiBwYXRoUmV3cml0ZShhdHRyaWJzLnNyYywgZm9ybWF0T3B0aW9ucy5wYXRoUmV3cml0ZSwgZm9ybWF0T3B0aW9ucy5iYXNlVXJsLCBidWlsZGVyLm1ldGFkYXRhLCBlbGVtKTtcbiAgY29uc3QgdGV4dCA9ICghc3JjKVxuICAgID8gYWx0XG4gICAgOiAoIWFsdClcbiAgICAgID8gd2l0aEJyYWNrZXRzKHNyYywgZm9ybWF0T3B0aW9ucy5saW5rQnJhY2tldHMpXG4gICAgICA6IGFsdCArICcgJyArIHdpdGhCcmFja2V0cyhzcmMsIGZvcm1hdE9wdGlvbnMubGlua0JyYWNrZXRzKTtcblxuICBidWlsZGVyLmFkZElubGluZSh0ZXh0LCB7IG5vV29yZFRyYW5zZm9ybTogdHJ1ZSB9KTtcbn1cblxuLy8gYSBpbWcgYmFzZVVybFxuLy8gYSBpbWcgcGF0aFJld3JpdGVcbi8vIGEgaW1nIGxpbmtCcmFja2V0c1xuXG4vLyBhICAgICBpZ25vcmVIcmVmOiBmYWxzZVxuLy8gICAgICAgICAgICBpZ25vcmVUZXh0ID9cbi8vIGEgICAgIG5vQW5jaG9yVXJsOiB0cnVlXG4vLyAgICAgICAgICAgIGNhbiBiZSByZXBsYWNlZCB3aXRoIHNlbGVjdG9yXG4vLyBhICAgICBoaWRlTGlua0hyZWZJZlNhbWVBc1RleHQ6IGZhbHNlXG4vLyAgICAgICAgICAgIGhvdyB0byBjb21wYXJlLCB3aGF0IHRvIHNob3cgKHRleHQsIGhyZWYsIG5vcm1hbGl6ZWQpID9cbi8vIGEgICAgIG1haWx0byBwcm90b2NvbCByZW1vdmVkIHdpdGhvdXQgb3B0aW9uc1xuXG4vLyBhICAgICBwcm90b2NvbHM6IG1haWx0bywgdGVsLCAuLi5cbi8vICAgICAgICAgICAgY2FuIGJlIG1hdGNoZWQgd2l0aCBzZWxlY3Rvcj9cblxuLy8gYW5jaG9ycywgcHJvdG9jb2xzIC0gb25seSBpZiBubyBwYXRoUmV3cml0ZSBmbiBpcyBwcm92aWRlZFxuXG4vLyBub3JtYWxpemUtdXJsID9cblxuLy8gYVxuLy8gYVtocmVmXj1cIiNcIl0gLSBmb3JtYXQ6c2tpcCBieSBkZWZhdWx0XG4vLyBhW2hyZWZePVwibWFpbHRvOlwiXSAtID9cblxuLyoqXG4gKiBQcm9jZXNzIGFuIGFuY2hvci5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QW5jaG9yIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGZ1bmN0aW9uIGdldEhyZWYgKCkge1xuICAgIGlmIChmb3JtYXRPcHRpb25zLmlnbm9yZUhyZWYpIHsgcmV0dXJuICcnOyB9XG4gICAgaWYgKCFlbGVtLmF0dHJpYnMgfHwgIWVsZW0uYXR0cmlicy5ocmVmKSB7IHJldHVybiAnJzsgfVxuICAgIGxldCBocmVmID0gZWxlbS5hdHRyaWJzLmhyZWYucmVwbGFjZSgvXm1haWx0bzovLCAnJyk7XG4gICAgaWYgKGZvcm1hdE9wdGlvbnMubm9BbmNob3JVcmwgJiYgaHJlZlswXSA9PT0gJyMnKSB7IHJldHVybiAnJzsgfVxuICAgIGhyZWYgPSBwYXRoUmV3cml0ZShocmVmLCBmb3JtYXRPcHRpb25zLnBhdGhSZXdyaXRlLCBmb3JtYXRPcHRpb25zLmJhc2VVcmwsIGJ1aWxkZXIubWV0YWRhdGEsIGVsZW0pO1xuICAgIHJldHVybiBocmVmO1xuICB9XG4gIGNvbnN0IGhyZWYgPSBnZXRIcmVmKCk7XG4gIGlmICghaHJlZikge1xuICAgIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIH0gZWxzZSB7XG4gICAgbGV0IHRleHQgPSAnJztcbiAgICBidWlsZGVyLnB1c2hXb3JkVHJhbnNmb3JtKFxuICAgICAgc3RyID0+IHtcbiAgICAgICAgaWYgKHN0cikgeyB0ZXh0ICs9IHN0cjsgfVxuICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgfVxuICAgICk7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgICBidWlsZGVyLnBvcFdvcmRUcmFuc2Zvcm0oKTtcblxuICAgIGNvbnN0IGhpZGVTYW1lTGluayA9IGZvcm1hdE9wdGlvbnMuaGlkZUxpbmtIcmVmSWZTYW1lQXNUZXh0ICYmIGhyZWYgPT09IHRleHQ7XG4gICAgaWYgKCFoaWRlU2FtZUxpbmspIHtcbiAgICAgIGJ1aWxkZXIuYWRkSW5saW5lKFxuICAgICAgICAoIXRleHQpXG4gICAgICAgICAgPyBocmVmXG4gICAgICAgICAgOiAnICcgKyB3aXRoQnJhY2tldHMoaHJlZiwgZm9ybWF0T3B0aW9ucy5saW5rQnJhY2tldHMpLFxuICAgICAgICB7IG5vV29yZFRyYW5zZm9ybTogdHJ1ZSB9XG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEBwYXJhbSB7IERvbU5vZGUgfSAgICAgICAgICAgZWxlbSAgICAgICAgICAgICAgIExpc3QgaXRlbXMgd2l0aCB0aGVpciBwcmVmaXhlcy5cbiAqIEBwYXJhbSB7IFJlY3Vyc2l2ZUNhbGxiYWNrIH0gd2FsayAgICAgICAgICAgICAgIFJlY3Vyc2l2ZSBjYWxsYmFjayB0byBwcm9jZXNzIGNoaWxkIG5vZGVzLlxuICogQHBhcmFtIHsgQmxvY2tUZXh0QnVpbGRlciB9ICBidWlsZGVyICAgICAgICAgICAgUGFzc2VkIGFyb3VuZCB0byBhY2N1bXVsYXRlIG91dHB1dCB0ZXh0LlxuICogQHBhcmFtIHsgRm9ybWF0T3B0aW9ucyB9ICAgICBmb3JtYXRPcHRpb25zICAgICAgT3B0aW9ucyBzcGVjaWZpYyB0byBhIGZvcm1hdHRlci5cbiAqIEBwYXJhbSB7ICgpID0+IHN0cmluZyB9ICAgICAgbmV4dFByZWZpeENhbGxiYWNrIEZ1bmN0aW9uIHRoYXQgcmV0dXJucyBpbmNyZWFzaW5nIGluZGV4IGVhY2ggdGltZSBpdCBpcyBjYWxsZWQuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdExpc3QgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsIG5leHRQcmVmaXhDYWxsYmFjaykge1xuICBjb25zdCBpc05lc3RlZExpc3QgPSBnZXQoZWxlbSwgWydwYXJlbnQnLCAnbmFtZSddKSA9PT0gJ2xpJztcblxuICAvLyBXaXRoIFJvbWFuIG51bWJlcnMsIGluZGV4IGxlbmd0aCBpcyBub3QgYXMgc3RyYWlnaHRmb3J3YXJkIGFzIHdpdGggQXJhYmljIG51bWJlcnMgb3IgbGV0dGVycyxcbiAgLy8gc28gdGhlIGR1bWIgbGVuZ3RoIGNvbXBhcmlzb24gaXMgdGhlIG1vc3Qgcm9idXN0IHdheSB0byBnZXQgdGhlIGNvcnJlY3QgdmFsdWUuXG4gIGxldCBtYXhQcmVmaXhMZW5ndGggPSAwO1xuICBjb25zdCBsaXN0SXRlbXMgPSAoZWxlbS5jaGlsZHJlbiB8fCBbXSlcbiAgICAvLyBpdCBtaWdodCBiZSBtb3JlIGFjY3VyYXRlIHRvIGNoZWNrIG9ubHkgZm9yIGh0bWwgc3BhY2VzIGhlcmUsIGJ1dCBubyBzaWduaWZpY2FudCBiZW5lZml0XG4gICAgLmZpbHRlcihjaGlsZCA9PiBjaGlsZC50eXBlICE9PSAndGV4dCcgfHwgIS9eXFxzKiQvLnRlc3QoY2hpbGQuZGF0YSkpXG4gICAgLm1hcChmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICAgIGlmIChjaGlsZC5uYW1lICE9PSAnbGknKSB7XG4gICAgICAgIHJldHVybiB7IG5vZGU6IGNoaWxkLCBwcmVmaXg6ICcnIH07XG4gICAgICB9XG4gICAgICBjb25zdCBwcmVmaXggPSAoaXNOZXN0ZWRMaXN0KVxuICAgICAgICA/IG5leHRQcmVmaXhDYWxsYmFjaygpLnRyaW1TdGFydCgpXG4gICAgICAgIDogbmV4dFByZWZpeENhbGxiYWNrKCk7XG4gICAgICBpZiAocHJlZml4Lmxlbmd0aCA+IG1heFByZWZpeExlbmd0aCkgeyBtYXhQcmVmaXhMZW5ndGggPSBwcmVmaXgubGVuZ3RoOyB9XG4gICAgICByZXR1cm4geyBub2RlOiBjaGlsZCwgcHJlZml4OiBwcmVmaXggfTtcbiAgICB9KTtcbiAgaWYgKCFsaXN0SXRlbXMubGVuZ3RoKSB7IHJldHVybjsgfVxuXG4gIGJ1aWxkZXIub3Blbkxpc3Qoe1xuICAgIGludGVyUm93TGluZUJyZWFrczogMSxcbiAgICBsZWFkaW5nTGluZUJyZWFrczogaXNOZXN0ZWRMaXN0ID8gMSA6IChmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIpLFxuICAgIG1heFByZWZpeExlbmd0aDogbWF4UHJlZml4TGVuZ3RoLFxuICAgIHByZWZpeEFsaWduOiAnbGVmdCdcbiAgfSk7XG5cbiAgZm9yIChjb25zdCB7IG5vZGUsIHByZWZpeCB9IG9mIGxpc3RJdGVtcykge1xuICAgIGJ1aWxkZXIub3Blbkxpc3RJdGVtKHsgcHJlZml4OiBwcmVmaXggfSk7XG4gICAgd2Fsayhbbm9kZV0sIGJ1aWxkZXIpO1xuICAgIGJ1aWxkZXIuY2xvc2VMaXN0SXRlbSgpO1xuICB9XG5cbiAgYnVpbGRlci5jbG9zZUxpc3QoeyB0cmFpbGluZ0xpbmVCcmVha3M6IGlzTmVzdGVkTGlzdCA/IDEgOiAoZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMikgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiB1bm9yZGVyZWQgbGlzdC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0VW5vcmRlcmVkTGlzdCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBjb25zdCBwcmVmaXggPSBmb3JtYXRPcHRpb25zLml0ZW1QcmVmaXggfHwgJyAqICc7XG4gIHJldHVybiBmb3JtYXRMaXN0KGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsICgpID0+IHByZWZpeCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiBvcmRlcmVkIGxpc3QuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdE9yZGVyZWRMaXN0IChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGxldCBuZXh0SW5kZXggPSBOdW1iZXIoZWxlbS5hdHRyaWJzLnN0YXJ0IHx8ICcxJyk7XG4gIGNvbnN0IGluZGV4RnVuY3Rpb24gPSBnZXRPcmRlcmVkTGlzdEluZGV4RnVuY3Rpb24oZWxlbS5hdHRyaWJzLnR5cGUpO1xuICBjb25zdCBuZXh0UHJlZml4Q2FsbGJhY2sgPSAoKSA9PiAnICcgKyBpbmRleEZ1bmN0aW9uKG5leHRJbmRleCsrKSArICcuICc7XG4gIHJldHVybiBmb3JtYXRMaXN0KGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsIG5leHRQcmVmaXhDYWxsYmFjayk7XG59XG5cbi8qKlxuICogUmV0dXJuIGEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBnZW5lcmF0ZSBpbmRleCBtYXJrZXJzIG9mIGEgc3BlY2lmaWVkIGZvcm1hdC5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IFtvbFR5cGU9JzEnXSBNYXJrZXIgdHlwZS5cbiAqIEByZXR1cm5zIHsgKGk6IG51bWJlcikgPT4gc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gZ2V0T3JkZXJlZExpc3RJbmRleEZ1bmN0aW9uIChvbFR5cGUgPSAnMScpIHtcbiAgc3dpdGNoIChvbFR5cGUpIHtcbiAgICBjYXNlICdhJzogcmV0dXJuIChpKSA9PiBudW1iZXJUb0xldHRlclNlcXVlbmNlKGksICdhJyk7XG4gICAgY2FzZSAnQSc6IHJldHVybiAoaSkgPT4gbnVtYmVyVG9MZXR0ZXJTZXF1ZW5jZShpLCAnQScpO1xuICAgIGNhc2UgJ2knOiByZXR1cm4gKGkpID0+IG51bWJlclRvUm9tYW4oaSkudG9Mb3dlckNhc2UoKTtcbiAgICBjYXNlICdJJzogcmV0dXJuIChpKSA9PiBudW1iZXJUb1JvbWFuKGkpO1xuICAgIGNhc2UgJzEnOlxuICAgIGRlZmF1bHQ6IHJldHVybiAoaSkgPT4gKGkpLnRvU3RyaW5nKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHaXZlbiBhIGxpc3Qgb2YgY2xhc3MgYW5kIElEIHNlbGVjdG9ycyAocHJlZml4ZWQgd2l0aCAnLicgYW5kICcjJyksXG4gKiByZXR1cm4gdGhlbSBhcyBzZXBhcmF0ZSBsaXN0cyBvZiBuYW1lcyB3aXRob3V0IHByZWZpeGVzLlxuICpcbiAqIEBwYXJhbSB7IHN0cmluZ1tdIH0gc2VsZWN0b3JzIENsYXNzIGFuZCBJRCBzZWxlY3RvcnMgKGBbXCIuY2xhc3NcIiwgXCIjaWRcIl1gIGV0YykuXG4gKiBAcmV0dXJucyB7IHsgY2xhc3Nlczogc3RyaW5nW10sIGlkczogc3RyaW5nW10gfSB9XG4gKi9cbmZ1bmN0aW9uIHNwbGl0Q2xhc3Nlc0FuZElkcyAoc2VsZWN0b3JzKSB7XG4gIGNvbnN0IGNsYXNzZXMgPSBbXTtcbiAgY29uc3QgaWRzID0gW107XG4gIGZvciAoY29uc3Qgc2VsZWN0b3Igb2Ygc2VsZWN0b3JzKSB7XG4gICAgaWYgKHNlbGVjdG9yLnN0YXJ0c1dpdGgoJy4nKSkge1xuICAgICAgY2xhc3Nlcy5wdXNoKHNlbGVjdG9yLnN1YnN0cmluZygxKSk7XG4gICAgfSBlbHNlIGlmIChzZWxlY3Rvci5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgIGlkcy5wdXNoKHNlbGVjdG9yLnN1YnN0cmluZygxKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB7IGNsYXNzZXM6IGNsYXNzZXMsIGlkczogaWRzIH07XG59XG5cbmZ1bmN0aW9uIGlzRGF0YVRhYmxlIChhdHRyLCB0YWJsZXMpIHtcbiAgaWYgKHRhYmxlcyA9PT0gdHJ1ZSkgeyByZXR1cm4gdHJ1ZTsgfVxuICBpZiAoIWF0dHIpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgY29uc3QgeyBjbGFzc2VzLCBpZHMgfSA9IHNwbGl0Q2xhc3Nlc0FuZElkcyh0YWJsZXMpO1xuICBjb25zdCBhdHRyQ2xhc3NlcyA9IChhdHRyWydjbGFzcyddIHx8ICcnKS5zcGxpdCgnICcpO1xuICBjb25zdCBhdHRySWRzID0gKGF0dHJbJ2lkJ10gfHwgJycpLnNwbGl0KCcgJyk7XG5cbiAgcmV0dXJuIGF0dHJDbGFzc2VzLnNvbWUoeCA9PiBjbGFzc2VzLmluY2x1ZGVzKHgpKSB8fCBhdHRySWRzLnNvbWUoeCA9PiBpZHMuaW5jbHVkZXMoeCkpO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSB0YWJsZSAoZWl0aGVyIGFzIGEgY29udGFpbmVyIG9yIGFzIGEgZGF0YSB0YWJsZSwgZGVwZW5kaW5nIG9uIG9wdGlvbnMpLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRUYWJsZSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICByZXR1cm4gaXNEYXRhVGFibGUoZWxlbS5hdHRyaWJzLCBidWlsZGVyLm9wdGlvbnMudGFibGVzKVxuICAgID8gZm9ybWF0RGF0YVRhYmxlKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpXG4gICAgOiBmb3JtYXRCbG9jayhlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKTtcbn1cblxuZnVuY3Rpb24gZm9ybWF0QmxvY2sgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB9KTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgZGF0YSB0YWJsZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0RGF0YVRhYmxlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlblRhYmxlKCk7XG4gIGVsZW0uY2hpbGRyZW4uZm9yRWFjaCh3YWxrVGFibGUpO1xuICBidWlsZGVyLmNsb3NlVGFibGUoe1xuICAgIHRhYmxlVG9TdHJpbmc6IChyb3dzKSA9PiB0YWJsZVRvU3RyaW5nKHJvd3MsIGZvcm1hdE9wdGlvbnMucm93U3BhY2luZyA/PyAwLCBmb3JtYXRPcHRpb25zLmNvbFNwYWNpbmcgPz8gMyksXG4gICAgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MsXG4gICAgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrc1xuICB9KTtcblxuICBmdW5jdGlvbiBmb3JtYXRDZWxsIChjZWxsTm9kZSkge1xuICAgIGNvbnN0IGNvbHNwYW4gPSArZ2V0KGNlbGxOb2RlLCBbJ2F0dHJpYnMnLCAnY29sc3BhbiddKSB8fCAxO1xuICAgIGNvbnN0IHJvd3NwYW4gPSArZ2V0KGNlbGxOb2RlLCBbJ2F0dHJpYnMnLCAncm93c3BhbiddKSB8fCAxO1xuICAgIGJ1aWxkZXIub3BlblRhYmxlQ2VsbCh7IG1heENvbHVtbldpZHRoOiBmb3JtYXRPcHRpb25zLm1heENvbHVtbldpZHRoIH0pO1xuICAgIHdhbGsoY2VsbE5vZGUuY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICAgIGJ1aWxkZXIuY2xvc2VUYWJsZUNlbGwoeyBjb2xzcGFuOiBjb2xzcGFuLCByb3dzcGFuOiByb3dzcGFuIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gd2Fsa1RhYmxlIChlbGVtKSB7XG4gICAgaWYgKGVsZW0udHlwZSAhPT0gJ3RhZycpIHsgcmV0dXJuOyB9XG5cbiAgICBjb25zdCBmb3JtYXRIZWFkZXJDZWxsID0gKGZvcm1hdE9wdGlvbnMudXBwZXJjYXNlSGVhZGVyQ2VsbHMgIT09IGZhbHNlKVxuICAgICAgPyAoY2VsbE5vZGUpID0+IHtcbiAgICAgICAgYnVpbGRlci5wdXNoV29yZFRyYW5zZm9ybShzdHIgPT4gc3RyLnRvVXBwZXJDYXNlKCkpO1xuICAgICAgICBmb3JtYXRDZWxsKGNlbGxOb2RlKTtcbiAgICAgICAgYnVpbGRlci5wb3BXb3JkVHJhbnNmb3JtKCk7XG4gICAgICB9XG4gICAgICA6IGZvcm1hdENlbGw7XG5cbiAgICBzd2l0Y2ggKGVsZW0ubmFtZSkge1xuICAgICAgY2FzZSAndGhlYWQnOlxuICAgICAgY2FzZSAndGJvZHknOlxuICAgICAgY2FzZSAndGZvb3QnOlxuICAgICAgY2FzZSAnY2VudGVyJzpcbiAgICAgICAgZWxlbS5jaGlsZHJlbi5mb3JFYWNoKHdhbGtUYWJsZSk7XG4gICAgICAgIHJldHVybjtcblxuICAgICAgY2FzZSAndHInOiB7XG4gICAgICAgIGJ1aWxkZXIub3BlblRhYmxlUm93KCk7XG4gICAgICAgIGZvciAoY29uc3QgY2hpbGRPZlRyIG9mIGVsZW0uY2hpbGRyZW4pIHtcbiAgICAgICAgICBpZiAoY2hpbGRPZlRyLnR5cGUgIT09ICd0YWcnKSB7IGNvbnRpbnVlOyB9XG4gICAgICAgICAgc3dpdGNoIChjaGlsZE9mVHIubmFtZSkge1xuICAgICAgICAgICAgY2FzZSAndGgnOiB7XG4gICAgICAgICAgICAgIGZvcm1hdEhlYWRlckNlbGwoY2hpbGRPZlRyKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlICd0ZCc6IHtcbiAgICAgICAgICAgICAgZm9ybWF0Q2VsbChjaGlsZE9mVHIpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgLy8gZG8gbm90aGluZ1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBidWlsZGVyLmNsb3NlVGFibGVSb3coKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gIH1cbn1cblxudmFyIHRleHRGb3JtYXR0ZXJzID0gLyojX19QVVJFX18qL09iamVjdC5mcmVlemUoe1xuICBfX3Byb3RvX186IG51bGwsXG4gIGFuY2hvcjogZm9ybWF0QW5jaG9yLFxuICBibG9ja3F1b3RlOiBmb3JtYXRCbG9ja3F1b3RlLFxuICBkYXRhVGFibGU6IGZvcm1hdERhdGFUYWJsZSxcbiAgaGVhZGluZzogZm9ybWF0SGVhZGluZyxcbiAgaG9yaXpvbnRhbExpbmU6IGZvcm1hdEhvcml6b250YWxMaW5lLFxuICBpbWFnZTogZm9ybWF0SW1hZ2UsXG4gIGxpbmVCcmVhazogZm9ybWF0TGluZUJyZWFrLFxuICBvcmRlcmVkTGlzdDogZm9ybWF0T3JkZXJlZExpc3QsXG4gIHBhcmFncmFwaDogZm9ybWF0UGFyYWdyYXBoLFxuICBwcmU6IGZvcm1hdFByZSxcbiAgdGFibGU6IGZvcm1hdFRhYmxlLFxuICB1bm9yZGVyZWRMaXN0OiBmb3JtYXRVbm9yZGVyZWRMaXN0LFxuICB3YnI6IGZvcm1hdFdiclxufSk7XG5cbi8qKlxuICogRGVmYXVsdCBvcHRpb25zLlxuICpcbiAqIEBjb25zdGFudFxuICogQHR5cGUgeyBPcHRpb25zIH1cbiAqIEBkZWZhdWx0XG4gKiBAcHJpdmF0ZVxuICovXG5jb25zdCBERUZBVUxUX09QVElPTlMgPSB7XG4gIGJhc2VFbGVtZW50czoge1xuICAgIHNlbGVjdG9yczogWyAnYm9keScgXSxcbiAgICBvcmRlckJ5OiAnc2VsZWN0b3JzJywgLy8gJ3NlbGVjdG9ycycgfCAnb2NjdXJyZW5jZSdcbiAgICByZXR1cm5Eb21CeURlZmF1bHQ6IHRydWVcbiAgfSxcbiAgZGVjb2RlRW50aXRpZXM6IHRydWUsXG4gIGVuY29kZUNoYXJhY3RlcnM6IHt9LFxuICBmb3JtYXR0ZXJzOiB7fSxcbiAgbGltaXRzOiB7XG4gICAgZWxsaXBzaXM6ICcuLi4nLFxuICAgIG1heEJhc2VFbGVtZW50czogdW5kZWZpbmVkLFxuICAgIG1heENoaWxkTm9kZXM6IHVuZGVmaW5lZCxcbiAgICBtYXhEZXB0aDogdW5kZWZpbmVkLFxuICAgIG1heElucHV0TGVuZ3RoOiAoMSA8PCAyNCkgLy8gMTZfNzc3XzIxNlxuICB9LFxuICBsb25nV29yZFNwbGl0OiB7XG4gICAgZm9yY2VXcmFwT25MaW1pdDogZmFsc2UsXG4gICAgd3JhcENoYXJhY3RlcnM6IFtdXG4gIH0sXG4gIHByZXNlcnZlTmV3bGluZXM6IGZhbHNlLFxuICBzZWxlY3RvcnM6IFtcbiAgICB7IHNlbGVjdG9yOiAnKicsIGZvcm1hdDogJ2lubGluZScgfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2EnLFxuICAgICAgZm9ybWF0OiAnYW5jaG9yJyxcbiAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgYmFzZVVybDogbnVsbCxcbiAgICAgICAgaGlkZUxpbmtIcmVmSWZTYW1lQXNUZXh0OiBmYWxzZSxcbiAgICAgICAgaWdub3JlSHJlZjogZmFsc2UsXG4gICAgICAgIGxpbmtCcmFja2V0czogWydbJywgJ10nXSxcbiAgICAgICAgbm9BbmNob3JVcmw6IHRydWVcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICdhcnRpY2xlJywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdhc2lkZScsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2Jsb2NrcXVvdGUnLFxuICAgICAgZm9ybWF0OiAnYmxvY2txdW90ZScsXG4gICAgICBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHRyaW1FbXB0eUxpbmVzOiB0cnVlIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICdicicsIGZvcm1hdDogJ2xpbmVCcmVhaycgfSxcbiAgICB7IHNlbGVjdG9yOiAnZGl2JywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdmb290ZXInLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2Zvcm0nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2gxJywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDMsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDInLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMywgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoMycsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAzLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2g0JywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDUnLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoNicsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2hlYWRlcicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2hyJyxcbiAgICAgIGZvcm1hdDogJ2hvcml6b250YWxMaW5lJyxcbiAgICAgIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIGxlbmd0aDogdW5kZWZpbmVkLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIgfVxuICAgIH0sXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICdpbWcnLFxuICAgICAgZm9ybWF0OiAnaW1hZ2UnLFxuICAgICAgb3B0aW9uczogeyBiYXNlVXJsOiBudWxsLCBsaW5rQnJhY2tldHM6IFsnWycsICddJ10gfVxuICAgIH0sXG4gICAgeyBzZWxlY3RvcjogJ21haW4nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ25hdicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ29sJyxcbiAgICAgIGZvcm1hdDogJ29yZGVyZWRMaXN0JyxcbiAgICAgIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9XG4gICAgfSxcbiAgICB7IHNlbGVjdG9yOiAncCcsIGZvcm1hdDogJ3BhcmFncmFwaCcsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ3ByZScsIGZvcm1hdDogJ3ByZScsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ3NlY3Rpb24nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICd0YWJsZScsXG4gICAgICBmb3JtYXQ6ICd0YWJsZScsXG4gICAgICBvcHRpb25zOiB7XG4gICAgICAgIGNvbFNwYWNpbmc6IDMsXG4gICAgICAgIGxlYWRpbmdMaW5lQnJlYWtzOiAyLFxuICAgICAgICBtYXhDb2x1bW5XaWR0aDogNjAsXG4gICAgICAgIHJvd1NwYWNpbmc6IDAsXG4gICAgICAgIHRyYWlsaW5nTGluZUJyZWFrczogMixcbiAgICAgICAgdXBwZXJjYXNlSGVhZGVyQ2VsbHM6IHRydWVcbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAndWwnLFxuICAgICAgZm9ybWF0OiAndW5vcmRlcmVkTGlzdCcsXG4gICAgICBvcHRpb25zOiB7IGl0ZW1QcmVmaXg6ICcgKiAnLCBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICd3YnInLCBmb3JtYXQ6ICd3YnInIH0sXG4gIF0sXG4gIHRhYmxlczogW10sIC8vIGRlcHJlY2F0ZWRcbiAgd2hpdGVzcGFjZUNoYXJhY3RlcnM6ICcgXFx0XFxyXFxuXFxmXFx1MjAwYicsXG4gIHdvcmR3cmFwOiA4MFxufTtcblxuY29uc3QgY29uY2F0TWVyZ2UgPSAoYWNjLCBzcmMsIG9wdGlvbnMpID0+IFsuLi5hY2MsIC4uLnNyY107XG5jb25zdCBvdmVyd3JpdGVNZXJnZSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gWy4uLnNyY107XG5jb25zdCBzZWxlY3RvcnNNZXJnZSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gKFxuICAoYWNjLnNvbWUocyA9PiB0eXBlb2YgcyA9PT0gJ29iamVjdCcpKVxuICAgID8gY29uY2F0TWVyZ2UoYWNjLCBzcmMpIC8vIHNlbGVjdG9yc1xuICAgIDogb3ZlcndyaXRlTWVyZ2UoYWNjLCBzcmMpIC8vIGJhc2VFbGVtZW50cy5zZWxlY3RvcnNcbik7XG5cbi8qKlxuICogUHJlcHJvY2VzcyBvcHRpb25zLCBjb21waWxlIHNlbGVjdG9ycyBpbnRvIGEgZGVjaXNpb24gdHJlZSxcbiAqIHJldHVybiBhIGZ1bmN0aW9uIGludGVuZGVkIGZvciBiYXRjaCBwcm9jZXNzaW5nLlxuICpcbiAqIEBwYXJhbSAgIHsgT3B0aW9ucyB9IFtvcHRpb25zID0ge31dICAgSHRtbFRvVGV4dCBvcHRpb25zLlxuICogQHJldHVybnMgeyAoaHRtbDogc3RyaW5nLCBtZXRhZGF0YT86IGFueSkgPT4gc3RyaW5nIH0gUHJlLWNvbmZpZ3VyZWQgY29udmVydGVyIGZ1bmN0aW9uLlxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBjb21waWxlIChvcHRpb25zID0ge30pIHtcbiAgb3B0aW9ucyA9IG1lcmdlX19kZWZhdWx0W1wiZGVmYXVsdFwiXShcbiAgICBERUZBVUxUX09QVElPTlMsXG4gICAgb3B0aW9ucyxcbiAgICB7XG4gICAgICBhcnJheU1lcmdlOiBvdmVyd3JpdGVNZXJnZSxcbiAgICAgIGN1c3RvbU1lcmdlOiAoa2V5KSA9PiAoKGtleSA9PT0gJ3NlbGVjdG9ycycpID8gc2VsZWN0b3JzTWVyZ2UgOiB1bmRlZmluZWQpXG4gICAgfVxuICApO1xuICBvcHRpb25zLmZvcm1hdHRlcnMgPSBPYmplY3QuYXNzaWduKHt9LCBnZW5lcmljRm9ybWF0dGVycywgdGV4dEZvcm1hdHRlcnMsIG9wdGlvbnMuZm9ybWF0dGVycyk7XG4gIG9wdGlvbnMuc2VsZWN0b3JzID0gbWVyZ2VEdXBsaWNhdGVzUHJlZmVyTGFzdChvcHRpb25zLnNlbGVjdG9ycywgKHMgPT4gcy5zZWxlY3RvcikpO1xuXG4gIGhhbmRsZURlcHJlY2F0ZWRPcHRpb25zKG9wdGlvbnMpO1xuXG4gIHJldHVybiBjb21waWxlJDEob3B0aW9ucyk7XG59XG5cbi8qKlxuICogQ29udmVydCBnaXZlbiBIVE1MIGNvbnRlbnQgdG8gcGxhaW4gdGV4dCBzdHJpbmcuXG4gKlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSAgaHRtbCAgICAgICAgICAgSFRNTCBjb250ZW50IHRvIGNvbnZlcnQuXG4gKiBAcGFyYW0gICB7IE9wdGlvbnMgfSBbb3B0aW9ucyA9IHt9XSBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gKiBAcGFyYW0gICB7IGFueSB9ICAgICBbbWV0YWRhdGFdICAgICBPcHRpb25hbCBtZXRhZGF0YSBmb3IgSFRNTCBkb2N1bWVudCwgZm9yIHVzZSBpbiBmb3JtYXR0ZXJzLlxuICogQHJldHVybnMgeyBzdHJpbmcgfSAgICAgICAgICAgICAgICAgUGxhaW4gdGV4dCBzdHJpbmcuXG4gKiBAc3RhdGljXG4gKlxuICogQGV4YW1wbGVcbiAqIGNvbnN0IHsgY29udmVydCB9ID0gcmVxdWlyZSgnaHRtbC10by10ZXh0Jyk7XG4gKiBjb25zdCB0ZXh0ID0gY29udmVydCgnPGgxPkhlbGxvIFdvcmxkPC9oMT4nLCB7XG4gKiAgIHdvcmR3cmFwOiAxMzBcbiAqIH0pO1xuICogY29uc29sZS5sb2codGV4dCk7IC8vIEhFTExPIFdPUkxEXG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnQgKGh0bWwsIG9wdGlvbnMgPSB7fSwgbWV0YWRhdGEgPSB1bmRlZmluZWQpIHtcbiAgcmV0dXJuIGNvbXBpbGUob3B0aW9ucykoaHRtbCwgbWV0YWRhdGEpO1xufVxuXG4vKipcbiAqIE1hcCBwcmV2aW91c2x5IGV4aXN0aW5nIGFuZCBub3cgZGVwcmVjYXRlZCBvcHRpb25zIHRvIHRoZSBuZXcgb3B0aW9ucyBsYXlvdXQuXG4gKiBUaGlzIGlzIGEgc3ViamVjdCBmb3IgY2xlYW51cCBpbiBtYWpvciByZWxlYXNlcy5cbiAqXG4gKiBAcGFyYW0geyBPcHRpb25zIH0gb3B0aW9ucyBIdG1sVG9UZXh0IG9wdGlvbnMuXG4gKi9cbmZ1bmN0aW9uIGhhbmRsZURlcHJlY2F0ZWRPcHRpb25zIChvcHRpb25zKSB7XG4gIGlmIChvcHRpb25zLnRhZ3MpIHtcbiAgICBjb25zdCB0YWdEZWZpbml0aW9ucyA9IE9iamVjdC5lbnRyaWVzKG9wdGlvbnMudGFncykubWFwKFxuICAgICAgKFtzZWxlY3RvciwgZGVmaW5pdGlvbl0pID0+ICh7IC4uLmRlZmluaXRpb24sIHNlbGVjdG9yOiBzZWxlY3RvciB8fCAnKicgfSlcbiAgICApO1xuICAgIG9wdGlvbnMuc2VsZWN0b3JzLnB1c2goLi4udGFnRGVmaW5pdGlvbnMpO1xuICAgIG9wdGlvbnMuc2VsZWN0b3JzID0gbWVyZ2VEdXBsaWNhdGVzUHJlZmVyTGFzdChvcHRpb25zLnNlbGVjdG9ycywgKHMgPT4gcy5zZWxlY3RvcikpO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0IChvYmosIHBhdGgsIHZhbHVlKSB7XG4gICAgY29uc3QgdmFsdWVLZXkgPSBwYXRoLnBvcCgpO1xuICAgIGZvciAoY29uc3Qga2V5IG9mIHBhdGgpIHtcbiAgICAgIGxldCBuZXN0ZWQgPSBvYmpba2V5XTtcbiAgICAgIGlmICghbmVzdGVkKSB7XG4gICAgICAgIG5lc3RlZCA9IHt9O1xuICAgICAgICBvYmpba2V5XSA9IG5lc3RlZDtcbiAgICAgIH1cbiAgICAgIG9iaiA9IG5lc3RlZDtcbiAgICB9XG4gICAgb2JqW3ZhbHVlS2V5XSA9IHZhbHVlO1xuICB9XG5cbiAgaWYgKG9wdGlvbnNbJ2Jhc2VFbGVtZW50J10pIHtcbiAgICBjb25zdCBiYXNlRWxlbWVudCA9IG9wdGlvbnNbJ2Jhc2VFbGVtZW50J107XG4gICAgc2V0KFxuICAgICAgb3B0aW9ucyxcbiAgICAgIFsnYmFzZUVsZW1lbnRzJywgJ3NlbGVjdG9ycyddLFxuICAgICAgKEFycmF5LmlzQXJyYXkoYmFzZUVsZW1lbnQpID8gYmFzZUVsZW1lbnQgOiBbYmFzZUVsZW1lbnRdKVxuICAgICk7XG4gIH1cbiAgaWYgKG9wdGlvbnNbJ3JldHVybkRvbUJ5RGVmYXVsdCddICE9PSB1bmRlZmluZWQpIHtcbiAgICBzZXQob3B0aW9ucywgWydiYXNlRWxlbWVudHMnLCAncmV0dXJuRG9tQnlEZWZhdWx0J10sIG9wdGlvbnNbJ3JldHVybkRvbUJ5RGVmYXVsdCddKTtcbiAgfVxuXG4gIGZvciAoY29uc3QgZGVmaW5pdGlvbiBvZiBvcHRpb25zLnNlbGVjdG9ycykge1xuICAgIGlmIChkZWZpbml0aW9uLmZvcm1hdCA9PT0gJ2FuY2hvcicgJiYgZ2V0KGRlZmluaXRpb24sIFsnb3B0aW9ucycsICdub0xpbmtCcmFja2V0cyddKSkge1xuICAgICAgc2V0KGRlZmluaXRpb24sIFsnb3B0aW9ucycsICdsaW5rQnJhY2tldHMnXSwgZmFsc2UpO1xuICAgIH1cbiAgfVxufVxuXG5leHBvcnRzLmNvbXBpbGUgPSBjb21waWxlO1xuZXhwb3J0cy5jb252ZXJ0ID0gY29udmVydDtcbmV4cG9ydHMuaHRtbFRvVGV4dCA9IGNvbnZlcnQ7XG4iXSwibmFtZXMiOltdLCJpZ25vcmVMaXN0IjpbMF0sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///(rsc)/./node_modules/html-to-text/lib/html-to-text.cjs\n");
/***/ })
};
;