25 lines
178 KiB
JavaScript
25 lines
178 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@9.0.5";
|
|
exports.ids = ["vendor-chunks/html-to-text@9.0.5"];
|
|
exports.modules = {
|
|
|
|
/***/ "(action-browser)/./node_modules/.pnpm/html-to-text@9.0.5/node_modules/html-to-text/lib/html-to-text.mjs":
|
|
/*!**********************************************************************************************!*\
|
|
!*** ./node_modules/.pnpm/html-to-text@9.0.5/node_modules/html-to-text/lib/html-to-text.mjs ***!
|
|
\**********************************************************************************************/
|
|
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
|
|
|
|
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ compile: () => (/* binding */ compile),\n/* harmony export */ convert: () => (/* binding */ convert),\n/* harmony export */ htmlToText: () => (/* binding */ convert)\n/* harmony export */ });\n/* harmony import */ var _selderee_plugin_htmlparser2__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @selderee/plugin-htmlparser2 */ \"(action-browser)/./node_modules/.pnpm/@selderee+plugin-htmlparser2@0.11.0/node_modules/@selderee/plugin-htmlparser2/lib/hp2-builder.mjs\");\n/* harmony import */ var htmlparser2__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! htmlparser2 */ \"(action-browser)/./node_modules/.pnpm/htmlparser2@8.0.2/node_modules/htmlparser2/lib/esm/index.js\");\n/* harmony import */ var selderee__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! selderee */ \"(action-browser)/./node_modules/.pnpm/selderee@0.11.0/node_modules/selderee/lib/selderee.mjs\");\n/* harmony import */ var deepmerge__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! deepmerge */ \"(action-browser)/./node_modules/.pnpm/deepmerge@4.3.1/node_modules/deepmerge/dist/cjs.js\");\n/* harmony import */ var dom_serializer__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! dom-serializer */ \"(action-browser)/./node_modules/.pnpm/dom-serializer@2.0.0/node_modules/dom-serializer/lib/esm/index.js\");\n\n\n\n\n\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 ? deepmerge__WEBPACK_IMPORTED_MODULE_2__(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__WEBPACK_IMPORTED_MODULE_4__.DecisionTree(\n options.selectors.map(s => [s.selector, s])\n ).build(_selderee_plugin_htmlparser2__WEBPACK_IMPORTED_MODULE_0__.hp2Builder);\n\n if (typeof options.encodeCharacters !== 'function') {\n options.encodeCharacters = makeReplacerFromDict(options.encodeCharacters);\n }\n\n const baseSelectorsPicker = new selderee__WEBPACK_IMPORTED_MODULE_4__.DecisionTree(\n options.baseElements.selectors.map((s, i) => [s, i + 1])\n ).build(_selderee_plugin_htmlparser2__WEBPACK_IMPORTED_MODULE_0__.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 = (0,htmlparser2__WEBPACK_IMPORTED_MODULE_1__.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, '"')}`))\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 (0,dom_serializer__WEBPACK_IMPORTED_MODULE_3__.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 (0,dom_serializer__WEBPACK_IMPORTED_MODULE_3__.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 = deepmerge__WEBPACK_IMPORTED_MODULE_2__(\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\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiKGFjdGlvbi1icm93c2VyKS8uL25vZGVfbW9kdWxlcy8ucG5wbS9odG1sLXRvLXRleHRAOS4wLjUvbm9kZV9tb2R1bGVzL2h0bWwtdG8tdGV4dC9saWIvaHRtbC10by10ZXh0Lm1qcyIsIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7OztBQUEwRDtBQUNkO0FBQ0o7QUFDVjtBQUNVOztBQUV4QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYyxxQkFBcUI7QUFDbkMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBLG9DQUFvQztBQUNwQztBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSwrQ0FBK0M7QUFDL0MsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsY0FBYyxTQUFTO0FBQ3ZCLGNBQWMsU0FBUztBQUN2QixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWMsU0FBUztBQUN2QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxxQkFBcUI7QUFDakMsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBLDZCQUE2QixRQUFRO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVLHNDQUFLLHVCQUF1Qiw4QkFBOEI7QUFDcEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxjQUFjLFdBQVc7QUFDekIsY0FBYyxXQUFXO0FBQ3pCLGNB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LFdBQVcsVUFBVTtBQUNyQjtBQUNBO0FBQ0EsSUFBSTtBQUNKLHNCQUFzQjtBQUN0QjtBQUNBLG9DQUFvQztBQUNwQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxVQUFVO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLDBDQUEwQztBQUMvRTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRW1EIiwic291cmNlcyI6WyIvVXNlcnMvbWFyY21pbnRlbC9Qcm9qZWN0cy9lLXRpYi5jb20vbm9kZV9tb2R1bGVzLy5wbnBtL2h0bWwtdG8tdGV4dEA5LjAuNS9ub2RlX21vZHVsZXMvaHRtbC10by10ZXh0L2xpYi9odG1sLXRvLXRleHQubWpzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IGhwMkJ1aWxkZXIgfSBmcm9tICdAc2VsZGVyZWUvcGx1Z2luLWh0bWxwYXJzZXIyJztcbmltcG9ydCB7IHBhcnNlRG9jdW1lbnQgfSBmcm9tICdodG1scGFyc2VyMic7XG5pbXBvcnQgeyBEZWNpc2lvblRyZWUgfSBmcm9tICdzZWxkZXJlZSc7XG5pbXBvcnQgbWVyZ2UgZnJvbSAnZGVlcG1lcmdlJztcbmltcG9ydCB7IHJlbmRlciB9IGZyb20gJ2RvbS1zZXJpYWxpemVyJztcblxuLyoqXG4gKiBNYWtlIGEgcmVjdXJzaXZlIGZ1bmN0aW9uIHRoYXQgd2lsbCBvbmx5IHJ1biB0byBhIGdpdmVuIGRlcHRoXG4gKiBhbmQgc3dpdGNoZXMgdG8gYW4gYWx0ZXJuYXRpdmUgZnVuY3Rpb24gYXQgdGhhdCBkZXB0aC4gXFxcbiAqIE5vIGxpbWl0YXRpb24gaWYgYG5gIGlzIGB1bmRlZmluZWRgIChKdXN0IHdyYXBzIGBmYCBpbiB0aGF0IGNhc2UpLlxuICpcbiAqIEBwYXJhbSAgIHsgbnVtYmVyIHwgdW5kZWZpbmVkIH0gbiAgIEFsbG93ZWQgZGVwdGggb2YgcmVjdXJzaW9uLiBgdW5kZWZpbmVkYCBmb3Igbm8gbGltaXRhdGlvbi5cbiAqIEBwYXJhbSAgIHsgRnVuY3Rpb24gfSAgICAgICAgICAgZiAgIEZ1bmN0aW9uIHRoYXQgYWNjZXB0cyByZWN1cnNpdmUgY2FsbGJhY2sgYXMgdGhlIGZpcnN0IGFyZ3VtZW50LlxuICogQHBhcmFtICAgeyBGdW5jdGlvbiB9ICAgICAgICAgICBbZ10gRnVuY3Rpb24gdG8gcnVuIGluc3RlYWQsIHdoZW4gbWF4aW11bSBkZXB0aCB3YXMgcmVhY2hlZC4gRG8gbm90aGluZyBieSBkZWZhdWx0LlxuICogQHJldHVybnMgeyBGdW5jdGlvbiB9XG4gKi9cbmZ1bmN0aW9uIGxpbWl0ZWREZXB0aFJlY3Vyc2l2ZSAobiwgZiwgZyA9ICgpID0+IHVuZGVmaW5lZCkge1xuICBpZiAobiA9PT0gdW5kZWZpbmVkKSB7XG4gICAgY29uc3QgZjEgPSBmdW5jdGlvbiAoLi4uYXJncykgeyByZXR1cm4gZihmMSwgLi4uYXJncyk7IH07XG4gICAgcmV0dXJuIGYxO1xuICB9XG4gIGlmIChuID49IDApIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKC4uLmFyZ3MpIHsgcmV0dXJuIGYobGltaXRlZERlcHRoUmVjdXJzaXZlKG4gLSAxLCBmLCBnKSwgLi4uYXJncyk7IH07XG4gIH1cbiAgcmV0dXJuIGc7XG59XG5cbi8qKlxuICogUmV0dXJuIHRoZSBzYW1lIHN0cmluZyBvciBhIHN1YnN0cmluZyB3aXRoXG4gKiB0aGUgZ2l2ZW4gY2hhcmFjdGVyIG9jY3VycmVuY2VzIHJlbW92ZWQgZnJvbSBlYWNoIHNpZGUuXG4gKlxuICogQHBhcmFtICAgeyBzdHJpbmcgfSBzdHIgIEEgc3RyaW5nIHRvIHRyaW0uXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IGNoYXIgQSBjaGFyYWN0ZXIgdG8gYmUgdHJpbW1lZC5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gdHJpbUNoYXJhY3RlciAoc3RyLCBjaGFyKSB7XG4gIGxldCBzdGFydCA9IDA7XG4gIGxldCBlbmQgPSBzdHIubGVuZ3RoO1xuICB3aGlsZSAoc3RhcnQgPCBlbmQgJiYgc3RyW3N0YXJ0XSA9PT0gY2hhcikgeyArK3N0YXJ0OyB9XG4gIHdoaWxlIChlbmQgPiBzdGFydCAmJiBzdHJbZW5kIC0gMV0gPT09IGNoYXIpIHsgLS1lbmQ7IH1cbiAgcmV0dXJuIChzdGFydCA+IDAgfHwgZW5kIDwgc3RyLmxlbmd0aClcbiAgICA/IHN0ci5zdWJzdHJpbmcoc3RhcnQsIGVuZClcbiAgICA6IHN0cjtcbn1cblxuLyoqXG4gKiBSZXR1cm4gdGhlIHNhbWUgc3RyaW5nIG9yIGEgc3Vic3RyaW5nIHdpdGhcbiAqIHRoZSBnaXZlbiBjaGFyYWN0ZXIgb2NjdXJyZW5jZXMgcmVtb3ZlZCBmcm9tIHRoZSBlbmQgb25seS5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IHN0ciAgQSBzdHJpbmcgdG8gdHJpbS5cbiAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gY2hhciBBIGNoYXJhY3RlciB0byBiZSB0cmltbWVkLlxuICogQHJldHVybnMgeyBzdHJpbmcgfVxuICovXG5mdW5jdGlvbiB0cmltQ2hhcmFjdGVyRW5kIChzdHIsIGNoYXIpIHtcbiAgbGV0IGVuZCA9IHN0ci5sZW5ndGg7XG4gIHdoaWxlIChlbmQgPiAwICYmIHN0cltlbmQgLSAxXSA9PT0gY2hhcikgeyAtLWVuZDsgfVxuICByZXR1cm4gKGVuZCA8IHN0ci5sZW5ndGgpXG4gICAgPyBzdHIuc3Vic3RyaW5nKDAsIGVuZClcbiAgICA6IHN0cjtcbn1cblxuLyoqXG4gKiBSZXR1cm4gYSBuZXcgc3RyaW5nIHdpbGwgYWxsIGNoYXJhY3RlcnMgcmVwbGFjZWQgd2l0aCB1bmljb2RlIGVzY2FwZSBzZXF1ZW5jZXMuXG4gKiBUaGlzIGV4dHJlbWUga2luZCBvZiBlc2NhcGluZyBjYW4gdXNlZCB0byBiZSBzYWZlbHkgY29tcG9zZSByZWd1bGFyIGV4cHJlc3Npb25zLlxuICpcbiAqIEBwYXJhbSB7IHN0cmluZyB9IHN0ciBBIHN0cmluZyB0byBlc2NhcGUuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9IEEgc3RyaW5nIG9mIHVuaWNvZGUgZXNjYXBlIHNlcXVlbmNlcy5cbiAqL1xuZnVuY3Rpb24gdW5pY29kZUVzY2FwZSAoc3RyKSB7XG4gIHJldHVybiBzdHIucmVwbGFjZSgvW1xcc1xcU10vZywgYyA9PiAnXFxcXHUnICsgYy5jaGFyQ29kZUF0KCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDQsICcwJykpO1xufVxuXG4vKipcbiAqIERlZHVwbGljYXRlIGFuIGFycmF5IGJ5IGEgZ2l2ZW4ga2V5IGNhbGxiYWNrLlxuICogSXRlbSBwcm9wZXJ0aWVzIGFyZSBtZXJnZWQgcmVjdXJzaXZlbHkgYW5kIHdpdGggdGhlIHByZWZlcmVuY2UgZm9yIGxhc3QgZGVmaW5lZCB2YWx1ZXMuXG4gKiBPZiBpdGVtcyB3aXRoIHRoZSBzYW1lIGtleSwgbWVyZ2VkIGl0ZW0gdGFrZXMgdGhlIHBsYWNlIG9mIHRoZSBsYXN0IGl0ZW0sXG4gKiBvdGhlcnMgYXJlIG9taXR0ZWQuXG4gKlxuICogQHBhcmFtIHsgYW55W10gfSBpdGVtcyBBbiBhcnJheSB0byBkZWR1cGxpY2F0ZS5cbiAqIEBwYXJhbSB7ICh4OiBhbnkpID0+IHN0cmluZyB9IGdldEtleSBDYWxsYmFjayB0byBnZXQgYSB2YWx1ZSB0aGF0IGRpc3Rpbmd1aXNoZXMgdW5pcXVlIGl0ZW1zLlxuICogQHJldHVybnMgeyBhbnlbXSB9XG4gKi9cbmZ1bmN0aW9uIG1lcmdlRHVwbGljYXRlc1ByZWZlckxhc3QgKGl0ZW1zLCBnZXRLZXkpIHtcbiAgY29uc3QgbWFwID0gbmV3IE1hcCgpO1xuICBmb3IgKGxldCBpID0gaXRlbXMubGVuZ3RoOyBpLS0gPiAwOykge1xuICAgIGNvbnN0IGl0ZW0gPSBpdGVtc1tpXTtcbiAgICBjb25zdCBrZXkgPSBnZXRLZXkoaXRlbSk7XG4gICAgbWFwLnNldChcbiAgICAgIGtleSxcbiAgICAgIChtYXAuaGFzKGtleSkpXG4gICAgICAgID8gbWVyZ2UoaXRlbSwgbWFwLmdldChrZXkpLCB7IGFycmF5TWVyZ2U6IG92ZXJ3cml0ZU1lcmdlJDEgfSlcbiAgICAgICAgOiBpdGVtXG4gICAgKTtcbiAgfVxuICByZXR1cm4gWy4uLm1hcC52YWx1ZXMoKV0ucmV2ZXJzZSgpO1xufVxuXG5jb25zdCBvdmVyd3JpdGVNZXJnZSQxID0gKGFjYywgc3JjLCBvcHRpb25zKSA9PiBbLi4uc3JjXTtcblxuLyoqXG4gKiBHZXQgYSBuZXN0ZWQgcHJvcGVydHkgZnJvbSBhbiBvYmplY3QuXG4gKlxuICogQHBhcmFtICAgeyBvYmplY3QgfSAgIG9iaiAgVGhlIG9iamVjdCB0byBxdWVyeSBmb3IgdGhlIHZhbHVlLlxuICogQHBhcmFtICAgeyBzdHJpbmdbXSB9IHBhdGggVGhlIHBhdGggdG8gdGhlIHByb3BlcnR5LlxuICogQHJldHVybnMgeyBhbnkgfVxuICovXG5mdW5jdGlvbiBnZXQgKG9iaiwgcGF0aCkge1xuICBmb3IgKGNvbnN0IGtleSBvZiBwYXRoKSB7XG4gICAgaWYgKCFvYmopIHsgcmV0dXJuIHVuZGVmaW5lZDsgfVxuICAgIG9iaiA9IG9ialtrZXldO1xuICB9XG4gIHJldHVybiBvYmo7XG59XG5cbi8qKlxuICogQ29udmVydCBhIG51bWJlciBpbnRvIGFscGhhYmV0aWMgc2VxdWVuY2UgcmVwcmVzZW50YXRpb24gKFNlcXVlbmNlIHdpdGhvdXQgemVyb2VzKS5cbiAqXG4gKiBGb3IgZXhhbXBsZTogYGEsIC4uLiwgeiwgYWEsIC4uLiwgenosIGFhYSwgLi4uYC5cbiAqXG4gKiBAcGFyYW0gICB7IG51bWJlciB9IG51bSAgICAgICAgICAgICAgTnVtYmVyIHRvIGNvbnZlcnQuIE11c3QgYmUgPj0gMS5cbiAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gW2Jhc2VDaGFyID0gJ2EnXSBDaGFyYWN0ZXIgZm9yIDEgaW4gdGhlIHNlcXVlbmNlLlxuICogQHBhcmFtICAgeyBudW1iZXIgfSBbYmFzZSA9IDI2XSAgICAgIE51bWJlciBvZiBjaGFyYWN0ZXJzIGluIHRoZSBzZXF1ZW5jZS5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gbnVtYmVyVG9MZXR0ZXJTZXF1ZW5jZSAobnVtLCBiYXNlQ2hhciA9ICdhJywgYmFzZSA9IDI2KSB7XG4gIGNvbnN0IGRpZ2l0cyA9IFtdO1xuICBkbyB7XG4gICAgbnVtIC09IDE7XG4gICAgZGlnaXRzLnB1c2gobnVtICUgYmFzZSk7XG4gICAgbnVtID0gKG51bSAvIGJhc2UpID4+IDA7IC8vIHF1aWNrIGBmbG9vcmBcbiAgfSB3aGlsZSAobnVtID4gMCk7XG4gIGNvbnN0IGJhc2VDb2RlID0gYmFzZUNoYXIuY2hhckNvZGVBdCgwKTtcbiAgcmV0dXJuIGRpZ2l0c1xuICAgIC5yZXZlcnNlKClcbiAgICAubWFwKG4gPT4gU3RyaW5nLmZyb21DaGFyQ29kZShiYXNlQ29kZSArIG4pKVxuICAgIC5qb2luKCcnKTtcbn1cblxuY29uc3QgSSA9IFsnSScsICdYJywgJ0MnLCAnTSddO1xuY29uc3QgViA9IFsnVicsICdMJywgJ0QnXTtcblxuLyoqXG4gKiBDb252ZXJ0IGEgbnVtYmVyIHRvIGl0J3MgUm9tYW4gcmVwcmVzZW50YXRpb24uIE5vIGxhcmdlIG51bWJlcnMgZXh0ZW5zaW9uLlxuICpcbiAqIEBwYXJhbSAgIHsgbnVtYmVyIH0gbnVtIE51bWJlciB0byBjb252ZXJ0LiBgMCA8IG51bSA8PSAzOTk5YC5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gbnVtYmVyVG9Sb21hbiAobnVtKSB7XG4gIHJldHVybiBbLi4uKG51bSkgKyAnJ11cbiAgICAubWFwKG4gPT4gK24pXG4gICAgLnJldmVyc2UoKVxuICAgIC5tYXAoKHYsIGkpID0+ICgodiAlIDUgPCA0KVxuICAgICAgPyAodiA8IDUgPyAnJyA6IFZbaV0pICsgSVtpXS5yZXBlYXQodiAlIDUpXG4gICAgICA6IElbaV0gKyAodiA8IDUgPyBWW2ldIDogSVtpICsgMV0pKSlcbiAgICAucmV2ZXJzZSgpXG4gICAgLmpvaW4oJycpO1xufVxuXG4vKipcbiAqIEhlbHBzIHRvIGJ1aWxkIHRleHQgZnJvbSB3b3Jkcy5cbiAqL1xuY2xhc3MgSW5saW5lVGV4dEJ1aWxkZXIge1xuICAvKipcbiAgICogQ3JlYXRlcyBhbiBpbnN0YW5jZSBvZiBJbmxpbmVUZXh0QnVpbGRlci5cbiAgICpcbiAgICogSWYgYG1heExpbmVMZW5ndGhgIGlzIG5vdCBwcm92aWRlZCB0aGVuIGl0IGlzIGVpdGhlciBgb3B0aW9ucy53b3Jkd3JhcGAgb3IgdW5saW1pdGVkLlxuICAgKlxuICAgKiBAcGFyYW0geyBPcHRpb25zIH0gb3B0aW9ucyAgICAgICAgICAgSHRtbFRvVGV4dCBvcHRpb25zLlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSAgWyBtYXhMaW5lTGVuZ3RoIF0gVGhpcyBidWlsZGVyIHdpbGwgdHJ5IHRvIHdyYXAgdGV4dCB0byBmaXQgdGhpcyBsaW5lIGxlbmd0aC5cbiAgICovXG4gIGNvbnN0cnVjdG9yIChvcHRpb25zLCBtYXhMaW5lTGVuZ3RoID0gdW5kZWZpbmVkKSB7XG4gICAgLyoqIEB0eXBlIHsgc3RyaW5nW11bXSB9ICovXG4gICAgdGhpcy5saW5lcyA9IFtdO1xuICAgIC8qKiBAdHlwZSB7IHN0cmluZ1tdIH0gICAqL1xuICAgIHRoaXMubmV4dExpbmVXb3JkcyA9IFtdO1xuICAgIHRoaXMubWF4TGluZUxlbmd0aCA9IG1heExpbmVMZW5ndGggfHwgb3B0aW9ucy53b3Jkd3JhcCB8fCBOdW1iZXIuTUFYX1ZBTFVFO1xuICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyA9IHRoaXMubWF4TGluZUxlbmd0aDtcbiAgICB0aGlzLndyYXBDaGFyYWN0ZXJzID0gZ2V0KG9wdGlvbnMsIFsnbG9uZ1dvcmRTcGxpdCcsICd3cmFwQ2hhcmFjdGVycyddKSB8fCBbXTtcbiAgICB0aGlzLmZvcmNlV3JhcE9uTGltaXQgPSBnZXQob3B0aW9ucywgWydsb25nV29yZFNwbGl0JywgJ2ZvcmNlV3JhcE9uTGltaXQnXSkgfHwgZmFsc2U7XG5cbiAgICB0aGlzLnN0YXNoZWRTcGFjZSA9IGZhbHNlO1xuICAgIHRoaXMud29yZEJyZWFrT3Bwb3J0dW5pdHkgPSBmYWxzZTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBuZXcgd29yZC5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gd29yZCBBIHdvcmQgdG8gYWRkLlxuICAgKiBAcGFyYW0geyBib29sZWFuIH0gW25vV3JhcF0gRG9uJ3Qgd3JhcCB0ZXh0IGV2ZW4gaWYgdGhlIGxpbmUgaXMgdG9vIGxvbmcuXG4gICAqL1xuICBwdXNoV29yZCAod29yZCwgbm9XcmFwID0gZmFsc2UpIHtcbiAgICBpZiAodGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzIDw9IDAgJiYgIW5vV3JhcCkge1xuICAgICAgdGhpcy5zdGFydE5ld0xpbmUoKTtcbiAgICB9XG4gICAgY29uc3QgaXNMaW5lU3RhcnQgPSB0aGlzLm5leHRMaW5lV29yZHMubGVuZ3RoID09PSAwO1xuICAgIGNvbnN0IGNvc3QgPSB3b3JkLmxlbmd0aCArIChpc0xpbmVTdGFydCA/IDAgOiAxKTtcbiAgICBpZiAoKGNvc3QgPD0gdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzKSB8fCBub1dyYXApIHsgLy8gRml0cyBpbnRvIGF2YWlsYWJsZSBidWRnZXRcblxuICAgICAgdGhpcy5uZXh0TGluZVdvcmRzLnB1c2god29yZCk7XG4gICAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgLT0gY29zdDtcblxuICAgIH0gZWxzZSB7IC8vIERvZXMgbm90IGZpdCAtIHRyeSB0byBzcGxpdCB0aGUgd29yZFxuXG4gICAgICAvLyBUaGUgd29yZCBpcyBtb3ZlZCB0byBhIG5ldyBsaW5lIC0gcHJlZmVyIHRvIHdyYXAgYmV0d2VlbiB3b3Jkcy5cbiAgICAgIGNvbnN0IFtmaXJzdCwgLi4ucmVzdF0gPSB0aGlzLnNwbGl0TG9uZ1dvcmQod29yZCk7XG4gICAgICBpZiAoIWlzTGluZVN0YXJ0KSB7IHRoaXMuc3RhcnROZXdMaW5lKCk7IH1cbiAgICAgIHRoaXMubmV4dExpbmVXb3Jkcy5wdXNoKGZpcnN0KTtcbiAgICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyAtPSBmaXJzdC5sZW5ndGg7XG4gICAgICBmb3IgKGNvbnN0IHBhcnQgb2YgcmVzdCkge1xuICAgICAgICB0aGlzLnN0YXJ0TmV3TGluZSgpO1xuICAgICAgICB0aGlzLm5leHRMaW5lV29yZHMucHVzaChwYXJ0KTtcbiAgICAgICAgdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzIC09IHBhcnQubGVuZ3RoO1xuICAgICAgfVxuXG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBvcCBhIHdvcmQgZnJvbSB0aGUgY3VycmVudGx5IGJ1aWx0IGxpbmUuXG4gICAqIFRoaXMgZG9lc24ndCBhZmZlY3QgY29tcGxldGVkIGxpbmVzLlxuICAgKlxuICAgKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gICAqL1xuICBwb3BXb3JkICgpIHtcbiAgICBjb25zdCBsYXN0V29yZCA9IHRoaXMubmV4dExpbmVXb3Jkcy5wb3AoKTtcbiAgICBpZiAobGFzdFdvcmQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgY29uc3QgaXNMaW5lU3RhcnQgPSB0aGlzLm5leHRMaW5lV29yZHMubGVuZ3RoID09PSAwO1xuICAgICAgY29uc3QgY29zdCA9IGxhc3RXb3JkLmxlbmd0aCArIChpc0xpbmVTdGFydCA/IDAgOiAxKTtcbiAgICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyArPSBjb3N0O1xuICAgIH1cbiAgICByZXR1cm4gbGFzdFdvcmQ7XG4gIH1cblxuICAvKipcbiAgICogQ29uY2F0IGEgd29yZCB0byB0aGUgbGFzdCB3b3JkIGFscmVhZHkgaW4gdGhlIGJ1aWxkZXIuXG4gICAqIEFkZHMgYSBuZXcgd29yZCBpbiBjYXNlIHRoZXJlIGFyZSBubyB3b3JkcyB5ZXQgaW4gdGhlIGxhc3QgbGluZS5cbiAgICpcbiAgICogQHBhcmFtIHsgc3RyaW5nIH0gd29yZCBBIHdvcmQgdG8gYmUgY29uY2F0ZW5hdGVkLlxuICAgKiBAcGFyYW0geyBib29sZWFuIH0gW25vV3JhcF0gRG9uJ3Qgd3JhcCB0ZXh0IGV2ZW4gaWYgdGhlIGxpbmUgaXMgdG9vIGxvbmcuXG4gICAqL1xuICBjb25jYXRXb3JkICh3b3JkLCBub1dyYXAgPSBmYWxzZSkge1xuICAgIGlmICh0aGlzLndvcmRCcmVha09wcG9ydHVuaXR5ICYmIHdvcmQubGVuZ3RoID4gdGhpcy5uZXh0TGluZUF2YWlsYWJsZUNoYXJzKSB7XG4gICAgICB0aGlzLnB1c2hXb3JkKHdvcmQsIG5vV3JhcCk7XG4gICAgICB0aGlzLndvcmRCcmVha09wcG9ydHVuaXR5ID0gZmFsc2U7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnN0IGxhc3RXb3JkID0gdGhpcy5wb3BXb3JkKCk7XG4gICAgICB0aGlzLnB1c2hXb3JkKChsYXN0V29yZCkgPyBsYXN0V29yZC5jb25jYXQod29yZCkgOiB3b3JkLCBub1dyYXApO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgY3VycmVudCBsaW5lIChhbmQgbW9yZSBlbXB0eSBsaW5lcyBpZiBwcm92aWRlZCBhcmd1bWVudCA+IDEpIHRvIHRoZSBsaXN0IG9mIGNvbXBsZXRlIGxpbmVzIGFuZCBzdGFydCBhIG5ldyBvbmUuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IG4gTnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRoYXQgd2lsbCBiZSBhZGRlZCB0byB0aGUgcmVzdWx0aW5nIHN0cmluZy5cbiAgICovXG4gIHN0YXJ0TmV3TGluZSAobiA9IDEpIHtcbiAgICB0aGlzLmxpbmVzLnB1c2godGhpcy5uZXh0TGluZVdvcmRzKTtcbiAgICBpZiAobiA+IDEpIHtcbiAgICAgIHRoaXMubGluZXMucHVzaCguLi5BcnJheS5mcm9tKHsgbGVuZ3RoOiBuIC0gMSB9LCAoKSA9PiBbXSkpO1xuICAgIH1cbiAgICB0aGlzLm5leHRMaW5lV29yZHMgPSBbXTtcbiAgICB0aGlzLm5leHRMaW5lQXZhaWxhYmxlQ2hhcnMgPSB0aGlzLm1heExpbmVMZW5ndGg7XG4gIH1cblxuICAvKipcbiAgICogTm8gd29yZHMgaW4gdGhpcyBidWlsZGVyLlxuICAgKlxuICAgKiBAcmV0dXJucyB7IGJvb2xlYW4gfVxuICAgKi9cbiAgaXNFbXB0eSAoKSB7XG4gICAgcmV0dXJuIHRoaXMubGluZXMubGVuZ3RoID09PSAwXG4gICAgICAgICYmIHRoaXMubmV4dExpbmVXb3Jkcy5sZW5ndGggPT09IDA7XG4gIH1cblxuICBjbGVhciAoKSB7XG4gICAgdGhpcy5saW5lcy5sZW5ndGggPSAwO1xuICAgIHRoaXMubmV4dExpbmVXb3Jkcy5sZW5ndGggPSAwO1xuICAgIHRoaXMubmV4dExpbmVBdmFpbGFibGVDaGFycyA9IHRoaXMubWF4TGluZUxlbmd0aDtcbiAgfVxuXG4gIC8qKlxuICAgKiBKb2luIGFsbCBsaW5lcyBvZiB3b3JkcyBpbnNpZGUgdGhlIElubGluZVRleHRCdWlsZGVyIGludG8gYSBjb21wbGV0ZSBzdHJpbmcuXG4gICAqXG4gICAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAgICovXG4gIHRvU3RyaW5nICgpIHtcbiAgICByZXR1cm4gWy4uLnRoaXMubGluZXMsIHRoaXMubmV4dExpbmVXb3Jkc11cbiAgICAgIC5tYXAod29yZHMgPT4gd29yZHMuam9pbignICcpKVxuICAgICAgLmpvaW4oJ1xcbicpO1xuICB9XG5cbiAgLyoqXG4gICAqIFNwbGl0IGEgbG9uZyB3b3JkIHVwIHRvIGZpdCB3aXRoaW4gdGhlIHdvcmQgd3JhcCBsaW1pdC5cbiAgICogVXNlIGVpdGhlciBhIGNoYXJhY3RlciB0byBzcGxpdCBsb29raW5nIGJhY2sgZnJvbSB0aGUgd29yZCB3cmFwIGxpbWl0LFxuICAgKiBvciB0cnVuY2F0ZSB0byB0aGUgd29yZCB3cmFwIGxpbWl0LlxuICAgKlxuICAgKiBAcGFyYW0gICB7IHN0cmluZyB9ICAgd29yZCBJbnB1dCB3b3JkLlxuICAgKiBAcmV0dXJucyB7IHN0cmluZ1tdIH0gICAgICBQYXJ0cyBvZiB0aGUgd29yZC5cbiAgICovXG4gIHNwbGl0TG9uZ1dvcmQgKHdvcmQpIHtcbiAgICBjb25zdCBwYXJ0cyA9IFtdO1xuICAgIGxldCBpZHggPSAwO1xuICAgIHdoaWxlICh3b3JkLmxlbmd0aCA+IHRoaXMubWF4TGluZUxlbmd0aCkge1xuXG4gICAgICBjb25zdCBmaXJzdExpbmUgPSB3b3JkLnN1YnN0cmluZygwLCB0aGlzLm1heExpbmVMZW5ndGgpO1xuICAgICAgY29uc3QgcmVtYWluaW5nQ2hhcnMgPSB3b3JkLnN1YnN0cmluZyh0aGlzLm1heExpbmVMZW5ndGgpO1xuXG4gICAgICBjb25zdCBzcGxpdEluZGV4ID0gZmlyc3RMaW5lLmxhc3RJbmRleE9mKHRoaXMud3JhcENoYXJhY3RlcnNbaWR4XSk7XG5cbiAgICAgIGlmIChzcGxpdEluZGV4ID4gLTEpIHsgLy8gRm91bmQgYSBjaGFyYWN0ZXIgdG8gc3BsaXQgb25cblxuICAgICAgICB3b3JkID0gZmlyc3RMaW5lLnN1YnN0cmluZyhzcGxpdEluZGV4ICsgMSkgKyByZW1haW5pbmdDaGFycztcbiAgICAgICAgcGFydHMucHVzaChmaXJzdExpbmUuc3Vic3RyaW5nKDAsIHNwbGl0SW5kZXggKyAxKSk7XG5cbiAgICAgIH0gZWxzZSB7IC8vIE5vdCBmb3VuZCBhIGNoYXJhY3RlciB0byBzcGxpdCBvblxuXG4gICAgICAgIGlkeCsrO1xuICAgICAgICBpZiAoaWR4IDwgdGhpcy53cmFwQ2hhcmFjdGVycy5sZW5ndGgpIHsgLy8gVGhlcmUgaXMgbmV4dCBjaGFyYWN0ZXIgdG8gdHJ5XG5cbiAgICAgICAgICB3b3JkID0gZmlyc3RMaW5lICsgcmVtYWluaW5nQ2hhcnM7XG5cbiAgICAgICAgfSBlbHNlIHsgLy8gTm8gbW9yZSBjaGFyYWN0ZXJzIHRvIHRyeVxuXG4gICAgICAgICAgaWYgKHRoaXMuZm9yY2VXcmFwT25MaW1pdCkge1xuICAgICAgICAgICAgcGFydHMucHVzaChmaXJzdExpbmUpO1xuICAgICAgICAgICAgd29yZCA9IHJlbWFpbmluZ0NoYXJzO1xuICAgICAgICAgICAgaWYgKHdvcmQubGVuZ3RoID4gdGhpcy5tYXhMaW5lTGVuZ3RoKSB7XG4gICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3b3JkID0gZmlyc3RMaW5lICsgcmVtYWluaW5nQ2hhcnM7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIH1cblxuICAgICAgfVxuXG4gICAgfVxuICAgIHBhcnRzLnB1c2god29yZCk7IC8vIEFkZCByZW1haW5pbmcgcGFydCB0byBhcnJheVxuICAgIHJldHVybiBwYXJ0cztcbiAgfVxufVxuXG4vKiBlc2xpbnQtZGlzYWJsZSBtYXgtY2xhc3Nlcy1wZXItZmlsZSAqL1xuXG5cbmNsYXNzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChuZXh0ID0gbnVsbCkgeyB0aGlzLm5leHQgPSBuZXh0OyB9XG5cbiAgZ2V0Um9vdCAoKSB7IHJldHVybiAodGhpcy5uZXh0KSA/IHRoaXMubmV4dCA6IHRoaXM7IH1cbn1cblxuY2xhc3MgQmxvY2tTdGFja0l0ZW0gZXh0ZW5kcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAob3B0aW9ucywgbmV4dCA9IG51bGwsIGxlYWRpbmdMaW5lQnJlYWtzID0gMSwgbWF4TGluZUxlbmd0aCA9IHVuZGVmaW5lZCkge1xuICAgIHN1cGVyKG5leHQpO1xuICAgIHRoaXMubGVhZGluZ0xpbmVCcmVha3MgPSBsZWFkaW5nTGluZUJyZWFrcztcbiAgICB0aGlzLmlubGluZVRleHRCdWlsZGVyID0gbmV3IElubGluZVRleHRCdWlsZGVyKG9wdGlvbnMsIG1heExpbmVMZW5ndGgpO1xuICAgIHRoaXMucmF3VGV4dCA9ICcnO1xuICAgIHRoaXMuc3Rhc2hlZExpbmVCcmVha3MgPSAwO1xuICAgIHRoaXMuaXNQcmUgPSBuZXh0ICYmIG5leHQuaXNQcmU7XG4gICAgdGhpcy5pc05vV3JhcCA9IG5leHQgJiYgbmV4dC5pc05vV3JhcDtcbiAgfVxufVxuXG5jbGFzcyBMaXN0U3RhY2tJdGVtIGV4dGVuZHMgQmxvY2tTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAoXG4gICAgb3B0aW9ucyxcbiAgICBuZXh0ID0gbnVsbCxcbiAgICB7XG4gICAgICBpbnRlclJvd0xpbmVCcmVha3MgPSAxLFxuICAgICAgbGVhZGluZ0xpbmVCcmVha3MgPSAyLFxuICAgICAgbWF4TGluZUxlbmd0aCA9IHVuZGVmaW5lZCxcbiAgICAgIG1heFByZWZpeExlbmd0aCA9IDAsXG4gICAgICBwcmVmaXhBbGlnbiA9ICdsZWZ0JyxcbiAgICB9ID0ge31cbiAgKSB7XG4gICAgc3VwZXIob3B0aW9ucywgbmV4dCwgbGVhZGluZ0xpbmVCcmVha3MsIG1heExpbmVMZW5ndGgpO1xuICAgIHRoaXMubWF4UHJlZml4TGVuZ3RoID0gbWF4UHJlZml4TGVuZ3RoO1xuICAgIHRoaXMucHJlZml4QWxpZ24gPSBwcmVmaXhBbGlnbjtcbiAgICB0aGlzLmludGVyUm93TGluZUJyZWFrcyA9IGludGVyUm93TGluZUJyZWFrcztcbiAgfVxufVxuXG5jbGFzcyBMaXN0SXRlbVN0YWNrSXRlbSBleHRlbmRzIEJsb2NrU3RhY2tJdGVtIHtcbiAgY29uc3RydWN0b3IgKFxuICAgIG9wdGlvbnMsXG4gICAgbmV4dCA9IG51bGwsXG4gICAge1xuICAgICAgbGVhZGluZ0xpbmVCcmVha3MgPSAxLFxuICAgICAgbWF4TGluZUxlbmd0aCA9IHVuZGVmaW5lZCxcbiAgICAgIHByZWZpeCA9ICcnLFxuICAgIH0gPSB7fVxuICApIHtcbiAgICBzdXBlcihvcHRpb25zLCBuZXh0LCBsZWFkaW5nTGluZUJyZWFrcywgbWF4TGluZUxlbmd0aCk7XG4gICAgdGhpcy5wcmVmaXggPSBwcmVmaXg7XG4gIH1cbn1cblxuY2xhc3MgVGFibGVTdGFja0l0ZW0gZXh0ZW5kcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAobmV4dCA9IG51bGwpIHtcbiAgICBzdXBlcihuZXh0KTtcbiAgICB0aGlzLnJvd3MgPSBbXTtcbiAgICB0aGlzLmlzUHJlID0gbmV4dCAmJiBuZXh0LmlzUHJlO1xuICAgIHRoaXMuaXNOb1dyYXAgPSBuZXh0ICYmIG5leHQuaXNOb1dyYXA7XG4gIH1cbn1cblxuY2xhc3MgVGFibGVSb3dTdGFja0l0ZW0gZXh0ZW5kcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAobmV4dCA9IG51bGwpIHtcbiAgICBzdXBlcihuZXh0KTtcbiAgICB0aGlzLmNlbGxzID0gW107XG4gICAgdGhpcy5pc1ByZSA9IG5leHQgJiYgbmV4dC5pc1ByZTtcbiAgICB0aGlzLmlzTm9XcmFwID0gbmV4dCAmJiBuZXh0LmlzTm9XcmFwO1xuICB9XG59XG5cbmNsYXNzIFRhYmxlQ2VsbFN0YWNrSXRlbSBleHRlbmRzIFN0YWNrSXRlbSB7XG4gIGNvbnN0cnVjdG9yIChvcHRpb25zLCBuZXh0ID0gbnVsbCwgbWF4Q29sdW1uV2lkdGggPSB1bmRlZmluZWQpIHtcbiAgICBzdXBlcihuZXh0KTtcbiAgICB0aGlzLmlubGluZVRleHRCdWlsZGVyID0gbmV3IElubGluZVRleHRCdWlsZGVyKG9wdGlvbnMsIG1heENvbHVtbldpZHRoKTtcbiAgICB0aGlzLnJhd1RleHQgPSAnJztcbiAgICB0aGlzLnN0YXNoZWRMaW5lQnJlYWtzID0gMDtcbiAgICB0aGlzLmlzUHJlID0gbmV4dCAmJiBuZXh0LmlzUHJlO1xuICAgIHRoaXMuaXNOb1dyYXAgPSBuZXh0ICYmIG5leHQuaXNOb1dyYXA7XG4gIH1cbn1cblxuY2xhc3MgVHJhbnNmb3JtZXJTdGFja0l0ZW0gZXh0ZW5kcyBTdGFja0l0ZW0ge1xuICBjb25zdHJ1Y3RvciAobmV4dCA9IG51bGwsIHRyYW5zZm9ybSkge1xuICAgIHN1cGVyKG5leHQpO1xuICAgIHRoaXMudHJhbnNmb3JtID0gdHJhbnNmb3JtO1xuICB9XG59XG5cbmZ1bmN0aW9uIGNoYXJhY3RlcnNUb0NvZGVzIChzdHIpIHtcbiAgcmV0dXJuIFsuLi5zdHJdXG4gICAgLm1hcChjID0+ICdcXFxcdScgKyBjLmNoYXJDb2RlQXQoMCkudG9TdHJpbmcoMTYpLnBhZFN0YXJ0KDQsICcwJykpXG4gICAgLmpvaW4oJycpO1xufVxuXG4vKipcbiAqIEhlbHBzIHRvIGhhbmRsZSBIVE1MIHdoaXRlc3BhY2VzLlxuICpcbiAqIEBjbGFzcyBXaGl0ZXNwYWNlUHJvY2Vzc29yXG4gKi9cbmNsYXNzIFdoaXRlc3BhY2VQcm9jZXNzb3Ige1xuXG4gIC8qKlxuICAgKiBDcmVhdGVzIGFuIGluc3RhbmNlIG9mIFdoaXRlc3BhY2VQcm9jZXNzb3IuXG4gICAqXG4gICAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zICAgIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAgICogQG1lbWJlcm9mIFdoaXRlc3BhY2VQcm9jZXNzb3JcbiAgICovXG4gIGNvbnN0cnVjdG9yIChvcHRpb25zKSB7XG4gICAgdGhpcy53aGl0ZXNwYWNlQ2hhcnMgPSAob3B0aW9ucy5wcmVzZXJ2ZU5ld2xpbmVzKVxuICAgICAgPyBvcHRpb25zLndoaXRlc3BhY2VDaGFyYWN0ZXJzLnJlcGxhY2UoL1xcbi9nLCAnJylcbiAgICAgIDogb3B0aW9ucy53aGl0ZXNwYWNlQ2hhcmFjdGVycztcbiAgICBjb25zdCB3aGl0ZXNwYWNlQ29kZXMgPSBjaGFyYWN0ZXJzVG9Db2Rlcyh0aGlzLndoaXRlc3BhY2VDaGFycyk7XG4gICAgdGhpcy5sZWFkaW5nV2hpdGVzcGFjZVJlID0gbmV3IFJlZ0V4cChgXlske3doaXRlc3BhY2VDb2Rlc31dYCk7XG4gICAgdGhpcy50cmFpbGluZ1doaXRlc3BhY2VSZSA9IG5ldyBSZWdFeHAoYFske3doaXRlc3BhY2VDb2Rlc31dJGApO1xuICAgIHRoaXMuYWxsV2hpdGVzcGFjZU9yRW1wdHlSZSA9IG5ldyBSZWdFeHAoYF5bJHt3aGl0ZXNwYWNlQ29kZXN9XSokYCk7XG4gICAgdGhpcy5uZXdsaW5lT3JOb25XaGl0ZXNwYWNlUmUgPSBuZXcgUmVnRXhwKGAoXFxcXG58W15cXFxcbiR7d2hpdGVzcGFjZUNvZGVzfV0pYCwgJ2cnKTtcbiAgICB0aGlzLm5ld2xpbmVPck5vbk5ld2xpbmVTdHJpbmdSZSA9IG5ldyBSZWdFeHAoYChcXFxcbnxbXlxcXFxuXSspYCwgJ2cnKTtcblxuICAgIGlmIChvcHRpb25zLnByZXNlcnZlTmV3bGluZXMpIHtcblxuICAgICAgY29uc3Qgd29yZE9yTmV3bGluZVJlID0gbmV3IFJlZ0V4cChgXFxcXG58W15cXFxcbiR7d2hpdGVzcGFjZUNvZGVzfV0rYCwgJ2dtJyk7XG5cbiAgICAgIC8qKlxuICAgICAgICogU2hyaW5rIHdoaXRlc3BhY2VzIGFuZCB3cmFwIHRleHQsIGFkZCB0byB0aGUgYnVpbGRlci5cbiAgICAgICAqXG4gICAgICAgKiBAcGFyYW0geyBzdHJpbmcgfSAgICAgICAgICAgICAgICAgIHRleHQgICAgICAgICAgICAgIElucHV0IHRleHQuXG4gICAgICAgKiBAcGFyYW0geyBJbmxpbmVUZXh0QnVpbGRlciB9ICAgICAgIGlubGluZVRleHRCdWlsZGVyIEEgYnVpbGRlciB0byByZWNlaXZlIHByb2Nlc3NlZCB0ZXh0LlxuICAgICAgICogQHBhcmFtIHsgKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcgfSBbIHRyYW5zZm9ybSBdICAgICBBIHRyYW5zZm9ybSB0byBiZSBhcHBsaWVkIHRvIHdvcmRzLlxuICAgICAgICogQHBhcmFtIHsgYm9vbGVhbiB9ICAgICAgICAgICAgICAgICBbbm9XcmFwXSBEb24ndCB3cmFwIHRleHQgZXZlbiBpZiB0aGUgbGluZSBpcyB0b28gbG9uZy5cbiAgICAgICAqL1xuICAgICAgdGhpcy5zaHJpbmtXcmFwQWRkID0gZnVuY3Rpb24gKHRleHQsIGlubGluZVRleHRCdWlsZGVyLCB0cmFuc2Zvcm0gPSAoc3RyID0+IHN0ciksIG5vV3JhcCA9IGZhbHNlKSB7XG4gICAgICAgIGlmICghdGV4dCkgeyByZXR1cm47IH1cbiAgICAgICAgY29uc3QgcHJldmlvdXNseVN0YXNoZWRTcGFjZSA9IGlubGluZVRleHRCdWlsZGVyLnN0YXNoZWRTcGFjZTtcbiAgICAgICAgbGV0IGFueU1hdGNoID0gZmFsc2U7XG4gICAgICAgIGxldCBtID0gd29yZE9yTmV3bGluZVJlLmV4ZWModGV4dCk7XG4gICAgICAgIGlmIChtKSB7XG4gICAgICAgICAgYW55TWF0Y2ggPSB0cnVlO1xuICAgICAgICAgIGlmIChtWzBdID09PSAnXFxuJykge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKCk7XG4gICAgICAgICAgfSBlbHNlIGlmIChwcmV2aW91c2x5U3Rhc2hlZFNwYWNlIHx8IHRoaXMudGVzdExlYWRpbmdXaGl0ZXNwYWNlKHRleHQpKSB7XG4gICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5wdXNoV29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLmNvbmNhdFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgIH1cbiAgICAgICAgICB3aGlsZSAoKG0gPSB3b3JkT3JOZXdsaW5lUmUuZXhlYyh0ZXh0KSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgIGlmIChtWzBdID09PSAnXFxuJykge1xuICAgICAgICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFydE5ld0xpbmUoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlID0gKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgJiYgIWFueU1hdGNoKSB8fCAodGhpcy50ZXN0VHJhaWxpbmdXaGl0ZXNwYWNlKHRleHQpKTtcbiAgICAgICAgLy8gTm8gbmVlZCB0byBzdGFzaCBhIHNwYWNlIGluIGNhc2UgbGFzdCBhZGRlZCBpdGVtIHdhcyBhIG5ldyBsaW5lLFxuICAgICAgICAvLyBidXQgdGhhdCB3b24ndCBhZmZlY3QgYW55dGhpbmcgbGF0ZXIgYW55d2F5LlxuICAgICAgfTtcblxuICAgIH0gZWxzZSB7XG5cbiAgICAgIGNvbnN0IHdvcmRSZSA9IG5ldyBSZWdFeHAoYFteJHt3aGl0ZXNwYWNlQ29kZXN9XStgLCAnZycpO1xuXG4gICAgICB0aGlzLnNocmlua1dyYXBBZGQgPSBmdW5jdGlvbiAodGV4dCwgaW5saW5lVGV4dEJ1aWxkZXIsIHRyYW5zZm9ybSA9IChzdHIgPT4gc3RyKSwgbm9XcmFwID0gZmFsc2UpIHtcbiAgICAgICAgaWYgKCF0ZXh0KSB7IHJldHVybjsgfVxuICAgICAgICBjb25zdCBwcmV2aW91c2x5U3Rhc2hlZFNwYWNlID0gaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlO1xuICAgICAgICBsZXQgYW55TWF0Y2ggPSBmYWxzZTtcbiAgICAgICAgbGV0IG0gPSB3b3JkUmUuZXhlYyh0ZXh0KTtcbiAgICAgICAgaWYgKG0pIHtcbiAgICAgICAgICBhbnlNYXRjaCA9IHRydWU7XG4gICAgICAgICAgaWYgKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgfHwgdGhpcy50ZXN0TGVhZGluZ1doaXRlc3BhY2UodGV4dCkpIHtcbiAgICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKHRyYW5zZm9ybShtWzBdKSwgbm9XcmFwKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuY29uY2F0V29yZCh0cmFuc2Zvcm0obVswXSksIG5vV3JhcCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIHdoaWxlICgobSA9IHdvcmRSZS5leGVjKHRleHQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQodHJhbnNmb3JtKG1bMF0pLCBub1dyYXApO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2UgPSAocHJldmlvdXNseVN0YXNoZWRTcGFjZSAmJiAhYW55TWF0Y2gpIHx8IHRoaXMudGVzdFRyYWlsaW5nV2hpdGVzcGFjZSh0ZXh0KTtcbiAgICAgIH07XG5cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogQWRkIHRleHQgd2l0aCBvbmx5IG1pbmltYWwgcHJvY2Vzc2luZy5cbiAgICogRXZlcnl0aGluZyBiZXR3ZWVuIG5ld2xpbmVzIGNvbnNpZGVyZWQgYSBzaW5nbGUgd29yZC5cbiAgICogTm8gd2hpdGVzcGFjZSBpcyB0cmltbWVkLlxuICAgKiBOb3QgYWZmZWN0ZWQgYnkgcHJlc2VydmVOZXdsaW5lcyBvcHRpb24gLSBgXFxuYCBhbHdheXMgc3RhcnRzIGEgbmV3IGxpbmUuXG4gICAqXG4gICAqIGBub1dyYXBgIGFyZ3VtZW50IGlzIGB0cnVlYCBieSBkZWZhdWx0IC0gdGhpcyB3b24ndCBzdGFydCBhIG5ldyBsaW5lXG4gICAqIGV2ZW4gaWYgdGhlcmUgaXMgbm90IGVub3VnaCBzcGFjZSBsZWZ0IGluIHRoZSBjdXJyZW50IGxpbmUuXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9ICAgICAgICAgICAgdGV4dCAgICAgICAgICAgICAgSW5wdXQgdGV4dC5cbiAgICogQHBhcmFtIHsgSW5saW5lVGV4dEJ1aWxkZXIgfSBpbmxpbmVUZXh0QnVpbGRlciBBIGJ1aWxkZXIgdG8gcmVjZWl2ZSBwcm9jZXNzZWQgdGV4dC5cbiAgICogQHBhcmFtIHsgYm9vbGVhbiB9ICAgICAgICAgICBbbm9XcmFwXSBEb24ndCB3cmFwIHRleHQgZXZlbiBpZiB0aGUgbGluZSBpcyB0b28gbG9uZy5cbiAgICovXG4gIGFkZExpdGVyYWwgKHRleHQsIGlubGluZVRleHRCdWlsZGVyLCBub1dyYXAgPSB0cnVlKSB7XG4gICAgaWYgKCF0ZXh0KSB7IHJldHVybjsgfVxuICAgIGNvbnN0IHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgPSBpbmxpbmVUZXh0QnVpbGRlci5zdGFzaGVkU3BhY2U7XG4gICAgbGV0IGFueU1hdGNoID0gZmFsc2U7XG4gICAgbGV0IG0gPSB0aGlzLm5ld2xpbmVPck5vbk5ld2xpbmVTdHJpbmdSZS5leGVjKHRleHQpO1xuICAgIGlmIChtKSB7XG4gICAgICBhbnlNYXRjaCA9IHRydWU7XG4gICAgICBpZiAobVswXSA9PT0gJ1xcbicpIHtcbiAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKCk7XG4gICAgICB9IGVsc2UgaWYgKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UpIHtcbiAgICAgICAgaW5saW5lVGV4dEJ1aWxkZXIucHVzaFdvcmQobVswXSwgbm9XcmFwKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlubGluZVRleHRCdWlsZGVyLmNvbmNhdFdvcmQobVswXSwgbm9XcmFwKTtcbiAgICAgIH1cbiAgICAgIHdoaWxlICgobSA9IHRoaXMubmV3bGluZU9yTm9uTmV3bGluZVN0cmluZ1JlLmV4ZWModGV4dCkpICE9PSBudWxsKSB7XG4gICAgICAgIGlmIChtWzBdID09PSAnXFxuJykge1xuICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlubGluZVRleHRCdWlsZGVyLnB1c2hXb3JkKG1bMF0sIG5vV3JhcCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaW5saW5lVGV4dEJ1aWxkZXIuc3Rhc2hlZFNwYWNlID0gKHByZXZpb3VzbHlTdGFzaGVkU3BhY2UgJiYgIWFueU1hdGNoKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBUZXN0IHdoZXRoZXIgdGhlIGdpdmVuIHRleHQgc3RhcnRzIHdpdGggSFRNTCB3aGl0ZXNwYWNlIGNoYXJhY3Rlci5cbiAgICpcbiAgICogQHBhcmFtICAgeyBzdHJpbmcgfSAgdGV4dCAgVGhlIHN0cmluZyB0byB0ZXN0LlxuICAgKiBAcmV0dXJucyB7IGJvb2xlYW4gfVxuICAgKi9cbiAgdGVzdExlYWRpbmdXaGl0ZXNwYWNlICh0ZXh0KSB7XG4gICAgcmV0dXJuIHRoaXMubGVhZGluZ1doaXRlc3BhY2VSZS50ZXN0KHRleHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRlc3Qgd2hldGhlciB0aGUgZ2l2ZW4gdGV4dCBlbmRzIHdpdGggSFRNTCB3aGl0ZXNwYWNlIGNoYXJhY3Rlci5cbiAgICpcbiAgICogQHBhcmFtICAgeyBzdHJpbmcgfSAgdGV4dCAgVGhlIHN0cmluZyB0byB0ZXN0LlxuICAgKiBAcmV0dXJucyB7IGJvb2xlYW4gfVxuICAgKi9cbiAgdGVzdFRyYWlsaW5nV2hpdGVzcGFjZSAodGV4dCkge1xuICAgIHJldHVybiB0aGlzLnRyYWlsaW5nV2hpdGVzcGFjZVJlLnRlc3QodGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogVGVzdCB3aGV0aGVyIHRoZSBnaXZlbiB0ZXh0IGNvbnRhaW5zIGFueSBub24td2hpdGVzcGFjZSBjaGFyYWN0ZXJzLlxuICAgKlxuICAgKiBAcGFyYW0gICB7IHN0cmluZyB9ICB0ZXh0ICBUaGUgc3RyaW5nIHRvIHRlc3QuXG4gICAqIEByZXR1cm5zIHsgYm9vbGVhbiB9XG4gICAqL1xuICB0ZXN0Q29udGFpbnNXb3JkcyAodGV4dCkge1xuICAgIHJldHVybiAhdGhpcy5hbGxXaGl0ZXNwYWNlT3JFbXB0eVJlLnRlc3QodGV4dCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0dXJuIHRoZSBudW1iZXIgb2YgbmV3bGluZXMgaWYgdGhlcmUgYXJlIG5vIHdvcmRzLlxuICAgKlxuICAgKiBJZiBhbnkgd29yZCBpcyBmb3VuZCB0aGVuIHJldHVybiB6ZXJvIHJlZ2FyZGxlc3Mgb2YgdGhlIGFjdHVhbCBudW1iZXIgb2YgbmV3bGluZXMuXG4gICAqXG4gICAqIEBwYXJhbSAgIHsgc3RyaW5nIH0gIHRleHQgIElucHV0IHN0cmluZy5cbiAgICogQHJldHVybnMgeyBudW1iZXIgfVxuICAgKi9cbiAgY291bnROZXdsaW5lc05vV29yZHMgKHRleHQpIHtcbiAgICB0aGlzLm5ld2xpbmVPck5vbldoaXRlc3BhY2VSZS5sYXN0SW5kZXggPSAwO1xuICAgIGxldCBjb3VudGVyID0gMDtcbiAgICBsZXQgbWF0Y2g7XG4gICAgd2hpbGUgKChtYXRjaCA9IHRoaXMubmV3bGluZU9yTm9uV2hpdGVzcGFjZVJlLmV4ZWModGV4dCkpICE9PSBudWxsKSB7XG4gICAgICBpZiAobWF0Y2hbMF0gPT09ICdcXG4nKSB7XG4gICAgICAgIGNvdW50ZXIrKztcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiAwO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gY291bnRlcjtcbiAgfVxuXG59XG5cbi8qKlxuICogSGVscHMgdG8gYnVpbGQgdGV4dCBmcm9tIGlubGluZSBhbmQgYmxvY2sgZWxlbWVudHMuXG4gKlxuICogQGNsYXNzIEJsb2NrVGV4dEJ1aWxkZXJcbiAqL1xuY2xhc3MgQmxvY2tUZXh0QnVpbGRlciB7XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYW4gaW5zdGFuY2Ugb2YgQmxvY2tUZXh0QnVpbGRlci5cbiAgICpcbiAgICogQHBhcmFtIHsgT3B0aW9ucyB9IG9wdGlvbnMgSHRtbFRvVGV4dCBvcHRpb25zLlxuICAgKiBAcGFyYW0geyBpbXBvcnQoJ3NlbGRlcmVlJykuUGlja2VyPERvbU5vZGUsIFRhZ0RlZmluaXRpb24+IH0gcGlja2VyIFNlbGVjdG9ycyBkZWNpc2lvbiB0cmVlIHBpY2tlci5cbiAgICogQHBhcmFtIHsgYW55fSBbbWV0YWRhdGFdIE9wdGlvbmFsIG1ldGFkYXRhIGZvciBIVE1MIGRvY3VtZW50LCBmb3IgdXNlIGluIGZvcm1hdHRlcnMuXG4gICAqL1xuICBjb25zdHJ1Y3RvciAob3B0aW9ucywgcGlja2VyLCBtZXRhZGF0YSA9IHVuZGVmaW5lZCkge1xuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG4gICAgdGhpcy5waWNrZXIgPSBwaWNrZXI7XG4gICAgdGhpcy5tZXRhZGF0YSA9IG1ldGFkYXRhO1xuICAgIHRoaXMud2hpdGVzcGFjZVByb2Nlc3NvciA9IG5ldyBXaGl0ZXNwYWNlUHJvY2Vzc29yKG9wdGlvbnMpO1xuICAgIC8qKiBAdHlwZSB7IFN0YWNrSXRlbSB9ICovXG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IEJsb2NrU3RhY2tJdGVtKG9wdGlvbnMpO1xuICAgIC8qKiBAdHlwZSB7IFRyYW5zZm9ybWVyU3RhY2tJdGVtIH0gKi9cbiAgICB0aGlzLl93b3JkVHJhbnNmb3JtZXIgPSB1bmRlZmluZWQ7XG4gIH1cblxuICAvKipcbiAgICogUHV0IGEgd29yZC1ieS13b3JkIHRyYW5zZm9ybSBmdW5jdGlvbiBvbnRvIHRoZSB0cmFuc2Zvcm1hdGlvbnMgc3RhY2suXG4gICAqXG4gICAqIE1haW5seSB1c2VkIGZvciB1cHBlcmNhc2luZy4gQ2FuIGJlIGJ5cGFzc2VkIHRvIGFkZCB1bmZvcm1hdHRlZCB0ZXh0IHN1Y2ggYXMgVVJMcy5cbiAgICpcbiAgICogV29yZCB0cmFuc2Zvcm1hdGlvbnMgYXBwbGllZCBiZWZvcmUgd3JhcHBpbmcuXG4gICAqXG4gICAqIEBwYXJhbSB7IChzdHI6IHN0cmluZykgPT4gc3RyaW5nIH0gd29yZFRyYW5zZm9ybSBXb3JkIHRyYW5zZm9ybWF0aW9uIGZ1bmN0aW9uLlxuICAgKi9cbiAgcHVzaFdvcmRUcmFuc2Zvcm0gKHdvcmRUcmFuc2Zvcm0pIHtcbiAgICB0aGlzLl93b3JkVHJhbnNmb3JtZXIgPSBuZXcgVHJhbnNmb3JtZXJTdGFja0l0ZW0odGhpcy5fd29yZFRyYW5zZm9ybWVyLCB3b3JkVHJhbnNmb3JtKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZW1vdmUgYSBmdW5jdGlvbiBmcm9tIHRoZSB3b3JkIHRyYW5zZm9ybWF0aW9ucyBzdGFjay5cbiAgICpcbiAgICogQHJldHVybnMgeyAoc3RyOiBzdHJpbmcpID0+IHN0cmluZyB9IEEgZnVuY3Rpb24gdGhhdCB3YXMgcmVtb3ZlZC5cbiAgICovXG4gIHBvcFdvcmRUcmFuc2Zvcm0gKCkge1xuICAgIGlmICghdGhpcy5fd29yZFRyYW5zZm9ybWVyKSB7IHJldHVybiB1bmRlZmluZWQ7IH1cbiAgICBjb25zdCB0cmFuc2Zvcm0gPSB0aGlzLl93b3JkVHJhbnNmb3JtZXIudHJhbnNmb3JtO1xuICAgIHRoaXMuX3dvcmRUcmFuc2Zvcm1lciA9IHRoaXMuX3dvcmRUcmFuc2Zvcm1lci5uZXh0O1xuICAgIHJldHVybiB0cmFuc2Zvcm07XG4gIH1cblxuICAvKipcbiAgICogSWdub3JlIHdvcmR3cmFwIG9wdGlvbiBpbiBmb2xsb3d1cCBpbmxpbmUgYWRkaXRpb25zIGFuZCBkaXNhYmxlIGF1dG9tYXRpYyB3cmFwcGluZy5cbiAgICovXG4gIHN0YXJ0Tm9XcmFwICgpIHtcbiAgICB0aGlzLl9zdGFja0l0ZW0uaXNOb1dyYXAgPSB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldHVybiBhdXRvbWF0aWMgd3JhcHBpbmcgdG8gYmVoYXZpb3IgZGVmaW5lZCBieSBvcHRpb25zLlxuICAgKi9cbiAgc3RvcE5vV3JhcCAoKSB7XG4gICAgdGhpcy5fc3RhY2tJdGVtLmlzTm9XcmFwID0gZmFsc2U7XG4gIH1cblxuICAvKiogQHJldHVybnMgeyAoc3RyOiBzdHJpbmcpID0+IHN0cmluZyB9ICovXG4gIF9nZXRDb21iaW5lZFdvcmRUcmFuc2Zvcm1lciAoKSB7XG4gICAgY29uc3Qgd3QgPSAodGhpcy5fd29yZFRyYW5zZm9ybWVyKVxuICAgICAgPyAoKHN0cikgPT4gYXBwbHlUcmFuc2Zvcm1lcihzdHIsIHRoaXMuX3dvcmRUcmFuc2Zvcm1lcikpXG4gICAgICA6IHVuZGVmaW5lZDtcbiAgICBjb25zdCBjZSA9IHRoaXMub3B0aW9ucy5lbmNvZGVDaGFyYWN0ZXJzO1xuICAgIHJldHVybiAod3QpXG4gICAgICA/ICgoY2UpID8gKHN0cikgPT4gY2Uod3Qoc3RyKSkgOiB3dClcbiAgICAgIDogY2U7XG4gIH1cblxuICBfcG9wU3RhY2tJdGVtICgpIHtcbiAgICBjb25zdCBpdGVtID0gdGhpcy5fc3RhY2tJdGVtO1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IGl0ZW0ubmV4dDtcbiAgICByZXR1cm4gaXRlbTtcbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBsaW5lIGJyZWFrIGludG8gY3VycmVudGx5IGJ1aWx0IGJsb2NrLlxuICAgKi9cbiAgYWRkTGluZUJyZWFrICgpIHtcbiAgICBpZiAoIShcbiAgICAgIHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICAgKSkgeyByZXR1cm47IH1cbiAgICBpZiAodGhpcy5fc3RhY2tJdGVtLmlzUHJlKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0ucmF3VGV4dCArPSAnXFxuJztcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSgpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBbGxvdyB0byBicmVhayBsaW5lIGluIGNhc2UgZGlyZWN0bHkgZm9sbG93aW5nIHRleHQgd2lsbCBub3QgZml0LlxuICAgKi9cbiAgYWRkV29yZEJyZWFrT3Bwb3J0dW5pdHkgKCkge1xuICAgIGlmIChcbiAgICAgIHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBMaXN0SXRlbVN0YWNrSXRlbVxuICAgICAgfHwgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICAgKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIud29yZEJyZWFrT3Bwb3J0dW5pdHkgPSB0cnVlO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBBZGQgYSBub2RlIGlubGluZSBpbnRvIHRoZSBjdXJyZW50bHkgYnVpbHQgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9IHN0clxuICAgKiBUZXh0IGNvbnRlbnQgb2YgYSBub2RlIHRvIGFkZC5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMV1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIG9wZXJhdGlvbi5cbiAgICpcbiAgICogQHBhcmFtIHsgYm9vbGVhbiB9IFtwYXJhbTEubm9Xb3JkVHJhbnNmb3JtXVxuICAgKiBJZ25vcmUgd29yZCB0cmFuc2Zvcm1lcnMgaWYgdGhlcmUgYXJlIGFueS5cbiAgICogRG9uJ3QgZW5jb2RlIGNoYXJhY3RlcnMgYXMgd2VsbC5cbiAgICogKFVzZSB0aGlzIGZvciB0aGluZ3MgbGlrZSBVUkwgYWRkcmVzc2VzKS5cbiAgICovXG4gIGFkZElubGluZSAoc3RyLCB7IG5vV29yZFRyYW5zZm9ybSA9IGZhbHNlIH0gPSB7fSkge1xuICAgIGlmICghKFxuICAgICAgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgICApKSB7IHJldHVybjsgfVxuXG4gICAgaWYgKHRoaXMuX3N0YWNrSXRlbS5pc1ByZSkge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLnJhd1RleHQgKz0gc3RyO1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChcbiAgICAgIHN0ci5sZW5ndGggPT09IDAgfHwgLy8gZW1wdHkgc3RyaW5nXG4gICAgICAoXG4gICAgICAgIHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyAmJiAvLyBzdGFzaGVkIGxpbmVicmVha3MgbWFrZSB3aGl0ZXNwYWNlIGlycmVsZXZhbnRcbiAgICAgICAgIXRoaXMud2hpdGVzcGFjZVByb2Nlc3Nvci50ZXN0Q29udGFpbnNXb3JkcyhzdHIpIC8vIG5vIHdvcmRzIHRvIGFkZFxuICAgICAgKVxuICAgICkgeyByZXR1cm47IH1cblxuICAgIGlmICh0aGlzLm9wdGlvbnMucHJlc2VydmVOZXdsaW5lcykge1xuICAgICAgY29uc3QgbmV3bGluZXNOdW1iZXIgPSB0aGlzLndoaXRlc3BhY2VQcm9jZXNzb3IuY291bnROZXdsaW5lc05vV29yZHMoc3RyKTtcbiAgICAgIGlmIChuZXdsaW5lc051bWJlciA+IDApIHtcbiAgICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZShuZXdsaW5lc051bWJlcik7XG4gICAgICAgIC8vIGtlZXAgc3Rhc2hlZExpbmVCcmVha3MgdW5jaGFuZ2VkXG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAodGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuc3RhcnROZXdMaW5lKHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcyk7XG4gICAgfVxuICAgIHRoaXMud2hpdGVzcGFjZVByb2Nlc3Nvci5zaHJpbmtXcmFwQWRkKFxuICAgICAgc3RyLFxuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLFxuICAgICAgKG5vV29yZFRyYW5zZm9ybSkgPyB1bmRlZmluZWQgOiB0aGlzLl9nZXRDb21iaW5lZFdvcmRUcmFuc2Zvcm1lcigpLFxuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlzTm9XcmFwXG4gICAgKTtcbiAgICB0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MgPSAwOyAvLyBpbmxpbmUgdGV4dCBkb2Vzbid0IGludHJvZHVjZSBsaW5lIGJyZWFrc1xuICB9XG5cbiAgLyoqXG4gICAqIEFkZCBhIHN0cmluZyBpbmxpbmUgaW50byB0aGUgY3VycmVudGx5IGJ1aWx0IGJsb2NrLlxuICAgKlxuICAgKiBVc2UgdGhpcyBmb3IgbWFya3VwIGVsZW1lbnRzIHRoYXQgZG9uJ3QgaGF2ZSB0byBhZGhlcmVcbiAgICogdG8gdGV4dCBsYXlvdXQgcnVsZXMuXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9IHN0ciBUZXh0IHRvIGFkZC5cbiAgICovXG4gIGFkZExpdGVyYWwgKHN0cikge1xuICAgIGlmICghKFxuICAgICAgdGhpcy5fc3RhY2tJdGVtIGluc3RhbmNlb2YgQmxvY2tTdGFja0l0ZW1cbiAgICAgIHx8IHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgICB8fCB0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgICApKSB7IHJldHVybjsgfVxuXG4gICAgaWYgKHN0ci5sZW5ndGggPT09IDApIHsgcmV0dXJuOyB9XG5cbiAgICBpZiAodGhpcy5fc3RhY2tJdGVtLmlzUHJlKSB7XG4gICAgICB0aGlzLl9zdGFja0l0ZW0ucmF3VGV4dCArPSBzdHI7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX3N0YWNrSXRlbS5zdGFzaGVkTGluZUJyZWFrcykge1xuICAgICAgdGhpcy5fc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLnN0YXJ0TmV3TGluZSh0aGlzLl9zdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MpO1xuICAgIH1cbiAgICB0aGlzLndoaXRlc3BhY2VQcm9jZXNzb3IuYWRkTGl0ZXJhbChcbiAgICAgIHN0cixcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pbmxpbmVUZXh0QnVpbGRlcixcbiAgICAgIHRoaXMuX3N0YWNrSXRlbS5pc05vV3JhcFxuICAgICk7XG4gICAgdGhpcy5fc3RhY2tJdGVtLnN0YXNoZWRMaW5lQnJlYWtzID0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBTdGFydCBidWlsZGluZyBhIG5ldyBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMF1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLmxlYWRpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIGJsb2NrIHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGl0IGZyb20gYW55IHByZWNlZGluZyBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gIFtwYXJhbTAucmVzZXJ2ZWRMaW5lTGVuZ3RoXVxuICAgKiBSZXNlcnZlIHRoaXMgbnVtYmVyIG9mIGNoYXJhY3RlcnMgb24gZWFjaCBsaW5lIGZvciBibG9jayBtYXJrdXAuXG4gICAqXG4gICAqIEBwYXJhbSB7IGJvb2xlYW4gfSBbcGFyYW0wLmlzUHJlXVxuICAgKiBTaG91bGQgSFRNTCB3aGl0ZXNwYWNlIGJlIHByZXNlcnZlZCBpbnNpZGUgdGhpcyBibG9jay5cbiAgICovXG4gIG9wZW5CbG9jayAoeyBsZWFkaW5nTGluZUJyZWFrcyA9IDEsIHJlc2VydmVkTGluZUxlbmd0aCA9IDAsIGlzUHJlID0gZmFsc2UgfSA9IHt9KSB7XG4gICAgY29uc3QgbWF4TGluZUxlbmd0aCA9IE1hdGgubWF4KDIwLCB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIubWF4TGluZUxlbmd0aCAtIHJlc2VydmVkTGluZUxlbmd0aCk7XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IEJsb2NrU3RhY2tJdGVtKFxuICAgICAgdGhpcy5vcHRpb25zLFxuICAgICAgdGhpcy5fc3RhY2tJdGVtLFxuICAgICAgbGVhZGluZ0xpbmVCcmVha3MsXG4gICAgICBtYXhMaW5lTGVuZ3RoXG4gICAgKTtcbiAgICBpZiAoaXNQcmUpIHsgdGhpcy5fc3RhY2tJdGVtLmlzUHJlID0gdHJ1ZTsgfVxuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCBibG9jaywgYWRkIGl0J3MgY29udGVudCB0byB0aGUgcGFyZW50IGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0wXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgYmxvY2suXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAudHJhaWxpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIGJsb2NrIHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGl0IGZyb20gYW55IGZvbGxvd2luZyBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgKHN0cjogc3RyaW5nKSA9PiBzdHJpbmcgfSBbcGFyYW0wLmJsb2NrVHJhbnNmb3JtXVxuICAgKiBBIGZ1bmN0aW9uIHRvIHRyYW5zZm9ybSB0aGUgYmxvY2sgdGV4dCBiZWZvcmUgYWRkaW5nIHRvIHRoZSBwYXJlbnQgYmxvY2suXG4gICAqIFRoaXMgaGFwcGVucyBhZnRlciB3b3JkIHdyYXAgYW5kIHNob3VsZCBiZSB1c2VkIGluIGNvbWJpbmF0aW9uIHdpdGggcmVzZXJ2ZWQgbGluZSBsZW5ndGhcbiAgICogaW4gb3JkZXIgdG8ga2VlcCBsaW5lIGxlbmd0aHMgY29ycmVjdC5cbiAgICogVXNlZCBmb3Igd2hvbGUgYmxvY2sgbWFya3VwLlxuICAgKi9cbiAgY2xvc2VCbG9jayAoeyB0cmFpbGluZ0xpbmVCcmVha3MgPSAxLCBibG9ja1RyYW5zZm9ybSA9IHVuZGVmaW5lZCB9ID0ge30pIHtcbiAgICBjb25zdCBibG9jayA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIGNvbnN0IGJsb2NrVGV4dCA9IChibG9ja1RyYW5zZm9ybSkgPyBibG9ja1RyYW5zZm9ybShnZXRUZXh0KGJsb2NrKSkgOiBnZXRUZXh0KGJsb2NrKTtcbiAgICBhZGRUZXh0KHRoaXMuX3N0YWNrSXRlbSwgYmxvY2tUZXh0LCBibG9jay5sZWFkaW5nTGluZUJyZWFrcywgTWF0aC5tYXgoYmxvY2suc3Rhc2hlZExpbmVCcmVha3MsIHRyYWlsaW5nTGluZUJyZWFrcykpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgbmV3IGxpc3QuXG4gICAqXG4gICAqIEBwYXJhbSB7IG9iamVjdCB9IFtwYXJhbTBdXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBsaXN0LlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLm1heFByZWZpeExlbmd0aF1cbiAgICogTGVuZ3RoIG9mIHRoZSBsb25nZXN0IGxpc3QgaXRlbSBwcmVmaXguXG4gICAqIElmIG5vdCBzdXBwbGllZCBvciB0b28gc21hbGwgdGhlbiBsaXN0IGl0ZW1zIHdvbid0IGJlIGFsaWduZWQgcHJvcGVybHkuXG4gICAqXG4gICAqIEBwYXJhbSB7ICdsZWZ0JyB8ICdyaWdodCcgfSBbcGFyYW0wLnByZWZpeEFsaWduXVxuICAgKiBTcGVjaWZ5IGhvdyBwcmVmaXhlcyBvZiBkaWZmZXJlbnQgbGVuZ3RocyBoYXZlIHRvIGJlIGFsaWduZWRcbiAgICogd2l0aGluIGEgY29sdW1uLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLmludGVyUm93TGluZUJyZWFrc11cbiAgICogTWluaW11bSBudW1iZXIgb2YgbGluZSBicmVha3MgYmV0d2VlbiBsaXN0IGl0ZW1zLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLmxlYWRpbmdMaW5lQnJlYWtzXVxuICAgKiBUaGlzIGxpc3Qgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaXQgZnJvbSBhbnkgcHJlY2VkaW5nIGJsb2NrLlxuICAgKi9cbiAgb3Blbkxpc3QgKHsgbWF4UHJlZml4TGVuZ3RoID0gMCwgcHJlZml4QWxpZ24gPSAnbGVmdCcsIGludGVyUm93TGluZUJyZWFrcyA9IDEsIGxlYWRpbmdMaW5lQnJlYWtzID0gMiB9ID0ge30pIHtcbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgTGlzdFN0YWNrSXRlbSh0aGlzLm9wdGlvbnMsIHRoaXMuX3N0YWNrSXRlbSwge1xuICAgICAgaW50ZXJSb3dMaW5lQnJlYWtzOiBpbnRlclJvd0xpbmVCcmVha3MsXG4gICAgICBsZWFkaW5nTGluZUJyZWFrczogbGVhZGluZ0xpbmVCcmVha3MsXG4gICAgICBtYXhMaW5lTGVuZ3RoOiB0aGlzLl9zdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIubWF4TGluZUxlbmd0aCxcbiAgICAgIG1heFByZWZpeExlbmd0aDogbWF4UHJlZml4TGVuZ3RoLFxuICAgICAgcHJlZml4QWxpZ246IHByZWZpeEFsaWduXG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogU3RhcnQgYnVpbGRpbmcgYSBuZXcgbGlzdCBpdGVtLlxuICAgKlxuICAgKiBAcGFyYW0ge29iamVjdH0gcGFyYW0wXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBsaXN0IGl0ZW0uXG4gICAqXG4gICAqIEBwYXJhbSB7IHN0cmluZyB9IFtwYXJhbTAucHJlZml4XVxuICAgKiBQcmVmaXggZm9yIHRoaXMgbGlzdCBpdGVtIChpdGVtIG51bWJlciwgYnVsbGV0IHBvaW50LCBldGMpLlxuICAgKi9cbiAgb3Blbkxpc3RJdGVtICh7IHByZWZpeCA9ICcnIH0gPSB7fSkge1xuICAgIGlmICghKHRoaXMuX3N0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RTdGFja0l0ZW0pKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0NhblxcJ3QgYWRkIGEgbGlzdCBpdGVtIHRvIHNvbWV0aGluZyB0aGF0IGlzIG5vdCBhIGxpc3QhIENoZWNrIHRoZSBmb3JtYXR0ZXIuJyk7XG4gICAgfVxuICAgIGNvbnN0IGxpc3QgPSB0aGlzLl9zdGFja0l0ZW07XG4gICAgY29uc3QgcHJlZml4TGVuZ3RoID0gTWF0aC5tYXgocHJlZml4Lmxlbmd0aCwgbGlzdC5tYXhQcmVmaXhMZW5ndGgpO1xuICAgIGNvbnN0IG1heExpbmVMZW5ndGggPSBNYXRoLm1heCgyMCwgbGlzdC5pbmxpbmVUZXh0QnVpbGRlci5tYXhMaW5lTGVuZ3RoIC0gcHJlZml4TGVuZ3RoKTtcbiAgICB0aGlzLl9zdGFja0l0ZW0gPSBuZXcgTGlzdEl0ZW1TdGFja0l0ZW0odGhpcy5vcHRpb25zLCBsaXN0LCB7XG4gICAgICBwcmVmaXg6IHByZWZpeCxcbiAgICAgIG1heExpbmVMZW5ndGg6IG1heExpbmVMZW5ndGgsXG4gICAgICBsZWFkaW5nTGluZUJyZWFrczogbGlzdC5pbnRlclJvd0xpbmVCcmVha3NcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgbGlzdCBpdGVtLCBhZGQgaXQncyBjb250ZW50IHRvIHRoZSBwYXJlbnQgbGlzdC5cbiAgICovXG4gIGNsb3NlTGlzdEl0ZW0gKCkge1xuICAgIGNvbnN0IGxpc3RJdGVtID0gdGhpcy5fcG9wU3RhY2tJdGVtKCk7XG4gICAgY29uc3QgbGlzdCA9IGxpc3RJdGVtLm5leHQ7XG5cbiAgICBjb25zdCBwcmVmaXhMZW5ndGggPSBNYXRoLm1heChsaXN0SXRlbS5wcmVmaXgubGVuZ3RoLCBsaXN0Lm1heFByZWZpeExlbmd0aCk7XG4gICAgY29uc3Qgc3BhY2luZyA9ICdcXG4nICsgJyAnLnJlcGVhdChwcmVmaXhMZW5ndGgpO1xuICAgIGNvbnN0IHByZWZpeCA9IChsaXN0LnByZWZpeEFsaWduID09PSAncmlnaHQnKVxuICAgICAgPyBsaXN0SXRlbS5wcmVmaXgucGFkU3RhcnQocHJlZml4TGVuZ3RoKVxuICAgICAgOiBsaXN0SXRlbS5wcmVmaXgucGFkRW5kKHByZWZpeExlbmd0aCk7XG4gICAgY29uc3QgdGV4dCA9IHByZWZpeCArIGdldFRleHQobGlzdEl0ZW0pLnJlcGxhY2UoL1xcbi9nLCBzcGFjaW5nKTtcblxuICAgIGFkZFRleHQoXG4gICAgICBsaXN0LFxuICAgICAgdGV4dCxcbiAgICAgIGxpc3RJdGVtLmxlYWRpbmdMaW5lQnJlYWtzLFxuICAgICAgTWF0aC5tYXgobGlzdEl0ZW0uc3Rhc2hlZExpbmVCcmVha3MsIGxpc3QuaW50ZXJSb3dMaW5lQnJlYWtzKVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IGxpc3QsIGFkZCBpdCdzIGNvbnRlbnQgdG8gdGhlIHBhcmVudCBibG9jay5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gcGFyYW0wXG4gICAqIE9iamVjdCBob2xkaW5nIHRoZSBwYXJhbWV0ZXJzIG9mIHRoZSBsaXN0LlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLnRyYWlsaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyBsaXN0IHNob3VsZCBoYXZlIGF0IGxlYXN0IHRoaXMgbnVtYmVyIG9mIGxpbmUgYnJlYWtzIHRvIHNlcGFyYXRlIGl0IGZyb20gYW55IGZvbGxvd2luZyBibG9jay5cbiAgICovXG4gIGNsb3NlTGlzdCAoeyB0cmFpbGluZ0xpbmVCcmVha3MgPSAyIH0gPSB7fSkge1xuICAgIGNvbnN0IGxpc3QgPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICBjb25zdCB0ZXh0ID0gZ2V0VGV4dChsaXN0KTtcbiAgICBpZiAodGV4dCkge1xuICAgICAgYWRkVGV4dCh0aGlzLl9zdGFja0l0ZW0sIHRleHQsIGxpc3QubGVhZGluZ0xpbmVCcmVha3MsIHRyYWlsaW5nTGluZUJyZWFrcyk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgdGFibGUuXG4gICAqL1xuICBvcGVuVGFibGUgKCkge1xuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBUYWJsZVN0YWNrSXRlbSh0aGlzLl9zdGFja0l0ZW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgdGFibGUgcm93LlxuICAgKi9cbiAgb3BlblRhYmxlUm93ICgpIHtcbiAgICBpZiAoISh0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZVN0YWNrSXRlbSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2FuXFwndCBhZGQgYSB0YWJsZSByb3cgdG8gc29tZXRoaW5nIHRoYXQgaXMgbm90IGEgdGFibGUhIENoZWNrIHRoZSBmb3JtYXR0ZXIuJyk7XG4gICAgfVxuICAgIHRoaXMuX3N0YWNrSXRlbSA9IG5ldyBUYWJsZVJvd1N0YWNrSXRlbSh0aGlzLl9zdGFja0l0ZW0pO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0YXJ0IGJ1aWxkaW5nIGEgdGFibGUgY2VsbC5cbiAgICpcbiAgICogQHBhcmFtIHsgb2JqZWN0IH0gW3BhcmFtMF1cbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIGNlbGwuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAubWF4Q29sdW1uV2lkdGhdXG4gICAqIFdyYXAgY2VsbCBjb250ZW50IHRvIHRoaXMgd2lkdGguIEZhbGwgYmFjayB0byBnbG9iYWwgd29yZHdyYXAgdmFsdWUgaWYgdW5kZWZpbmVkLlxuICAgKi9cbiAgb3BlblRhYmxlQ2VsbCAoeyBtYXhDb2x1bW5XaWR0aCA9IHVuZGVmaW5lZCB9ID0ge30pIHtcbiAgICBpZiAoISh0aGlzLl9zdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZVJvd1N0YWNrSXRlbSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignQ2FuXFwndCBhZGQgYSB0YWJsZSBjZWxsIHRvIHNvbWV0aGluZyB0aGF0IGlzIG5vdCBhIHRhYmxlIHJvdyEgQ2hlY2sgdGhlIGZvcm1hdHRlci4nKTtcbiAgICB9XG4gICAgdGhpcy5fc3RhY2tJdGVtID0gbmV3IFRhYmxlQ2VsbFN0YWNrSXRlbSh0aGlzLm9wdGlvbnMsIHRoaXMuX3N0YWNrSXRlbSwgbWF4Q29sdW1uV2lkdGgpO1xuICB9XG5cbiAgLyoqXG4gICAqIEZpbmFsaXplIGN1cnJlbnRseSBidWlsdCB0YWJsZSBjZWxsIGFuZCBhZGQgaXQgdG8gcGFyZW50IHRhYmxlIHJvdydzIGNlbGxzLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBbcGFyYW0wXVxuICAgKiBPYmplY3QgaG9sZGluZyB0aGUgcGFyYW1ldGVycyBvZiB0aGUgY2VsbC5cbiAgICpcbiAgICogQHBhcmFtIHsgbnVtYmVyIH0gW3BhcmFtMC5jb2xzcGFuXSBIb3cgbWFueSBjb2x1bW5zIHRoaXMgY2VsbCBzaG91bGQgb2NjdXB5LlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLnJvd3NwYW5dIEhvdyBtYW55IHJvd3MgdGhpcyBjZWxsIHNob3VsZCBvY2N1cHkuXG4gICAqL1xuICBjbG9zZVRhYmxlQ2VsbCAoeyBjb2xzcGFuID0gMSwgcm93c3BhbiA9IDEgfSA9IHt9KSB7XG4gICAgY29uc3QgY2VsbCA9IHRoaXMuX3BvcFN0YWNrSXRlbSgpO1xuICAgIGNvbnN0IHRleHQgPSB0cmltQ2hhcmFjdGVyKGdldFRleHQoY2VsbCksICdcXG4nKTtcbiAgICBjZWxsLm5leHQuY2VsbHMucHVzaCh7IGNvbHNwYW46IGNvbHNwYW4sIHJvd3NwYW46IHJvd3NwYW4sIHRleHQ6IHRleHQgfSk7XG4gIH1cblxuICAvKipcbiAgICogRmluYWxpemUgY3VycmVudGx5IGJ1aWx0IHRhYmxlIHJvdyBhbmQgYWRkIGl0IHRvIHBhcmVudCB0YWJsZSdzIHJvd3MuXG4gICAqL1xuICBjbG9zZVRhYmxlUm93ICgpIHtcbiAgICBjb25zdCByb3cgPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICByb3cubmV4dC5yb3dzLnB1c2gocm93LmNlbGxzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBGaW5hbGl6ZSBjdXJyZW50bHkgYnVpbHQgdGFibGUgYW5kIGFkZCB0aGUgcmVuZGVyZWQgdGV4dCB0byB0aGUgcGFyZW50IGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBvYmplY3QgfSBwYXJhbTBcbiAgICogT2JqZWN0IGhvbGRpbmcgdGhlIHBhcmFtZXRlcnMgb2YgdGhlIHRhYmxlLlxuICAgKlxuICAgKiBAcGFyYW0geyBUYWJsZVByaW50ZXIgfSBwYXJhbTAudGFibGVUb1N0cmluZ1xuICAgKiBBIGZ1bmN0aW9uIHRvIGNvbnZlcnQgYSB0YWJsZSBvZiBzdHJpbmdpZmllZCBjZWxscyBpbnRvIGEgY29tcGxldGUgdGFibGUuXG4gICAqXG4gICAqIEBwYXJhbSB7IG51bWJlciB9IFtwYXJhbTAubGVhZGluZ0xpbmVCcmVha3NdXG4gICAqIFRoaXMgdGFibGUgc2hvdWxkIGhhdmUgYXQgbGVhc3QgdGhpcyBudW1iZXIgb2YgbGluZSBicmVha3MgdG8gc2VwYXJhdGUgaWYgZnJvbSBhbnkgcHJlY2VkaW5nIGJsb2NrLlxuICAgKlxuICAgKiBAcGFyYW0geyBudW1iZXIgfSBbcGFyYW0wLnRyYWlsaW5nTGluZUJyZWFrc11cbiAgICogVGhpcyB0YWJsZSBzaG91bGQgaGF2ZSBhdCBsZWFzdCB0aGlzIG51bWJlciBvZiBsaW5lIGJyZWFrcyB0byBzZXBhcmF0ZSBpdCBmcm9tIGFueSBmb2xsb3dpbmcgYmxvY2suXG4gICAqL1xuICBjbG9zZVRhYmxlICh7IHRhYmxlVG9TdHJpbmcsIGxlYWRpbmdMaW5lQnJlYWtzID0gMiwgdHJhaWxpbmdMaW5lQnJlYWtzID0gMiB9KSB7XG4gICAgY29uc3QgdGFibGUgPSB0aGlzLl9wb3BTdGFja0l0ZW0oKTtcbiAgICBjb25zdCBvdXRwdXQgPSB0YWJsZVRvU3RyaW5nKHRhYmxlLnJvd3MpO1xuICAgIGlmIChvdXRwdXQpIHtcbiAgICAgIGFkZFRleHQodGhpcy5fc3RhY2tJdGVtLCBvdXRwdXQsIGxlYWRpbmdMaW5lQnJlYWtzLCB0cmFpbGluZ0xpbmVCcmVha3MpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm4gdGhlIHJlbmRlcmVkIHRleHQgY29udGVudCBvZiB0aGlzIGJ1aWxkZXIuXG4gICAqXG4gICAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAgICovXG4gIHRvU3RyaW5nICgpIHtcbiAgICByZXR1cm4gZ2V0VGV4dCh0aGlzLl9zdGFja0l0ZW0uZ2V0Um9vdCgpKTtcbiAgICAvLyBUaGVyZSBzaG91bGQgb25seSBiZSB0aGUgcm9vdCBpdGVtIGlmIGV2ZXJ5dGhpbmcgaXMgY2xvc2VkIHByb3Blcmx5LlxuICB9XG5cbn1cblxuZnVuY3Rpb24gZ2V0VGV4dCAoc3RhY2tJdGVtKSB7XG4gIGlmICghKFxuICAgIHN0YWNrSXRlbSBpbnN0YW5jZW9mIEJsb2NrU3RhY2tJdGVtXG4gICAgfHwgc3RhY2tJdGVtIGluc3RhbmNlb2YgTGlzdEl0ZW1TdGFja0l0ZW1cbiAgICB8fCBzdGFja0l0ZW0gaW5zdGFuY2VvZiBUYWJsZUNlbGxTdGFja0l0ZW1cbiAgKSkge1xuICAgIHRocm93IG5ldyBFcnJvcignT25seSBibG9ja3MsIGxpc3QgaXRlbXMgYW5kIHRhYmxlIGNlbGxzIGNhbiBiZSByZXF1ZXN0ZWQgZm9yIHRleHQgY29udGVudHMuJyk7XG4gIH1cbiAgcmV0dXJuIChzdGFja0l0ZW0uaW5saW5lVGV4dEJ1aWxkZXIuaXNFbXB0eSgpKVxuICAgID8gc3RhY2tJdGVtLnJhd1RleHRcbiAgICA6IHN0YWNrSXRlbS5yYXdUZXh0ICsgc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLnRvU3RyaW5nKCk7XG59XG5cbmZ1bmN0aW9uIGFkZFRleHQgKHN0YWNrSXRlbSwgdGV4dCwgbGVhZGluZ0xpbmVCcmVha3MsIHRyYWlsaW5nTGluZUJyZWFrcykge1xuICBpZiAoIShcbiAgICBzdGFja0l0ZW0gaW5zdGFuY2VvZiBCbG9ja1N0YWNrSXRlbVxuICAgIHx8IHN0YWNrSXRlbSBpbnN0YW5jZW9mIExpc3RJdGVtU3RhY2tJdGVtXG4gICAgfHwgc3RhY2tJdGVtIGluc3RhbmNlb2YgVGFibGVDZWxsU3RhY2tJdGVtXG4gICkpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ09ubHkgYmxvY2tzLCBsaXN0IGl0ZW1zIGFuZCB0YWJsZSBjZWxscyBjYW4gY29udGFpbiB0ZXh0LicpO1xuICB9XG4gIGNvbnN0IHBhcmVudFRleHQgPSBnZXRUZXh0KHN0YWNrSXRlbSk7XG4gIGNvbnN0IGxpbmVCcmVha3MgPSBNYXRoLm1heChzdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MsIGxlYWRpbmdMaW5lQnJlYWtzKTtcbiAgc3RhY2tJdGVtLmlubGluZVRleHRCdWlsZGVyLmNsZWFyKCk7XG4gIGlmIChwYXJlbnRUZXh0KSB7XG4gICAgc3RhY2tJdGVtLnJhd1RleHQgPSBwYXJlbnRUZXh0ICsgJ1xcbicucmVwZWF0KGxpbmVCcmVha3MpICsgdGV4dDtcbiAgfSBlbHNlIHtcbiAgICBzdGFja0l0ZW0ucmF3VGV4dCA9IHRleHQ7XG4gICAgc3RhY2tJdGVtLmxlYWRpbmdMaW5lQnJlYWtzID0gbGluZUJyZWFrcztcbiAgfVxuICBzdGFja0l0ZW0uc3Rhc2hlZExpbmVCcmVha3MgPSB0cmFpbGluZ0xpbmVCcmVha3M7XG59XG5cbi8qKlxuICogQHBhcmFtIHsgc3RyaW5nIH0gc3RyIEEgc3RyaW5nIHRvIHRyYW5zZm9ybS5cbiAqIEBwYXJhbSB7IFRyYW5zZm9ybWVyU3RhY2tJdGVtIH0gdHJhbnNmb3JtZXIgQSB0cmFuc2Zvcm1lciBpdGVtICh3aXRoIHBvc3NpYmxlIGNvbnRpbnVhdGlvbikuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIGFwcGx5VHJhbnNmb3JtZXIgKHN0ciwgdHJhbnNmb3JtZXIpIHtcbiAgcmV0dXJuICgodHJhbnNmb3JtZXIpID8gYXBwbHlUcmFuc2Zvcm1lcih0cmFuc2Zvcm1lci50cmFuc2Zvcm0oc3RyKSwgdHJhbnNmb3JtZXIubmV4dCkgOiBzdHIpO1xufVxuXG4vKipcbiAqIENvbXBpbGUgc2VsZWN0b3JzIGludG8gYSBkZWNpc2lvbiB0cmVlLFxuICogcmV0dXJuIGEgZnVuY3Rpb24gaW50ZW5kZWQgZm9yIGJhdGNoIHByb2Nlc3NpbmcuXG4gKlxuICogQHBhcmFtICAgeyBPcHRpb25zIH0gW29wdGlvbnMgPSB7fV0gICBIdG1sVG9UZXh0IG9wdGlvbnMgKGRlZmF1bHRzLCBmb3JtYXR0ZXJzLCB1c2VyIG9wdGlvbnMgbWVyZ2VkLCBkZWR1cGxpY2F0ZWQpLlxuICogQHJldHVybnMgeyAoaHRtbDogc3RyaW5nLCBtZXRhZGF0YT86IGFueSkgPT4gc3RyaW5nIH0gUHJlLWNvbmZpZ3VyZWQgY29udmVydGVyIGZ1bmN0aW9uLlxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBjb21waWxlJDEgKG9wdGlvbnMgPSB7fSkge1xuICBjb25zdCBzZWxlY3RvcnNXaXRob3V0Rm9ybWF0ID0gb3B0aW9ucy5zZWxlY3RvcnMuZmlsdGVyKHMgPT4gIXMuZm9ybWF0KTtcbiAgaWYgKHNlbGVjdG9yc1dpdGhvdXRGb3JtYXQubGVuZ3RoKSB7XG4gICAgdGhyb3cgbmV3IEVycm9yKFxuICAgICAgJ0ZvbGxvd2luZyBzZWxlY3RvcnMgaGF2ZSBubyBzcGVjaWZpZWQgZm9ybWF0OiAnICtcbiAgICAgIHNlbGVjdG9yc1dpdGhvdXRGb3JtYXQubWFwKHMgPT4gYFxcYCR7cy5zZWxlY3Rvcn1cXGBgKS5qb2luKCcsICcpXG4gICAgKTtcbiAgfVxuICBjb25zdCBwaWNrZXIgPSBuZXcgRGVjaXNpb25UcmVlKFxuICAgIG9wdGlvbnMuc2VsZWN0b3JzLm1hcChzID0+IFtzLnNlbGVjdG9yLCBzXSlcbiAgKS5idWlsZChocDJCdWlsZGVyKTtcblxuICBpZiAodHlwZW9mIG9wdGlvbnMuZW5jb2RlQ2hhcmFjdGVycyAhPT0gJ2Z1bmN0aW9uJykge1xuICAgIG9wdGlvbnMuZW5jb2RlQ2hhcmFjdGVycyA9IG1ha2VSZXBsYWNlckZyb21EaWN0KG9wdGlvbnMuZW5jb2RlQ2hhcmFjdGVycyk7XG4gIH1cblxuICBjb25zdCBiYXNlU2VsZWN0b3JzUGlja2VyID0gbmV3IERlY2lzaW9uVHJlZShcbiAgICBvcHRpb25zLmJhc2VFbGVtZW50cy5zZWxlY3RvcnMubWFwKChzLCBpKSA9PiBbcywgaSArIDFdKVxuICApLmJ1aWxkKGhwMkJ1aWxkZXIpO1xuICBmdW5jdGlvbiBmaW5kQmFzZUVsZW1lbnRzIChkb20pIHtcbiAgICByZXR1cm4gZmluZEJhc2VzKGRvbSwgb3B0aW9ucywgYmFzZVNlbGVjdG9yc1BpY2tlcik7XG4gIH1cblxuICBjb25zdCBsaW1pdGVkV2FsayA9IGxpbWl0ZWREZXB0aFJlY3Vyc2l2ZShcbiAgICBvcHRpb25zLmxpbWl0cy5tYXhEZXB0aCxcbiAgICByZWN1cnNpdmVXYWxrLFxuICAgIGZ1bmN0aW9uIChkb20sIGJ1aWxkZXIpIHtcbiAgICAgIGJ1aWxkZXIuYWRkSW5saW5lKG9wdGlvbnMubGltaXRzLmVsbGlwc2lzIHx8ICcnKTtcbiAgICB9XG4gICk7XG5cbiAgcmV0dXJuIGZ1bmN0aW9uIChodG1sLCBtZXRhZGF0YSA9IHVuZGVmaW5lZCkge1xuICAgIHJldHVybiBwcm9jZXNzKGh0bWwsIG1ldGFkYXRhLCBvcHRpb25zLCBwaWNrZXIsIGZpbmRCYXNlRWxlbWVudHMsIGxpbWl0ZWRXYWxrKTtcbiAgfTtcbn1cblxuXG4vKipcbiAqIENvbnZlcnQgZ2l2ZW4gSFRNTCBhY2NvcmRpbmcgdG8gcHJlcHJvY2Vzc2VkIG9wdGlvbnMuXG4gKlxuICogQHBhcmFtIHsgc3RyaW5nIH0gaHRtbCBIVE1MIGNvbnRlbnQgdG8gY29udmVydC5cbiAqIEBwYXJhbSB7IGFueSB9IG1ldGFkYXRhIE9wdGlvbmFsIG1ldGFkYXRhIGZvciBIVE1MIGRvY3VtZW50LCBmb3IgdXNlIGluIGZvcm1hdHRlcnMuXG4gKiBAcGFyYW0geyBPcHRpb25zIH0gb3B0aW9ucyBIdG1sVG9UZXh0IG9wdGlvbnMgKHByZXByb2Nlc3NlZCkuXG4gKiBAcGFyYW0geyBpbXBvcnQoJ3NlbGRlcmVlJykuUGlja2VyPERvbU5vZGUsIFRhZ0RlZmluaXRpb24+IH0gcGlja2VyXG4gKiBUYWcgZGVmaW5pdGlvbiBwaWNrZXIgZm9yIERPTSBub2RlcyBwcm9jZXNzaW5nLlxuICogQHBhcmFtIHsgKGRvbTogRG9tTm9kZVtdKSA9PiBEb21Ob2RlW10gfSBmaW5kQmFzZUVsZW1lbnRzXG4gKiBGdW5jdGlvbiB0byBleHRyYWN0IGVsZW1lbnRzIGZyb20gSFRNTCBET01cbiAqIHRoYXQgd2lsbCBvbmx5IGJlIHByZXNlbnQgaW4gdGhlIG91dHB1dCB0ZXh0LlxuICogQHBhcmFtIHsgUmVjdXJzaXZlQ2FsbGJhY2sgfSB3YWxrIFJlY3Vyc2l2ZSBjYWxsYmFjay5cbiAqIEByZXR1cm5zIHsgc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gcHJvY2VzcyAoaHRtbCwgbWV0YWRhdGEsIG9wdGlvbnMsIHBpY2tlciwgZmluZEJhc2VFbGVtZW50cywgd2Fsaykge1xuICBjb25zdCBtYXhJbnB1dExlbmd0aCA9IG9wdGlvbnMubGltaXRzLm1heElucHV0TGVuZ3RoO1xuICBpZiAobWF4SW5wdXRMZW5ndGggJiYgaHRtbCAmJiBodG1sLmxlbmd0aCA+IG1heElucHV0TGVuZ3RoKSB7XG4gICAgY29uc29sZS53YXJuKFxuICAgICAgYElucHV0IGxlbmd0aCAke2h0bWwubGVuZ3RofSBpcyBhYm92ZSBhbGxvd2VkIGxpbWl0IG9mICR7bWF4SW5wdXRMZW5ndGh9LiBUcnVuY2F0aW5nIHdpdGhvdXQgZWxsaXBzaXMuYFxuICAgICk7XG4gICAgaHRtbCA9IGh0bWwuc3Vic3RyaW5nKDAsIG1heElucHV0TGVuZ3RoKTtcbiAgfVxuXG4gIGNvbnN0IGRvY3VtZW50ID0gcGFyc2VEb2N1bWVudChodG1sLCB7IGRlY29kZUVudGl0aWVzOiBvcHRpb25zLmRlY29kZUVudGl0aWVzIH0pO1xuICBjb25zdCBiYXNlcyA9IGZpbmRCYXNlRWxlbWVudHMoZG9jdW1lbnQuY2hpbGRyZW4pO1xuICBjb25zdCBidWlsZGVyID0gbmV3IEJsb2NrVGV4dEJ1aWxkZXIob3B0aW9ucywgcGlja2VyLCBtZXRhZGF0YSk7XG4gIHdhbGsoYmFzZXMsIGJ1aWxkZXIpO1xuICByZXR1cm4gYnVpbGRlci50b1N0cmluZygpO1xufVxuXG5cbmZ1bmN0aW9uIGZpbmRCYXNlcyAoZG9tLCBvcHRpb25zLCBiYXNlU2VsZWN0b3JzUGlja2VyKSB7XG4gIGNvbnN0IHJlc3VsdHMgPSBbXTtcblxuICBmdW5jdGlvbiByZWN1cnNpdmVXYWxrICh3YWxrLCAvKiogQHR5cGUgeyBEb21Ob2RlW10gfSAqLyBkb20pIHtcbiAgICBkb20gPSBkb20uc2xpY2UoMCwgb3B0aW9ucy5saW1pdHMubWF4Q2hpbGROb2Rlcyk7XG4gICAgZm9yIChjb25zdCBlbGVtIG9mIGRvbSkge1xuICAgICAgaWYgKGVsZW0udHlwZSAhPT0gJ3RhZycpIHtcbiAgICAgICAgY29udGludWU7XG4gICAgICB9XG4gICAgICBjb25zdCBwaWNrZWRTZWxlY3RvckluZGV4ID0gYmFzZVNlbGVjdG9yc1BpY2tlci5waWNrMShlbGVtKTtcbiAgICAgIGlmIChwaWNrZWRTZWxlY3RvckluZGV4ID4gMCkge1xuICAgICAgICByZXN1bHRzLnB1c2goeyBzZWxlY3RvckluZGV4OiBwaWNrZWRTZWxlY3RvckluZGV4LCBlbGVtZW50OiBlbGVtIH0pO1xuICAgICAgfSBlbHNlIGlmIChlbGVtLmNoaWxkcmVuKSB7XG4gICAgICAgIHdhbGsoZWxlbS5jaGlsZHJlbik7XG4gICAgICB9XG4gICAgICBpZiAocmVzdWx0cy5sZW5ndGggPj0gb3B0aW9ucy5saW1pdHMubWF4QmFzZUVsZW1lbnRzKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBjb25zdCBsaW1pdGVkV2FsayA9IGxpbWl0ZWREZXB0aFJlY3Vyc2l2ZShcbiAgICBvcHRpb25zLmxpbWl0cy5tYXhEZXB0aCxcbiAgICByZWN1cnNpdmVXYWxrXG4gICk7XG4gIGxpbWl0ZWRXYWxrKGRvbSk7XG5cbiAgaWYgKG9wdGlvbnMuYmFzZUVsZW1lbnRzLm9yZGVyQnkgIT09ICdvY2N1cnJlbmNlJykgeyAvLyAnc2VsZWN0b3JzJ1xuICAgIHJlc3VsdHMuc29ydCgoYSwgYikgPT4gYS5zZWxlY3RvckluZGV4IC0gYi5zZWxlY3RvckluZGV4KTtcbiAgfVxuICByZXR1cm4gKG9wdGlvbnMuYmFzZUVsZW1lbnRzLnJldHVybkRvbUJ5RGVmYXVsdCAmJiByZXN1bHRzLmxlbmd0aCA9PT0gMClcbiAgICA/IGRvbVxuICAgIDogcmVzdWx0cy5tYXAoeCA9PiB4LmVsZW1lbnQpO1xufVxuXG4vKipcbiAqIEZ1bmN0aW9uIHRvIHdhbGsgdGhyb3VnaCBET00gbm9kZXMgYW5kIGFjY3VtdWxhdGUgdGhlaXIgc3RyaW5nIHJlcHJlc2VudGF0aW9ucy5cbiAqXG4gKiBAcGFyYW0gICB7IFJlY3Vyc2l2ZUNhbGxiYWNrIH0gd2FsayAgICBSZWN1cnNpdmUgY2FsbGJhY2suXG4gKiBAcGFyYW0gICB7IERvbU5vZGVbXSB9ICAgICAgICAgW2RvbV0gICBOb2RlcyBhcnJheSB0byBwcm9jZXNzLlxuICogQHBhcmFtICAgeyBCbG9ja1RleHRCdWlsZGVyIH0gIGJ1aWxkZXIgUGFzc2VkIGFyb3VuZCB0byBhY2N1bXVsYXRlIG91dHB1dCB0ZXh0LlxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gcmVjdXJzaXZlV2FsayAod2FsaywgZG9tLCBidWlsZGVyKSB7XG4gIGlmICghZG9tKSB7IHJldHVybjsgfVxuXG4gIGNvbnN0IG9wdGlvbnMgPSBidWlsZGVyLm9wdGlvbnM7XG5cbiAgY29uc3QgdG9vTWFueUNoaWxkTm9kZXMgPSBkb20ubGVuZ3RoID4gb3B0aW9ucy5saW1pdHMubWF4Q2hpbGROb2RlcztcbiAgaWYgKHRvb01hbnlDaGlsZE5vZGVzKSB7XG4gICAgZG9tID0gZG9tLnNsaWNlKDAsIG9wdGlvbnMubGltaXRzLm1heENoaWxkTm9kZXMpO1xuICAgIGRvbS5wdXNoKHtcbiAgICAgIGRhdGE6IG9wdGlvbnMubGltaXRzLmVsbGlwc2lzLFxuICAgICAgdHlwZTogJ3RleHQnXG4gICAgfSk7XG4gIH1cblxuICBmb3IgKGNvbnN0IGVsZW0gb2YgZG9tKSB7XG4gICAgc3dpdGNoIChlbGVtLnR5cGUpIHtcbiAgICAgIGNhc2UgJ3RleHQnOiB7XG4gICAgICAgIGJ1aWxkZXIuYWRkSW5saW5lKGVsZW0uZGF0YSk7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgY2FzZSAndGFnJzoge1xuICAgICAgICBjb25zdCB0YWdEZWZpbml0aW9uID0gYnVpbGRlci5waWNrZXIucGljazEoZWxlbSk7XG4gICAgICAgIGNvbnN0IGZvcm1hdCA9IG9wdGlvbnMuZm9ybWF0dGVyc1t0YWdEZWZpbml0aW9uLmZvcm1hdF07XG4gICAgICAgIGZvcm1hdChlbGVtLCB3YWxrLCBidWlsZGVyLCB0YWdEZWZpbml0aW9uLm9wdGlvbnMgfHwge30pO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm47XG59XG5cbi8qKlxuICogQHBhcmFtIHsgT2JqZWN0PHN0cmluZyxzdHJpbmcgfCBmYWxzZT4gfSBkaWN0XG4gKiBBIGRpY3Rpb25hcnkgd2hlcmUga2V5cyBhcmUgY2hhcmFjdGVycyB0byByZXBsYWNlXG4gKiBhbmQgdmFsdWVzIGFyZSByZXBsYWNlbWVudCBzdHJpbmdzLlxuICpcbiAqIEZpcnN0IGNvZGUgcG9pbnQgZnJvbSBkaWN0IGtleXMgaXMgdXNlZC5cbiAqIENvbXBvdW5kIGVtb2ppcyB3aXRoIFpXSiBhcmUgbm90IHN1cHBvcnRlZCAobm90IHVudGlsIE5vZGUgMTYpLlxuICpcbiAqIEByZXR1cm5zIHsgKChzdHI6IHN0cmluZykgPT4gc3RyaW5nKSB8IHVuZGVmaW5lZCB9XG4gKi9cbmZ1bmN0aW9uIG1ha2VSZXBsYWNlckZyb21EaWN0IChkaWN0KSB7XG4gIGlmICghZGljdCB8fCBPYmplY3Qua2V5cyhkaWN0KS5sZW5ndGggPT09IDApIHtcbiAgICByZXR1cm4gdW5kZWZpbmVkO1xuICB9XG4gIC8qKiBAdHlwZSB7IFtzdHJpbmcsIHN0cmluZ11bXSB9ICovXG4gIGNvbnN0IGVudHJpZXMgPSBPYmplY3QuZW50cmllcyhkaWN0KS5maWx0ZXIoKFssIHZdKSA9PiB2ICE9PSBmYWxzZSk7XG4gIGNvbnN0IHJlZ2V4ID0gbmV3IFJlZ0V4cChcbiAgICBlbnRyaWVzXG4gICAgICAubWFwKChbY10pID0+IGAoJHt1bmljb2RlRXNjYXBlKFsuLi5jXVswXSl9KWApXG4gICAgICAuam9pbignfCcpLFxuICAgICdnJ1xuICApO1xuICBjb25zdCB2YWx1ZXMgPSBlbnRyaWVzLm1hcCgoWywgdl0pID0+IHYpO1xuICBjb25zdCByZXBsYWNlciA9IChtLCAuLi5jZ3MpID0+IHZhbHVlc1tjZ3MuZmluZEluZGV4KGNnID0+IGNnKV07XG4gIHJldHVybiAoc3RyKSA9PiBzdHIucmVwbGFjZShyZWdleCwgcmVwbGFjZXIpO1xufVxuXG4vKipcbiAqIER1bW15IGZvcm1hdHRlciB0aGF0IGRpc2NhcmRzIHRoZSBpbnB1dCBhbmQgZG9lcyBub3RoaW5nLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRTa2lwIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIC8qIGRvIG5vdGhpbmcgKi9cbn1cblxuLyoqXG4gKiBJbnNlcnQgdGhlIGdpdmVuIHN0cmluZyBsaXRlcmFsIGlubGluZSBpbnN0ZWFkIG9mIGEgdGFnLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmVTdHJpbmcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKGZvcm1hdE9wdGlvbnMuc3RyaW5nIHx8ICcnKTtcbn1cblxuLyoqXG4gKiBJbnNlcnQgYSBibG9jayB3aXRoIHRoZSBnaXZlbiBzdHJpbmcgbGl0ZXJhbCBpbnN0ZWFkIG9mIGEgdGFnLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRCbG9ja1N0cmluZyAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLm9wZW5CbG9jayh7IGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChmb3JtYXRPcHRpb25zLnN0cmluZyB8fCAnJyk7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGFuIGlubGluZS1sZXZlbCBlbGVtZW50LlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgYmxvY2stbGV2ZWwgY29udGFpbmVyLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRCbG9jayQxIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xufVxuXG5mdW5jdGlvbiByZW5kZXJPcGVuVGFnIChlbGVtKSB7XG4gIGNvbnN0IGF0dHJzID0gKGVsZW0uYXR0cmlicyAmJiBlbGVtLmF0dHJpYnMubGVuZ3RoKVxuICAgID8gJyAnICsgT2JqZWN0LmVudHJpZXMoZWxlbS5hdHRyaWJzKVxuICAgICAgLm1hcCgoW2ssIHZdKSA9PiAoKHYgPT09ICcnKSA/IGsgOiBgJHtrfT0ke3YucmVwbGFjZSgvXCIvZywgJyZxdW90OycpfWApKVxuICAgICAgLmpvaW4oJyAnKVxuICAgIDogJyc7XG4gIHJldHVybiBgPCR7ZWxlbS5uYW1lfSR7YXR0cnN9PmA7XG59XG5cbmZ1bmN0aW9uIHJlbmRlckNsb3NlVGFnIChlbGVtKSB7XG4gIHJldHVybiBgPC8ke2VsZW0ubmFtZX0+YDtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYW4gZWxlbWVudCBhcyBpbmxpbmUgSFRNTCB0YWcsIHdhbGsgdGhyb3VnaCBpdCdzIGNoaWxkcmVuLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmVUYWcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5zdGFydE5vV3JhcCgpO1xuICBidWlsZGVyLmFkZExpdGVyYWwocmVuZGVyT3BlblRhZyhlbGVtKSk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChyZW5kZXJDbG9zZVRhZyhlbGVtKSk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xufVxuXG4vKipcbiAqIFJlbmRlciBhbiBlbGVtZW50IGFzIEhUTUwgYmxvY2sgYmFnLCB3YWxrIHRocm91Z2ggaXQncyBjaGlsZHJlbi5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QmxvY2tUYWcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChyZW5kZXJPcGVuVGFnKGVsZW0pKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG4gIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIGJ1aWxkZXIuc3RhcnROb1dyYXAoKTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKHJlbmRlckNsb3NlVGFnKGVsZW0pKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG4gIGJ1aWxkZXIuY2xvc2VCbG9jayh7IHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYW4gZWxlbWVudCB3aXRoIGFsbCBpdCdzIGNoaWxkcmVuIGFzIGlubGluZSBIVE1MLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmVIdG1sIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuc3RhcnROb1dyYXAoKTtcbiAgYnVpbGRlci5hZGRMaXRlcmFsKFxuICAgIHJlbmRlcihlbGVtLCB7IGRlY29kZUVudGl0aWVzOiBidWlsZGVyLm9wdGlvbnMuZGVjb2RlRW50aXRpZXMgfSlcbiAgKTtcbiAgYnVpbGRlci5zdG9wTm9XcmFwKCk7XG59XG5cbi8qKlxuICogUmVuZGVyIGFuIGVsZW1lbnQgd2l0aCBhbGwgaXQncyBjaGlsZHJlbiBhcyBIVE1MIGJsb2NrLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRCbG9ja0h0bWwgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLnN0YXJ0Tm9XcmFwKCk7XG4gIGJ1aWxkZXIuYWRkTGl0ZXJhbChcbiAgICByZW5kZXIoZWxlbSwgeyBkZWNvZGVFbnRpdGllczogYnVpbGRlci5vcHRpb25zLmRlY29kZUVudGl0aWVzIH0pXG4gICk7XG4gIGJ1aWxkZXIuc3RvcE5vV3JhcCgpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUmVuZGVyIGlubGluZSBlbGVtZW50IHdyYXBwZWQgd2l0aCBnaXZlbiBzdHJpbmdzLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRJbmxpbmVTdXJyb3VuZCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5wcmVmaXggfHwgJycpO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmFkZExpdGVyYWwoZm9ybWF0T3B0aW9ucy5zdWZmaXggfHwgJycpO1xufVxuXG52YXIgZ2VuZXJpY0Zvcm1hdHRlcnMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG4gIF9fcHJvdG9fXzogbnVsbCxcbiAgYmxvY2s6IGZvcm1hdEJsb2NrJDEsXG4gIGJsb2NrSHRtbDogZm9ybWF0QmxvY2tIdG1sLFxuICBibG9ja1N0cmluZzogZm9ybWF0QmxvY2tTdHJpbmcsXG4gIGJsb2NrVGFnOiBmb3JtYXRCbG9ja1RhZyxcbiAgaW5saW5lOiBmb3JtYXRJbmxpbmUsXG4gIGlubGluZUh0bWw6IGZvcm1hdElubGluZUh0bWwsXG4gIGlubGluZVN0cmluZzogZm9ybWF0SW5saW5lU3RyaW5nLFxuICBpbmxpbmVTdXJyb3VuZDogZm9ybWF0SW5saW5lU3Vycm91bmQsXG4gIGlubGluZVRhZzogZm9ybWF0SW5saW5lVGFnLFxuICBza2lwOiBmb3JtYXRTa2lwXG59KTtcblxuZnVuY3Rpb24gZ2V0Um93IChtYXRyaXgsIGopIHtcbiAgaWYgKCFtYXRyaXhbal0pIHsgbWF0cml4W2pdID0gW107IH1cbiAgcmV0dXJuIG1hdHJpeFtqXTtcbn1cblxuZnVuY3Rpb24gZmluZEZpcnN0VmFjYW50SW5kZXggKHJvdywgeCA9IDApIHtcbiAgd2hpbGUgKHJvd1t4XSkgeyB4Kys7IH1cbiAgcmV0dXJuIHg7XG59XG5cbmZ1bmN0aW9uIHRyYW5zcG9zZUluUGxhY2UgKG1hdHJpeCwgbWF4U2l6ZSkge1xuICBmb3IgKGxldCBpID0gMDsgaSA8IG1heFNpemU7IGkrKykge1xuICAgIGNvbnN0IHJvd0kgPSBnZXRSb3cobWF0cml4LCBpKTtcbiAgICBmb3IgKGxldCBqID0gMDsgaiA8IGk7IGorKykge1xuICAgICAgY29uc3Qgcm93SiA9IGdldFJvdyhtYXRyaXgsIGopO1xuICAgICAgaWYgKHJvd0lbal0gfHwgcm93SltpXSkge1xuICAgICAgICBjb25zdCB0ZW1wID0gcm93SVtqXTtcbiAgICAgICAgcm93SVtqXSA9IHJvd0pbaV07XG4gICAgICAgIHJvd0pbaV0gPSB0ZW1wO1xuICAgICAgfVxuICAgIH1cbiAgfVxufVxuXG5mdW5jdGlvbiBwdXRDZWxsSW50b0xheW91dCAoY2VsbCwgbGF5b3V0LCBiYXNlUm93LCBiYXNlQ29sKSB7XG4gIGZvciAobGV0IHIgPSAwOyByIDwgY2VsbC5yb3dzcGFuOyByKyspIHtcbiAgICBjb25zdCBsYXlvdXRSb3cgPSBnZXRSb3cobGF5b3V0LCBiYXNlUm93ICsgcik7XG4gICAgZm9yIChsZXQgYyA9IDA7IGMgPCBjZWxsLmNvbHNwYW47IGMrKykge1xuICAgICAgbGF5b3V0Um93W2Jhc2VDb2wgKyBjXSA9IGNlbGw7XG4gICAgfVxuICB9XG59XG5cbmZ1bmN0aW9uIGdldE9ySW5pdE9mZnNldCAob2Zmc2V0cywgaW5kZXgpIHtcbiAgaWYgKG9mZnNldHNbaW5kZXhdID09PSB1bmRlZmluZWQpIHtcbiAgICBvZmZzZXRzW2luZGV4XSA9IChpbmRleCA9PT0gMCkgPyAwIDogMSArIGdldE9ySW5pdE9mZnNldChvZmZzZXRzLCBpbmRleCAtIDEpO1xuICB9XG4gIHJldHVybiBvZmZzZXRzW2luZGV4XTtcbn1cblxuZnVuY3Rpb24gdXBkYXRlT2Zmc2V0IChvZmZzZXRzLCBiYXNlLCBzcGFuLCB2YWx1ZSkge1xuICBvZmZzZXRzW2Jhc2UgKyBzcGFuXSA9IE1hdGgubWF4KFxuICAgIGdldE9ySW5pdE9mZnNldChvZmZzZXRzLCBiYXNlICsgc3BhbiksXG4gICAgZ2V0T3JJbml0T2Zmc2V0KG9mZnNldHMsIGJhc2UpICsgdmFsdWVcbiAgKTtcbn1cblxuLyoqXG4gKiBSZW5kZXIgYSB0YWJsZSBpbnRvIGEgc3RyaW5nLlxuICogQ2VsbHMgY2FuIGNvbnRhaW4gbXVsdGlsaW5lIHRleHQgYW5kIHNwYW4gYWNyb3NzIG11bHRpcGxlIHJvd3MgYW5kIGNvbHVtbnMuXG4gKlxuICogTW9kaWZpZXMgY2VsbHMgdG8gYWRkIGxpbmVzIGFycmF5LlxuICpcbiAqIEBwYXJhbSB7IFRhYmxlUHJpbnRlckNlbGxbXVtdIH0gdGFibGVSb3dzIFRhYmxlIHRvIHJlbmRlci5cbiAqIEBwYXJhbSB7IG51bWJlciB9IHJvd1NwYWNpbmcgTnVtYmVyIG9mIHNwYWNlcyBiZXR3ZWVuIGNvbHVtbnMuXG4gKiBAcGFyYW0geyBudW1iZXIgfSBjb2xTcGFjaW5nIE51bWJlciBvZiBlbXB0eSBsaW5lcyBiZXR3ZWVuIHJvd3MuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9XG4gKi9cbmZ1bmN0aW9uIHRhYmxlVG9TdHJpbmcgKHRhYmxlUm93cywgcm93U3BhY2luZywgY29sU3BhY2luZykge1xuICBjb25zdCBsYXlvdXQgPSBbXTtcbiAgbGV0IGNvbE51bWJlciA9IDA7XG4gIGNvbnN0IHJvd051bWJlciA9IHRhYmxlUm93cy5sZW5ndGg7XG4gIGNvbnN0IHJvd09mZnNldHMgPSBbMF07XG4gIC8vIEZpbGwgdGhlIGxheW91dCB0YWJsZSBhbmQgcm93IG9mZnNldHMgcm93LWJ5LXJvdy5cbiAgZm9yIChsZXQgaiA9IDA7IGogPCByb3dOdW1iZXI7IGorKykge1xuICAgIGNvbnN0IGxheW91dFJvdyA9IGdldFJvdyhsYXlvdXQsIGopO1xuICAgIGNvbnN0IGNlbGxzID0gdGFibGVSb3dzW2pdO1xuICAgIGxldCB4ID0gMDtcbiAgICBmb3IgKGxldCBpID0gMDsgaSA8IGNlbGxzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBjb25zdCBjZWxsID0gY2VsbHNbaV07XG4gICAgICB4ID0gZmluZEZpcnN0VmFjYW50SW5kZXgobGF5b3V0Um93LCB4KTtcbiAgICAgIHB1dENlbGxJbnRvTGF5b3V0KGNlbGwsIGxheW91dCwgaiwgeCk7XG4gICAgICB4ICs9IGNlbGwuY29sc3BhbjtcbiAgICAgIGNlbGwubGluZXMgPSBjZWxsLnRleHQuc3BsaXQoJ1xcbicpO1xuICAgICAgY29uc3QgY2VsbEhlaWdodCA9IGNlbGwubGluZXMubGVuZ3RoO1xuICAgICAgdXBkYXRlT2Zmc2V0KHJvd09mZnNldHMsIGosIGNlbGwucm93c3BhbiwgY2VsbEhlaWdodCArIHJvd1NwYWNpbmcpO1xuICAgIH1cbiAgICBjb2xOdW1iZXIgPSAobGF5b3V0Um93Lmxlbmd0aCA+IGNvbE51bWJlcikgPyBsYXlvdXRSb3cubGVuZ3RoIDogY29sTnVtYmVyO1xuICB9XG5cbiAgdHJhbnNwb3NlSW5QbGFjZShsYXlvdXQsIChyb3dOdW1iZXIgPiBjb2xOdW1iZXIpID8gcm93TnVtYmVyIDogY29sTnVtYmVyKTtcblxuICBjb25zdCBvdXRwdXRMaW5lcyA9IFtdO1xuICBjb25zdCBjb2xPZmZzZXRzID0gWzBdO1xuICAvLyBGaWxsIGNvbHVtbiBvZmZzZXRzIGFuZCBvdXRwdXQgbGluZXMgY29sdW1uLWJ5LWNvbHVtbi5cbiAgZm9yIChsZXQgeCA9IDA7IHggPCBjb2xOdW1iZXI7IHgrKykge1xuICAgIGxldCB5ID0gMDtcbiAgICBsZXQgY2VsbDtcbiAgICBjb25zdCByb3dzSW5UaGlzQ29sdW1uID0gTWF0aC5taW4ocm93TnVtYmVyLCBsYXlvdXRbeF0ubGVuZ3RoKTtcbiAgICB3aGlsZSAoeSA8IHJvd3NJblRoaXNDb2x1bW4pIHtcbiAgICAgIGNlbGwgPSBsYXlvdXRbeF1beV07XG4gICAgICBpZiAoY2VsbCkge1xuICAgICAgICBpZiAoIWNlbGwucmVuZGVyZWQpIHtcbiAgICAgICAgICBsZXQgY2VsbFdpZHRoID0gMDtcbiAgICAgICAgICBmb3IgKGxldCBqID0gMDsgaiA8IGNlbGwubGluZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGNvbnN0IGxpbmUgPSBjZWxsLmxpbmVzW2pdO1xuICAgICAgICAgICAgY29uc3QgbGluZU9mZnNldCA9IHJvd09mZnNldHNbeV0gKyBqO1xuICAgICAgICAgICAgb3V0cHV0TGluZXNbbGluZU9mZnNldF0gPSAob3V0cHV0TGluZXNbbGluZU9mZnNldF0gfHwgJycpLnBhZEVuZChjb2xPZmZzZXRzW3hdKSArIGxpbmU7XG4gICAgICAgICAgICBjZWxsV2lkdGggPSAobGluZS5sZW5ndGggPiBjZWxsV2lkdGgpID8gbGluZS5sZW5ndGggOiBjZWxsV2lkdGg7XG4gICAgICAgICAgfVxuICAgICAgICAgIHVwZGF0ZU9mZnNldChjb2xPZmZzZXRzLCB4LCBjZWxsLmNvbHNwYW4sIGNlbGxXaWR0aCArIGNvbFNwYWNpbmcpO1xuICAgICAgICAgIGNlbGwucmVuZGVyZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgICAgIHkgKz0gY2VsbC5yb3dzcGFuO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgY29uc3QgbGluZU9mZnNldCA9IHJvd09mZnNldHNbeV07XG4gICAgICAgIG91dHB1dExpbmVzW2xpbmVPZmZzZXRdID0gKG91dHB1dExpbmVzW2xpbmVPZmZzZXRdIHx8ICcnKTtcbiAgICAgICAgeSsrO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiBvdXRwdXRMaW5lcy5qb2luKCdcXG4nKTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgbGluZS1icmVhay5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0TGluZUJyZWFrIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIuYWRkTGluZUJyZWFrKCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGB3YnJgIHRhZyAod29yZCBicmVhayBvcHBvcnR1bml0eSkuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdFdiciAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBidWlsZGVyLmFkZFdvcmRCcmVha09wcG9ydHVuaXR5KCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGhvcml6b250YWwgbGluZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0SG9yaXpvbnRhbExpbmUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBidWlsZGVyLmFkZElubGluZSgnLScucmVwZWF0KGZvcm1hdE9wdGlvbnMubGVuZ3RoIHx8IGJ1aWxkZXIub3B0aW9ucy53b3Jkd3JhcCB8fCA0MCkpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIHBhcmFncmFwaC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0UGFyYWdyYXBoIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHsgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MgfHwgMiB9KTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSBwcmVmb3JtYXR0ZWQgY29udGVudC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0UHJlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlbkJsb2NrKHtcbiAgICBpc1ByZTogdHJ1ZSxcbiAgICBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyXG4gIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGhlYWRpbmcuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEhlYWRpbmcgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB8fCAyIH0pO1xuICBpZiAoZm9ybWF0T3B0aW9ucy51cHBlcmNhc2UgIT09IGZhbHNlKSB7XG4gICAgYnVpbGRlci5wdXNoV29yZFRyYW5zZm9ybShzdHIgPT4gc3RyLnRvVXBwZXJDYXNlKCkpO1xuICAgIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gICAgYnVpbGRlci5wb3BXb3JkVHJhbnNmb3JtKCk7XG4gIH0gZWxzZSB7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgfVxuICBidWlsZGVyLmNsb3NlQmxvY2soeyB0cmFpbGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMudHJhaWxpbmdMaW5lQnJlYWtzIHx8IDIgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhIGJsb2NrcXVvdGUuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEJsb2NrcXVvdGUgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soe1xuICAgIGxlYWRpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIsXG4gICAgcmVzZXJ2ZWRMaW5lTGVuZ3RoOiAyXG4gIH0pO1xuICB3YWxrKGVsZW0uY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICBidWlsZGVyLmNsb3NlQmxvY2soe1xuICAgIHRyYWlsaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMixcbiAgICBibG9ja1RyYW5zZm9ybTogc3RyID0+ICgoZm9ybWF0T3B0aW9ucy50cmltRW1wdHlMaW5lcyAhPT0gZmFsc2UpID8gdHJpbUNoYXJhY3RlcihzdHIsICdcXG4nKSA6IHN0cilcbiAgICAgIC5zcGxpdCgnXFxuJylcbiAgICAgIC5tYXAobGluZSA9PiAnPiAnICsgbGluZSlcbiAgICAgIC5qb2luKCdcXG4nKVxuICB9KTtcbn1cblxuZnVuY3Rpb24gd2l0aEJyYWNrZXRzIChzdHIsIGJyYWNrZXRzKSB7XG4gIGlmICghYnJhY2tldHMpIHsgcmV0dXJuIHN0cjsgfVxuXG4gIGNvbnN0IGxiciA9ICh0eXBlb2YgYnJhY2tldHNbMF0gPT09ICdzdHJpbmcnKVxuICAgID8gYnJhY2tldHNbMF1cbiAgICA6ICdbJztcbiAgY29uc3QgcmJyID0gKHR5cGVvZiBicmFja2V0c1sxXSA9PT0gJ3N0cmluZycpXG4gICAgPyBicmFja2V0c1sxXVxuICAgIDogJ10nO1xuICByZXR1cm4gbGJyICsgc3RyICsgcmJyO1xufVxuXG5mdW5jdGlvbiBwYXRoUmV3cml0ZSAocGF0aCwgcmV3cml0ZXIsIGJhc2VVcmwsIG1ldGFkYXRhLCBlbGVtKSB7XG4gIGNvbnN0IG1vZGlmaWVkUGF0aCA9ICh0eXBlb2YgcmV3cml0ZXIgPT09ICdmdW5jdGlvbicpXG4gICAgPyByZXdyaXRlcihwYXRoLCBtZXRhZGF0YSwgZWxlbSlcbiAgICA6IHBhdGg7XG4gIHJldHVybiAobW9kaWZpZWRQYXRoWzBdID09PSAnLycgJiYgYmFzZVVybClcbiAgICA/IHRyaW1DaGFyYWN0ZXJFbmQoYmFzZVVybCwgJy8nKSArIG1vZGlmaWVkUGF0aFxuICAgIDogbW9kaWZpZWRQYXRoO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYW4gaW1hZ2UuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdEltYWdlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGNvbnN0IGF0dHJpYnMgPSBlbGVtLmF0dHJpYnMgfHwge307XG4gIGNvbnN0IGFsdCA9IChhdHRyaWJzLmFsdClcbiAgICA/IGF0dHJpYnMuYWx0XG4gICAgOiAnJztcbiAgY29uc3Qgc3JjID0gKCFhdHRyaWJzLnNyYylcbiAgICA/ICcnXG4gICAgOiBwYXRoUmV3cml0ZShhdHRyaWJzLnNyYywgZm9ybWF0T3B0aW9ucy5wYXRoUmV3cml0ZSwgZm9ybWF0T3B0aW9ucy5iYXNlVXJsLCBidWlsZGVyLm1ldGFkYXRhLCBlbGVtKTtcbiAgY29uc3QgdGV4dCA9ICghc3JjKVxuICAgID8gYWx0XG4gICAgOiAoIWFsdClcbiAgICAgID8gd2l0aEJyYWNrZXRzKHNyYywgZm9ybWF0T3B0aW9ucy5saW5rQnJhY2tldHMpXG4gICAgICA6IGFsdCArICcgJyArIHdpdGhCcmFja2V0cyhzcmMsIGZvcm1hdE9wdGlvbnMubGlua0JyYWNrZXRzKTtcblxuICBidWlsZGVyLmFkZElubGluZSh0ZXh0LCB7IG5vV29yZFRyYW5zZm9ybTogdHJ1ZSB9KTtcbn1cblxuLy8gYSBpbWcgYmFzZVVybFxuLy8gYSBpbWcgcGF0aFJld3JpdGVcbi8vIGEgaW1nIGxpbmtCcmFja2V0c1xuXG4vLyBhICAgICBpZ25vcmVIcmVmOiBmYWxzZVxuLy8gICAgICAgICAgICBpZ25vcmVUZXh0ID9cbi8vIGEgICAgIG5vQW5jaG9yVXJsOiB0cnVlXG4vLyAgICAgICAgICAgIGNhbiBiZSByZXBsYWNlZCB3aXRoIHNlbGVjdG9yXG4vLyBhICAgICBoaWRlTGlua0hyZWZJZlNhbWVBc1RleHQ6IGZhbHNlXG4vLyAgICAgICAgICAgIGhvdyB0byBjb21wYXJlLCB3aGF0IHRvIHNob3cgKHRleHQsIGhyZWYsIG5vcm1hbGl6ZWQpID9cbi8vIGEgICAgIG1haWx0byBwcm90b2NvbCByZW1vdmVkIHdpdGhvdXQgb3B0aW9uc1xuXG4vLyBhICAgICBwcm90b2NvbHM6IG1haWx0bywgdGVsLCAuLi5cbi8vICAgICAgICAgICAgY2FuIGJlIG1hdGNoZWQgd2l0aCBzZWxlY3Rvcj9cblxuLy8gYW5jaG9ycywgcHJvdG9jb2xzIC0gb25seSBpZiBubyBwYXRoUmV3cml0ZSBmbiBpcyBwcm92aWRlZFxuXG4vLyBub3JtYWxpemUtdXJsID9cblxuLy8gYVxuLy8gYVtocmVmXj1cIiNcIl0gLSBmb3JtYXQ6c2tpcCBieSBkZWZhdWx0XG4vLyBhW2hyZWZePVwibWFpbHRvOlwiXSAtID9cblxuLyoqXG4gKiBQcm9jZXNzIGFuIGFuY2hvci5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0QW5jaG9yIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGZ1bmN0aW9uIGdldEhyZWYgKCkge1xuICAgIGlmIChmb3JtYXRPcHRpb25zLmlnbm9yZUhyZWYpIHsgcmV0dXJuICcnOyB9XG4gICAgaWYgKCFlbGVtLmF0dHJpYnMgfHwgIWVsZW0uYXR0cmlicy5ocmVmKSB7IHJldHVybiAnJzsgfVxuICAgIGxldCBocmVmID0gZWxlbS5hdHRyaWJzLmhyZWYucmVwbGFjZSgvXm1haWx0bzovLCAnJyk7XG4gICAgaWYgKGZvcm1hdE9wdGlvbnMubm9BbmNob3JVcmwgJiYgaHJlZlswXSA9PT0gJyMnKSB7IHJldHVybiAnJzsgfVxuICAgIGhyZWYgPSBwYXRoUmV3cml0ZShocmVmLCBmb3JtYXRPcHRpb25zLnBhdGhSZXdyaXRlLCBmb3JtYXRPcHRpb25zLmJhc2VVcmwsIGJ1aWxkZXIubWV0YWRhdGEsIGVsZW0pO1xuICAgIHJldHVybiBocmVmO1xuICB9XG4gIGNvbnN0IGhyZWYgPSBnZXRIcmVmKCk7XG4gIGlmICghaHJlZikge1xuICAgIHdhbGsoZWxlbS5jaGlsZHJlbiwgYnVpbGRlcik7XG4gIH0gZWxzZSB7XG4gICAgbGV0IHRleHQgPSAnJztcbiAgICBidWlsZGVyLnB1c2hXb3JkVHJhbnNmb3JtKFxuICAgICAgc3RyID0+IHtcbiAgICAgICAgaWYgKHN0cikgeyB0ZXh0ICs9IHN0cjsgfVxuICAgICAgICByZXR1cm4gc3RyO1xuICAgICAgfVxuICAgICk7XG4gICAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgICBidWlsZGVyLnBvcFdvcmRUcmFuc2Zvcm0oKTtcblxuICAgIGNvbnN0IGhpZGVTYW1lTGluayA9IGZvcm1hdE9wdGlvbnMuaGlkZUxpbmtIcmVmSWZTYW1lQXNUZXh0ICYmIGhyZWYgPT09IHRleHQ7XG4gICAgaWYgKCFoaWRlU2FtZUxpbmspIHtcbiAgICAgIGJ1aWxkZXIuYWRkSW5saW5lKFxuICAgICAgICAoIXRleHQpXG4gICAgICAgICAgPyBocmVmXG4gICAgICAgICAgOiAnICcgKyB3aXRoQnJhY2tldHMoaHJlZiwgZm9ybWF0T3B0aW9ucy5saW5rQnJhY2tldHMpLFxuICAgICAgICB7IG5vV29yZFRyYW5zZm9ybTogdHJ1ZSB9XG4gICAgICApO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEBwYXJhbSB7IERvbU5vZGUgfSAgICAgICAgICAgZWxlbSAgICAgICAgICAgICAgIExpc3QgaXRlbXMgd2l0aCB0aGVpciBwcmVmaXhlcy5cbiAqIEBwYXJhbSB7IFJlY3Vyc2l2ZUNhbGxiYWNrIH0gd2FsayAgICAgICAgICAgICAgIFJlY3Vyc2l2ZSBjYWxsYmFjayB0byBwcm9jZXNzIGNoaWxkIG5vZGVzLlxuICogQHBhcmFtIHsgQmxvY2tUZXh0QnVpbGRlciB9ICBidWlsZGVyICAgICAgICAgICAgUGFzc2VkIGFyb3VuZCB0byBhY2N1bXVsYXRlIG91dHB1dCB0ZXh0LlxuICogQHBhcmFtIHsgRm9ybWF0T3B0aW9ucyB9ICAgICBmb3JtYXRPcHRpb25zICAgICAgT3B0aW9ucyBzcGVjaWZpYyB0byBhIGZvcm1hdHRlci5cbiAqIEBwYXJhbSB7ICgpID0+IHN0cmluZyB9ICAgICAgbmV4dFByZWZpeENhbGxiYWNrIEZ1bmN0aW9uIHRoYXQgcmV0dXJucyBpbmNyZWFzaW5nIGluZGV4IGVhY2ggdGltZSBpdCBpcyBjYWxsZWQuXG4gKi9cbmZ1bmN0aW9uIGZvcm1hdExpc3QgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsIG5leHRQcmVmaXhDYWxsYmFjaykge1xuICBjb25zdCBpc05lc3RlZExpc3QgPSBnZXQoZWxlbSwgWydwYXJlbnQnLCAnbmFtZSddKSA9PT0gJ2xpJztcblxuICAvLyBXaXRoIFJvbWFuIG51bWJlcnMsIGluZGV4IGxlbmd0aCBpcyBub3QgYXMgc3RyYWlnaHRmb3J3YXJkIGFzIHdpdGggQXJhYmljIG51bWJlcnMgb3IgbGV0dGVycyxcbiAgLy8gc28gdGhlIGR1bWIgbGVuZ3RoIGNvbXBhcmlzb24gaXMgdGhlIG1vc3Qgcm9idXN0IHdheSB0byBnZXQgdGhlIGNvcnJlY3QgdmFsdWUuXG4gIGxldCBtYXhQcmVmaXhMZW5ndGggPSAwO1xuICBjb25zdCBsaXN0SXRlbXMgPSAoZWxlbS5jaGlsZHJlbiB8fCBbXSlcbiAgICAvLyBpdCBtaWdodCBiZSBtb3JlIGFjY3VyYXRlIHRvIGNoZWNrIG9ubHkgZm9yIGh0bWwgc3BhY2VzIGhlcmUsIGJ1dCBubyBzaWduaWZpY2FudCBiZW5lZml0XG4gICAgLmZpbHRlcihjaGlsZCA9PiBjaGlsZC50eXBlICE9PSAndGV4dCcgfHwgIS9eXFxzKiQvLnRlc3QoY2hpbGQuZGF0YSkpXG4gICAgLm1hcChmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICAgIGlmIChjaGlsZC5uYW1lICE9PSAnbGknKSB7XG4gICAgICAgIHJldHVybiB7IG5vZGU6IGNoaWxkLCBwcmVmaXg6ICcnIH07XG4gICAgICB9XG4gICAgICBjb25zdCBwcmVmaXggPSAoaXNOZXN0ZWRMaXN0KVxuICAgICAgICA/IG5leHRQcmVmaXhDYWxsYmFjaygpLnRyaW1TdGFydCgpXG4gICAgICAgIDogbmV4dFByZWZpeENhbGxiYWNrKCk7XG4gICAgICBpZiAocHJlZml4Lmxlbmd0aCA+IG1heFByZWZpeExlbmd0aCkgeyBtYXhQcmVmaXhMZW5ndGggPSBwcmVmaXgubGVuZ3RoOyB9XG4gICAgICByZXR1cm4geyBub2RlOiBjaGlsZCwgcHJlZml4OiBwcmVmaXggfTtcbiAgICB9KTtcbiAgaWYgKCFsaXN0SXRlbXMubGVuZ3RoKSB7IHJldHVybjsgfVxuXG4gIGJ1aWxkZXIub3Blbkxpc3Qoe1xuICAgIGludGVyUm93TGluZUJyZWFrczogMSxcbiAgICBsZWFkaW5nTGluZUJyZWFrczogaXNOZXN0ZWRMaXN0ID8gMSA6IChmb3JtYXRPcHRpb25zLmxlYWRpbmdMaW5lQnJlYWtzIHx8IDIpLFxuICAgIG1heFByZWZpeExlbmd0aDogbWF4UHJlZml4TGVuZ3RoLFxuICAgIHByZWZpeEFsaWduOiAnbGVmdCdcbiAgfSk7XG5cbiAgZm9yIChjb25zdCB7IG5vZGUsIHByZWZpeCB9IG9mIGxpc3RJdGVtcykge1xuICAgIGJ1aWxkZXIub3Blbkxpc3RJdGVtKHsgcHJlZml4OiBwcmVmaXggfSk7XG4gICAgd2Fsayhbbm9kZV0sIGJ1aWxkZXIpO1xuICAgIGJ1aWxkZXIuY2xvc2VMaXN0SXRlbSgpO1xuICB9XG5cbiAgYnVpbGRlci5jbG9zZUxpc3QoeyB0cmFpbGluZ0xpbmVCcmVha3M6IGlzTmVzdGVkTGlzdCA/IDEgOiAoZm9ybWF0T3B0aW9ucy50cmFpbGluZ0xpbmVCcmVha3MgfHwgMikgfSk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiB1bm9yZGVyZWQgbGlzdC5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0VW5vcmRlcmVkTGlzdCAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICBjb25zdCBwcmVmaXggPSBmb3JtYXRPcHRpb25zLml0ZW1QcmVmaXggfHwgJyAqICc7XG4gIHJldHVybiBmb3JtYXRMaXN0KGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsICgpID0+IHByZWZpeCk7XG59XG5cbi8qKlxuICogUHJvY2VzcyBhbiBvcmRlcmVkIGxpc3QuXG4gKlxuICogQHR5cGUgeyBGb3JtYXRDYWxsYmFjayB9XG4gKi9cbmZ1bmN0aW9uIGZvcm1hdE9yZGVyZWRMaXN0IChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGxldCBuZXh0SW5kZXggPSBOdW1iZXIoZWxlbS5hdHRyaWJzLnN0YXJ0IHx8ICcxJyk7XG4gIGNvbnN0IGluZGV4RnVuY3Rpb24gPSBnZXRPcmRlcmVkTGlzdEluZGV4RnVuY3Rpb24oZWxlbS5hdHRyaWJzLnR5cGUpO1xuICBjb25zdCBuZXh0UHJlZml4Q2FsbGJhY2sgPSAoKSA9PiAnICcgKyBpbmRleEZ1bmN0aW9uKG5leHRJbmRleCsrKSArICcuICc7XG4gIHJldHVybiBmb3JtYXRMaXN0KGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMsIG5leHRQcmVmaXhDYWxsYmFjayk7XG59XG5cbi8qKlxuICogUmV0dXJuIGEgZnVuY3Rpb24gdGhhdCBjYW4gYmUgdXNlZCB0byBnZW5lcmF0ZSBpbmRleCBtYXJrZXJzIG9mIGEgc3BlY2lmaWVkIGZvcm1hdC5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9IFtvbFR5cGU9JzEnXSBNYXJrZXIgdHlwZS5cbiAqIEByZXR1cm5zIHsgKGk6IG51bWJlcikgPT4gc3RyaW5nIH1cbiAqL1xuZnVuY3Rpb24gZ2V0T3JkZXJlZExpc3RJbmRleEZ1bmN0aW9uIChvbFR5cGUgPSAnMScpIHtcbiAgc3dpdGNoIChvbFR5cGUpIHtcbiAgICBjYXNlICdhJzogcmV0dXJuIChpKSA9PiBudW1iZXJUb0xldHRlclNlcXVlbmNlKGksICdhJyk7XG4gICAgY2FzZSAnQSc6IHJldHVybiAoaSkgPT4gbnVtYmVyVG9MZXR0ZXJTZXF1ZW5jZShpLCAnQScpO1xuICAgIGNhc2UgJ2knOiByZXR1cm4gKGkpID0+IG51bWJlclRvUm9tYW4oaSkudG9Mb3dlckNhc2UoKTtcbiAgICBjYXNlICdJJzogcmV0dXJuIChpKSA9PiBudW1iZXJUb1JvbWFuKGkpO1xuICAgIGNhc2UgJzEnOlxuICAgIGRlZmF1bHQ6IHJldHVybiAoaSkgPT4gKGkpLnRvU3RyaW5nKCk7XG4gIH1cbn1cblxuLyoqXG4gKiBHaXZlbiBhIGxpc3Qgb2YgY2xhc3MgYW5kIElEIHNlbGVjdG9ycyAocHJlZml4ZWQgd2l0aCAnLicgYW5kICcjJyksXG4gKiByZXR1cm4gdGhlbSBhcyBzZXBhcmF0ZSBsaXN0cyBvZiBuYW1lcyB3aXRob3V0IHByZWZpeGVzLlxuICpcbiAqIEBwYXJhbSB7IHN0cmluZ1tdIH0gc2VsZWN0b3JzIENsYXNzIGFuZCBJRCBzZWxlY3RvcnMgKGBbXCIuY2xhc3NcIiwgXCIjaWRcIl1gIGV0YykuXG4gKiBAcmV0dXJucyB7IHsgY2xhc3Nlczogc3RyaW5nW10sIGlkczogc3RyaW5nW10gfSB9XG4gKi9cbmZ1bmN0aW9uIHNwbGl0Q2xhc3Nlc0FuZElkcyAoc2VsZWN0b3JzKSB7XG4gIGNvbnN0IGNsYXNzZXMgPSBbXTtcbiAgY29uc3QgaWRzID0gW107XG4gIGZvciAoY29uc3Qgc2VsZWN0b3Igb2Ygc2VsZWN0b3JzKSB7XG4gICAgaWYgKHNlbGVjdG9yLnN0YXJ0c1dpdGgoJy4nKSkge1xuICAgICAgY2xhc3Nlcy5wdXNoKHNlbGVjdG9yLnN1YnN0cmluZygxKSk7XG4gICAgfSBlbHNlIGlmIChzZWxlY3Rvci5zdGFydHNXaXRoKCcjJykpIHtcbiAgICAgIGlkcy5wdXNoKHNlbGVjdG9yLnN1YnN0cmluZygxKSk7XG4gICAgfVxuICB9XG4gIHJldHVybiB7IGNsYXNzZXM6IGNsYXNzZXMsIGlkczogaWRzIH07XG59XG5cbmZ1bmN0aW9uIGlzRGF0YVRhYmxlIChhdHRyLCB0YWJsZXMpIHtcbiAgaWYgKHRhYmxlcyA9PT0gdHJ1ZSkgeyByZXR1cm4gdHJ1ZTsgfVxuICBpZiAoIWF0dHIpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgY29uc3QgeyBjbGFzc2VzLCBpZHMgfSA9IHNwbGl0Q2xhc3Nlc0FuZElkcyh0YWJsZXMpO1xuICBjb25zdCBhdHRyQ2xhc3NlcyA9IChhdHRyWydjbGFzcyddIHx8ICcnKS5zcGxpdCgnICcpO1xuICBjb25zdCBhdHRySWRzID0gKGF0dHJbJ2lkJ10gfHwgJycpLnNwbGl0KCcgJyk7XG5cbiAgcmV0dXJuIGF0dHJDbGFzc2VzLnNvbWUoeCA9PiBjbGFzc2VzLmluY2x1ZGVzKHgpKSB8fCBhdHRySWRzLnNvbWUoeCA9PiBpZHMuaW5jbHVkZXMoeCkpO1xufVxuXG4vKipcbiAqIFByb2Nlc3MgYSB0YWJsZSAoZWl0aGVyIGFzIGEgY29udGFpbmVyIG9yIGFzIGEgZGF0YSB0YWJsZSwgZGVwZW5kaW5nIG9uIG9wdGlvbnMpLlxuICpcbiAqIEB0eXBlIHsgRm9ybWF0Q2FsbGJhY2sgfVxuICovXG5mdW5jdGlvbiBmb3JtYXRUYWJsZSAoZWxlbSwgd2FsaywgYnVpbGRlciwgZm9ybWF0T3B0aW9ucykge1xuICByZXR1cm4gaXNEYXRhVGFibGUoZWxlbS5hdHRyaWJzLCBidWlsZGVyLm9wdGlvbnMudGFibGVzKVxuICAgID8gZm9ybWF0RGF0YVRhYmxlKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpXG4gICAgOiBmb3JtYXRCbG9jayhlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKTtcbn1cblxuZnVuY3Rpb24gZm9ybWF0QmxvY2sgKGVsZW0sIHdhbGssIGJ1aWxkZXIsIGZvcm1hdE9wdGlvbnMpIHtcbiAgYnVpbGRlci5vcGVuQmxvY2soeyBsZWFkaW5nTGluZUJyZWFrczogZm9ybWF0T3B0aW9ucy5sZWFkaW5nTGluZUJyZWFrcyB9KTtcbiAgd2FsayhlbGVtLmNoaWxkcmVuLCBidWlsZGVyKTtcbiAgYnVpbGRlci5jbG9zZUJsb2NrKHsgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrcyB9KTtcbn1cblxuLyoqXG4gKiBQcm9jZXNzIGEgZGF0YSB0YWJsZS5cbiAqXG4gKiBAdHlwZSB7IEZvcm1hdENhbGxiYWNrIH1cbiAqL1xuZnVuY3Rpb24gZm9ybWF0RGF0YVRhYmxlIChlbGVtLCB3YWxrLCBidWlsZGVyLCBmb3JtYXRPcHRpb25zKSB7XG4gIGJ1aWxkZXIub3BlblRhYmxlKCk7XG4gIGVsZW0uY2hpbGRyZW4uZm9yRWFjaCh3YWxrVGFibGUpO1xuICBidWlsZGVyLmNsb3NlVGFibGUoe1xuICAgIHRhYmxlVG9TdHJpbmc6IChyb3dzKSA9PiB0YWJsZVRvU3RyaW5nKHJvd3MsIGZvcm1hdE9wdGlvbnMucm93U3BhY2luZyA/PyAwLCBmb3JtYXRPcHRpb25zLmNvbFNwYWNpbmcgPz8gMyksXG4gICAgbGVhZGluZ0xpbmVCcmVha3M6IGZvcm1hdE9wdGlvbnMubGVhZGluZ0xpbmVCcmVha3MsXG4gICAgdHJhaWxpbmdMaW5lQnJlYWtzOiBmb3JtYXRPcHRpb25zLnRyYWlsaW5nTGluZUJyZWFrc1xuICB9KTtcblxuICBmdW5jdGlvbiBmb3JtYXRDZWxsIChjZWxsTm9kZSkge1xuICAgIGNvbnN0IGNvbHNwYW4gPSArZ2V0KGNlbGxOb2RlLCBbJ2F0dHJpYnMnLCAnY29sc3BhbiddKSB8fCAxO1xuICAgIGNvbnN0IHJvd3NwYW4gPSArZ2V0KGNlbGxOb2RlLCBbJ2F0dHJpYnMnLCAncm93c3BhbiddKSB8fCAxO1xuICAgIGJ1aWxkZXIub3BlblRhYmxlQ2VsbCh7IG1heENvbHVtbldpZHRoOiBmb3JtYXRPcHRpb25zLm1heENvbHVtbldpZHRoIH0pO1xuICAgIHdhbGsoY2VsbE5vZGUuY2hpbGRyZW4sIGJ1aWxkZXIpO1xuICAgIGJ1aWxkZXIuY2xvc2VUYWJsZUNlbGwoeyBjb2xzcGFuOiBjb2xzcGFuLCByb3dzcGFuOiByb3dzcGFuIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gd2Fsa1RhYmxlIChlbGVtKSB7XG4gICAgaWYgKGVsZW0udHlwZSAhPT0gJ3RhZycpIHsgcmV0dXJuOyB9XG5cbiAgICBjb25zdCBmb3JtYXRIZWFkZXJDZWxsID0gKGZvcm1hdE9wdGlvbnMudXBwZXJjYXNlSGVhZGVyQ2VsbHMgIT09IGZhbHNlKVxuICAgICAgPyAoY2VsbE5vZGUpID0+IHtcbiAgICAgICAgYnVpbGRlci5wdXNoV29yZFRyYW5zZm9ybShzdHIgPT4gc3RyLnRvVXBwZXJDYXNlKCkpO1xuICAgICAgICBmb3JtYXRDZWxsKGNlbGxOb2RlKTtcbiAgICAgICAgYnVpbGRlci5wb3BXb3JkVHJhbnNmb3JtKCk7XG4gICAgICB9XG4gICAgICA6IGZvcm1hdENlbGw7XG5cbiAgICBzd2l0Y2ggKGVsZW0ubmFtZSkge1xuICAgICAgY2FzZSAndGhlYWQnOlxuICAgICAgY2FzZSAndGJvZHknOlxuICAgICAgY2FzZSAndGZvb3QnOlxuICAgICAgY2FzZSAnY2VudGVyJzpcbiAgICAgICAgZWxlbS5jaGlsZHJlbi5mb3JFYWNoKHdhbGtUYWJsZSk7XG4gICAgICAgIHJldHVybjtcblxuICAgICAgY2FzZSAndHInOiB7XG4gICAgICAgIGJ1aWxkZXIub3BlblRhYmxlUm93KCk7XG4gICAgICAgIGZvciAoY29uc3QgY2hpbGRPZlRyIG9mIGVsZW0uY2hpbGRyZW4pIHtcbiAgICAgICAgICBpZiAoY2hpbGRPZlRyLnR5cGUgIT09ICd0YWcnKSB7IGNvbnRpbnVlOyB9XG4gICAgICAgICAgc3dpdGNoIChjaGlsZE9mVHIubmFtZSkge1xuICAgICAgICAgICAgY2FzZSAndGgnOiB7XG4gICAgICAgICAgICAgIGZvcm1hdEhlYWRlckNlbGwoY2hpbGRPZlRyKTtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYXNlICd0ZCc6IHtcbiAgICAgICAgICAgICAgZm9ybWF0Q2VsbChjaGlsZE9mVHIpO1xuICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgLy8gZG8gbm90aGluZ1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBidWlsZGVyLmNsb3NlVGFibGVSb3coKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAgIC8vIGRvIG5vdGhpbmdcbiAgICB9XG4gIH1cbn1cblxudmFyIHRleHRGb3JtYXR0ZXJzID0gLyojX19QVVJFX18qL09iamVjdC5mcmVlemUoe1xuICBfX3Byb3RvX186IG51bGwsXG4gIGFuY2hvcjogZm9ybWF0QW5jaG9yLFxuICBibG9ja3F1b3RlOiBmb3JtYXRCbG9ja3F1b3RlLFxuICBkYXRhVGFibGU6IGZvcm1hdERhdGFUYWJsZSxcbiAgaGVhZGluZzogZm9ybWF0SGVhZGluZyxcbiAgaG9yaXpvbnRhbExpbmU6IGZvcm1hdEhvcml6b250YWxMaW5lLFxuICBpbWFnZTogZm9ybWF0SW1hZ2UsXG4gIGxpbmVCcmVhazogZm9ybWF0TGluZUJyZWFrLFxuICBvcmRlcmVkTGlzdDogZm9ybWF0T3JkZXJlZExpc3QsXG4gIHBhcmFncmFwaDogZm9ybWF0UGFyYWdyYXBoLFxuICBwcmU6IGZvcm1hdFByZSxcbiAgdGFibGU6IGZvcm1hdFRhYmxlLFxuICB1bm9yZGVyZWRMaXN0OiBmb3JtYXRVbm9yZGVyZWRMaXN0LFxuICB3YnI6IGZvcm1hdFdiclxufSk7XG5cbi8qKlxuICogRGVmYXVsdCBvcHRpb25zLlxuICpcbiAqIEBjb25zdGFudFxuICogQHR5cGUgeyBPcHRpb25zIH1cbiAqIEBkZWZhdWx0XG4gKiBAcHJpdmF0ZVxuICovXG5jb25zdCBERUZBVUxUX09QVElPTlMgPSB7XG4gIGJhc2VFbGVtZW50czoge1xuICAgIHNlbGVjdG9yczogWyAnYm9keScgXSxcbiAgICBvcmRlckJ5OiAnc2VsZWN0b3JzJywgLy8gJ3NlbGVjdG9ycycgfCAnb2NjdXJyZW5jZSdcbiAgICByZXR1cm5Eb21CeURlZmF1bHQ6IHRydWVcbiAgfSxcbiAgZGVjb2RlRW50aXRpZXM6IHRydWUsXG4gIGVuY29kZUNoYXJhY3RlcnM6IHt9LFxuICBmb3JtYXR0ZXJzOiB7fSxcbiAgbGltaXRzOiB7XG4gICAgZWxsaXBzaXM6ICcuLi4nLFxuICAgIG1heEJhc2VFbGVtZW50czogdW5kZWZpbmVkLFxuICAgIG1heENoaWxkTm9kZXM6IHVuZGVmaW5lZCxcbiAgICBtYXhEZXB0aDogdW5kZWZpbmVkLFxuICAgIG1heElucHV0TGVuZ3RoOiAoMSA8PCAyNCkgLy8gMTZfNzc3XzIxNlxuICB9LFxuICBsb25nV29yZFNwbGl0OiB7XG4gICAgZm9yY2VXcmFwT25MaW1pdDogZmFsc2UsXG4gICAgd3JhcENoYXJhY3RlcnM6IFtdXG4gIH0sXG4gIHByZXNlcnZlTmV3bGluZXM6IGZhbHNlLFxuICBzZWxlY3RvcnM6IFtcbiAgICB7IHNlbGVjdG9yOiAnKicsIGZvcm1hdDogJ2lubGluZScgfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2EnLFxuICAgICAgZm9ybWF0OiAnYW5jaG9yJyxcbiAgICAgIG9wdGlvbnM6IHtcbiAgICAgICAgYmFzZVVybDogbnVsbCxcbiAgICAgICAgaGlkZUxpbmtIcmVmSWZTYW1lQXNUZXh0OiBmYWxzZSxcbiAgICAgICAgaWdub3JlSHJlZjogZmFsc2UsXG4gICAgICAgIGxpbmtCcmFja2V0czogWydbJywgJ10nXSxcbiAgICAgICAgbm9BbmNob3JVcmw6IHRydWVcbiAgICAgIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICdhcnRpY2xlJywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdhc2lkZScsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2Jsb2NrcXVvdGUnLFxuICAgICAgZm9ybWF0OiAnYmxvY2txdW90ZScsXG4gICAgICBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHRyaW1FbXB0eUxpbmVzOiB0cnVlIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICdicicsIGZvcm1hdDogJ2xpbmVCcmVhaycgfSxcbiAgICB7IHNlbGVjdG9yOiAnZGl2JywgZm9ybWF0OiAnYmxvY2snLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAxLCB0cmFpbGluZ0xpbmVCcmVha3M6IDEgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdmb290ZXInLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2Zvcm0nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2gxJywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDMsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDInLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMywgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoMycsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAzLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2g0JywgZm9ybWF0OiAnaGVhZGluZycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiwgdXBwZXJjYXNlOiB0cnVlIH0gfSxcbiAgICB7IHNlbGVjdG9yOiAnaDUnLCBmb3JtYXQ6ICdoZWFkaW5nJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyLCB1cHBlcmNhc2U6IHRydWUgfSB9LFxuICAgIHsgc2VsZWN0b3I6ICdoNicsIGZvcm1hdDogJ2hlYWRpbmcnLCBvcHRpb25zOiB7IGxlYWRpbmdMaW5lQnJlYWtzOiAyLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIsIHVwcGVyY2FzZTogdHJ1ZSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ2hlYWRlcicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ2hyJyxcbiAgICAgIGZvcm1hdDogJ2hvcml6b250YWxMaW5lJyxcbiAgICAgIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIGxlbmd0aDogdW5kZWZpbmVkLCB0cmFpbGluZ0xpbmVCcmVha3M6IDIgfVxuICAgIH0sXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICdpbWcnLFxuICAgICAgZm9ybWF0OiAnaW1hZ2UnLFxuICAgICAgb3B0aW9uczogeyBiYXNlVXJsOiBudWxsLCBsaW5rQnJhY2tldHM6IFsnWycsICddJ10gfVxuICAgIH0sXG4gICAgeyBzZWxlY3RvcjogJ21haW4nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ25hdicsIGZvcm1hdDogJ2Jsb2NrJywgb3B0aW9uczogeyBsZWFkaW5nTGluZUJyZWFrczogMSwgdHJhaWxpbmdMaW5lQnJlYWtzOiAxIH0gfSxcbiAgICB7XG4gICAgICBzZWxlY3RvcjogJ29sJyxcbiAgICAgIGZvcm1hdDogJ29yZGVyZWRMaXN0JyxcbiAgICAgIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9XG4gICAgfSxcbiAgICB7IHNlbGVjdG9yOiAncCcsIGZvcm1hdDogJ3BhcmFncmFwaCcsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ3ByZScsIGZvcm1hdDogJ3ByZScsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDIsIHRyYWlsaW5nTGluZUJyZWFrczogMiB9IH0sXG4gICAgeyBzZWxlY3RvcjogJ3NlY3Rpb24nLCBmb3JtYXQ6ICdibG9jaycsIG9wdGlvbnM6IHsgbGVhZGluZ0xpbmVCcmVha3M6IDEsIHRyYWlsaW5nTGluZUJyZWFrczogMSB9IH0sXG4gICAge1xuICAgICAgc2VsZWN0b3I6ICd0YWJsZScsXG4gICAgICBmb3JtYXQ6ICd0YWJsZScsXG4gICAgICBvcHRpb25zOiB7XG4gICAgICAgIGNvbFNwYWNpbmc6IDMsXG4gICAgICAgIGxlYWRpbmdMaW5lQnJlYWtzOiAyLFxuICAgICAgICBtYXhDb2x1bW5XaWR0aDogNjAsXG4gICAgICAgIHJvd1NwYWNpbmc6IDAsXG4gICAgICAgIHRyYWlsaW5nTGluZUJyZWFrczogMixcbiAgICAgICAgdXBwZXJjYXNlSGVhZGVyQ2VsbHM6IHRydWVcbiAgICAgIH1cbiAgICB9LFxuICAgIHtcbiAgICAgIHNlbGVjdG9yOiAndWwnLFxuICAgICAgZm9ybWF0OiAndW5vcmRlcmVkTGlzdCcsXG4gICAgICBvcHRpb25zOiB7IGl0ZW1QcmVmaXg6ICcgKiAnLCBsZWFkaW5nTGluZUJyZWFrczogMiwgdHJhaWxpbmdMaW5lQnJlYWtzOiAyIH1cbiAgICB9LFxuICAgIHsgc2VsZWN0b3I6ICd3YnInLCBmb3JtYXQ6ICd3YnInIH0sXG4gIF0sXG4gIHRhYmxlczogW10sIC8vIGRlcHJlY2F0ZWRcbiAgd2hpdGVzcGFjZUNoYXJhY3RlcnM6ICcgXFx0XFxyXFxuXFxmXFx1MjAwYicsXG4gIHdvcmR3cmFwOiA4MFxufTtcblxuY29uc3QgY29uY2F0TWVyZ2UgPSAoYWNjLCBzcmMsIG9wdGlvbnMpID0+IFsuLi5hY2MsIC4uLnNyY107XG5jb25zdCBvdmVyd3JpdGVNZXJnZSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gWy4uLnNyY107XG5jb25zdCBzZWxlY3RvcnNNZXJnZSA9IChhY2MsIHNyYywgb3B0aW9ucykgPT4gKFxuICAoYWNjLnNvbWUocyA9PiB0eXBlb2YgcyA9PT0gJ29iamVjdCcpKVxuICAgID8gY29uY2F0TWVyZ2UoYWNjLCBzcmMpIC8vIHNlbGVjdG9yc1xuICAgIDogb3ZlcndyaXRlTWVyZ2UoYWNjLCBzcmMpIC8vIGJhc2VFbGVtZW50cy5zZWxlY3RvcnNcbik7XG5cbi8qKlxuICogUHJlcHJvY2VzcyBvcHRpb25zLCBjb21waWxlIHNlbGVjdG9ycyBpbnRvIGEgZGVjaXNpb24gdHJlZSxcbiAqIHJldHVybiBhIGZ1bmN0aW9uIGludGVuZGVkIGZvciBiYXRjaCBwcm9jZXNzaW5nLlxuICpcbiAqIEBwYXJhbSAgIHsgT3B0aW9ucyB9IFtvcHRpb25zID0ge31dICAgSHRtbFRvVGV4dCBvcHRpb25zLlxuICogQHJldHVybnMgeyAoaHRtbDogc3RyaW5nLCBtZXRhZGF0YT86IGFueSkgPT4gc3RyaW5nIH0gUHJlLWNvbmZpZ3VyZWQgY29udmVydGVyIGZ1bmN0aW9uLlxuICogQHN0YXRpY1xuICovXG5mdW5jdGlvbiBjb21waWxlIChvcHRpb25zID0ge30pIHtcbiAgb3B0aW9ucyA9IG1lcmdlKFxuICAgIERFRkFVTFRfT1BUSU9OUyxcbiAgICBvcHRpb25zLFxuICAgIHtcbiAgICAgIGFycmF5TWVyZ2U6IG92ZXJ3cml0ZU1lcmdlLFxuICAgICAgY3VzdG9tTWVyZ2U6IChrZXkpID0+ICgoa2V5ID09PSAnc2VsZWN0b3JzJykgPyBzZWxlY3RvcnNNZXJnZSA6IHVuZGVmaW5lZClcbiAgICB9XG4gICk7XG4gIG9wdGlvbnMuZm9ybWF0dGVycyA9IE9iamVjdC5hc3NpZ24oe30sIGdlbmVyaWNGb3JtYXR0ZXJzLCB0ZXh0Rm9ybWF0dGVycywgb3B0aW9ucy5mb3JtYXR0ZXJzKTtcbiAgb3B0aW9ucy5zZWxlY3RvcnMgPSBtZXJnZUR1cGxpY2F0ZXNQcmVmZXJMYXN0KG9wdGlvbnMuc2VsZWN0b3JzLCAocyA9PiBzLnNlbGVjdG9yKSk7XG5cbiAgaGFuZGxlRGVwcmVjYXRlZE9wdGlvbnMob3B0aW9ucyk7XG5cbiAgcmV0dXJuIGNvbXBpbGUkMShvcHRpb25zKTtcbn1cblxuLyoqXG4gKiBDb252ZXJ0IGdpdmVuIEhUTUwgY29udGVudCB0byBwbGFpbiB0ZXh0IHN0cmluZy5cbiAqXG4gKiBAcGFyYW0gICB7IHN0cmluZyB9ICBodG1sICAgICAgICAgICBIVE1MIGNvbnRlbnQgdG8gY29udmVydC5cbiAqIEBwYXJhbSAgIHsgT3B0aW9ucyB9IFtvcHRpb25zID0ge31dIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAqIEBwYXJhbSAgIHsgYW55IH0gICAgIFttZXRhZGF0YV0gICAgIE9wdGlvbmFsIG1ldGFkYXRhIGZvciBIVE1MIGRvY3VtZW50LCBmb3IgdXNlIGluIGZvcm1hdHRlcnMuXG4gKiBAcmV0dXJucyB7IHN0cmluZyB9ICAgICAgICAgICAgICAgICBQbGFpbiB0ZXh0IHN0cmluZy5cbiAqIEBzdGF0aWNcbiAqXG4gKiBAZXhhbXBsZVxuICogY29uc3QgeyBjb252ZXJ0IH0gPSByZXF1aXJlKCdodG1sLXRvLXRleHQnKTtcbiAqIGNvbnN0IHRleHQgPSBjb252ZXJ0KCc8aDE+SGVsbG8gV29ybGQ8L2gxPicsIHtcbiAqICAgd29yZHdyYXA6IDEzMFxuICogfSk7XG4gKiBjb25zb2xlLmxvZyh0ZXh0KTsgLy8gSEVMTE8gV09STERcbiAqL1xuZnVuY3Rpb24gY29udmVydCAoaHRtbCwgb3B0aW9ucyA9IHt9LCBtZXRhZGF0YSA9IHVuZGVmaW5lZCkge1xuICByZXR1cm4gY29tcGlsZShvcHRpb25zKShodG1sLCBtZXRhZGF0YSk7XG59XG5cbi8qKlxuICogTWFwIHByZXZpb3VzbHkgZXhpc3RpbmcgYW5kIG5vdyBkZXByZWNhdGVkIG9wdGlvbnMgdG8gdGhlIG5ldyBvcHRpb25zIGxheW91dC5cbiAqIFRoaXMgaXMgYSBzdWJqZWN0IGZvciBjbGVhbnVwIGluIG1ham9yIHJlbGVhc2VzLlxuICpcbiAqIEBwYXJhbSB7IE9wdGlvbnMgfSBvcHRpb25zIEh0bWxUb1RleHQgb3B0aW9ucy5cbiAqL1xuZnVuY3Rpb24gaGFuZGxlRGVwcmVjYXRlZE9wdGlvbnMgKG9wdGlvbnMpIHtcbiAgaWYgKG9wdGlvbnMudGFncykge1xuICAgIGNvbnN0IHRhZ0RlZmluaXRpb25zID0gT2JqZWN0LmVudHJpZXMob3B0aW9ucy50YWdzKS5tYXAoXG4gICAgICAoW3NlbGVjdG9yLCBkZWZpbml0aW9uXSkgPT4gKHsgLi4uZGVmaW5pdGlvbiwgc2VsZWN0b3I6IHNlbGVjdG9yIHx8ICcqJyB9KVxuICAgICk7XG4gICAgb3B0aW9ucy5zZWxlY3RvcnMucHVzaCguLi50YWdEZWZpbml0aW9ucyk7XG4gICAgb3B0aW9ucy5zZWxlY3RvcnMgPSBtZXJnZUR1cGxpY2F0ZXNQcmVmZXJMYXN0KG9wdGlvbnMuc2VsZWN0b3JzLCAocyA9PiBzLnNlbGVjdG9yKSk7XG4gIH1cblxuICBmdW5jdGlvbiBzZXQgKG9iaiwgcGF0aCwgdmFsdWUpIHtcbiAgICBjb25zdCB2YWx1ZUtleSA9IHBhdGgucG9wKCk7XG4gICAgZm9yIChjb25zdCBrZXkgb2YgcGF0aCkge1xuICAgICAgbGV0IG5lc3RlZCA9IG9ialtrZXldO1xuICAgICAgaWYgKCFuZXN0ZWQpIHtcbiAgICAgICAgbmVzdGVkID0ge307XG4gICAgICAgIG9ialtrZXldID0gbmVzdGVkO1xuICAgICAgfVxuICAgICAgb2JqID0gbmVzdGVkO1xuICAgIH1cbiAgICBvYmpbdmFsdWVLZXldID0gdmFsdWU7XG4gIH1cblxuICBpZiAob3B0aW9uc1snYmFzZUVsZW1lbnQnXSkge1xuICAgIGNvbnN0IGJhc2VFbGVtZW50ID0gb3B0aW9uc1snYmFzZUVsZW1lbnQnXTtcbiAgICBzZXQoXG4gICAgICBvcHRpb25zLFxuICAgICAgWydiYXNlRWxlbWVudHMnLCAnc2VsZWN0b3JzJ10sXG4gICAgICAoQXJyYXkuaXNBcnJheShiYXNlRWxlbWVudCkgPyBiYXNlRWxlbWVudCA6IFtiYXNlRWxlbWVudF0pXG4gICAgKTtcbiAgfVxuICBpZiAob3B0aW9uc1sncmV0dXJuRG9tQnlEZWZhdWx0J10gIT09IHVuZGVmaW5lZCkge1xuICAgIHNldChvcHRpb25zLCBbJ2Jhc2VFbGVtZW50cycsICdyZXR1cm5Eb21CeURlZmF1bHQnXSwgb3B0aW9uc1sncmV0dXJuRG9tQnlEZWZhdWx0J10pO1xuICB9XG5cbiAgZm9yIChjb25zdCBkZWZpbml0aW9uIG9mIG9wdGlvbnMuc2VsZWN0b3JzKSB7XG4gICAgaWYgKGRlZmluaXRpb24uZm9ybWF0ID09PSAnYW5jaG9yJyAmJiBnZXQoZGVmaW5pdGlvbiwgWydvcHRpb25zJywgJ25vTGlua0JyYWNrZXRzJ10pKSB7XG4gICAgICBzZXQoZGVmaW5pdGlvbiwgWydvcHRpb25zJywgJ2xpbmtCcmFja2V0cyddLCBmYWxzZSk7XG4gICAgfVxuICB9XG59XG5cbmV4cG9ydCB7IGNvbXBpbGUsIGNvbnZlcnQsIGNvbnZlcnQgYXMgaHRtbFRvVGV4dCB9O1xuIl0sIm5hbWVzIjpbXSwiaWdub3JlTGlzdCI6WzBdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///(action-browser)/./node_modules/.pnpm/html-to-text@9.0.5/node_modules/html-to-text/lib/html-to-text.mjs\n");
|
|
|
|
/***/ })
|
|
|
|
};
|
|
; |