Subversion Repository Public Repository

Nextrek

Diff Revisions 1084 vs 1086 for /s2s/data/A597C1D0K3983A48BBSAC37E1E30D2F97314.json

Diff revisions: vs.
  @@ -6,10 +6,10 @@
6 6 "name": "Component_TextRenderer",
7 7 "type": "game_script",
8 8 "order": 10,
9 - "content": "# ===================================================================\n#\n# Script: Component_TextRenderer\n#\n# $$COPYRIGHT$$\n#\n# ===================================================================\n\nclass RendererTextLine\n ###*\n * Stores a text line.\n * \n * @module gs.RendererTextLine\n * @class RendererTextLine\n * @memberof gs.RendererTextLine\n * @constructor\n ###\n constructor: ->\n ###\n * The width of the line in pixels.\n * @property width\n * @type number\n * @protected\n ###\n @width = 0\n ###\n * The height of the line in pixels.\n * @property width\n * @type number\n * @protected\n ###\n @height = 0\n ###\n * The descent of the line in pixels.\n * @property descent\n * @type number\n * @protected\n ###\n @descent = 0\n ###\n * The content of the line as token objects.\n * @property content\n * @type Object[]\n * @protected\n ###\n @content = []\n \ngs.RendererTextLine = RendererTextLine\n\nclass RendererToken\n ###*\n * Stores a token.\n * \n * @module gs\n * @class RendererToken\n * @memberof gs\n * @constructor\n ###\n constructor: (code, value, font) ->\n ###\n * The value of the token. That value depends on the token type. For text-tokens, it stores\n * the actual text.\n * @property content\n * @type string\n ###\n @value = value\n ###\n * The code describes what kind of token it is. For example, if the code is \"Y\" it means it is a\n * style-token. If the code is <b>null</b>, it means it is a text-token.\n * @property code\n * @type string\n ###\n @code = code\n ###\n * The format stores the font-style properties of the token like if it is italic, bold, etc. It can be <b>null</b>.\n * @property format\n * @type Object\n ###\n @format = null\n \n @takeFormat(font) if font?\n \n ###*\n * Takes the style from the specified font and stores it into the format-property. The token will\n * will be rendered with that style then.\n * \n * @method takeFormat\n * @param {gs.Font} font - The font to take the style from.\n ###\n takeFormat: (font) ->\n @format = font.toDataBundle()\n \n ###*\n * Applies the format-style of the token on the specified font. The font will have the style from\n * then token then.\n * \n * @method applyFormat\n * @param {gs.Font} font - The font to apply the format-style on.\n ### \n applyFormat: (font) ->\n font.set(@format)\n \ngs.RendererToken = RendererToken\n\nclass Component_TextRenderer extends gs.Component\n ###*\n * A text-renderer component allow to draw plain or formatted text on a\n * game object's bitmap. For formatted text, different text-codes can be\n * used to add formatting or define a placeholder.<br><br>\n * \n * A text-code uses the following syntax:<br><br>\n * \n * {code:value} <- Single Value<br />\n * {code:value1,value2,...} <- Multiple Values<br><br>\n * \n * Example:<br><br>\n * \n * \"This is {Y:I}a Text{Y:N}\" <- \"a Text\" will be italic here.<br>\n * \"The value is {GN:1}\" <- \"{GN:1}\" will be replaced for the value of the global number variable 0001.<br><br>\n * \n * For a list of all available text-codes with examples, just take a look into the offical help-file.\n * \n * @module gs\n * @class Component_TextRenderer\n * @extends gs.Component\n * @memberof gs\n * @constructor\n ###\n constructor: ->\n super\n \n ###*\n * @property currentX\n * @type number\n * @protected\n ###\n @currentX = 0\n \n ###*\n * @property currentY\n * @type number\n * @protected\n ###\n @currentY = 0\n \n ###*\n * @property currentLineHeight\n * @type number\n * @protected\n ###\n @currentLineHeight = 0\n \n ###*\n * @property font\n * @type gs.Font\n * @protected\n ###\n @font = new Font(\"Times New Roman\", 22)\n \n ###*\n * @property spaceSize\n * @type number\n * @protected\n ###\n @spaceSize = 0\n \n ###*\n * @property fontSize\n * @type number\n * @protected\n ###\n @fontSize = 0\n \n ###*\n * The left and right padding per line.\n * @property padding\n * @type number\n ###\n @padding = 0\n \n ###*\n * The spacing between text lines in pixels.\n * @property lineSpacing\n * @type number\n ###\n @lineSpacing = 0\n \n ###*\n * Creates the token-object for a list-placeholder. A list-placeholder\n * allows to insert a value from a list-variable.\n * \n * @method createListToken\n * @param {Array} list - The list.\n * @param {Array} values - The values of the list-placeholder text-code.\n * @return {string} The token-object.\n ###\n createListToken: (list, values) ->\n index = 0\n if values[1]?\n values = values[1].split(\":\")\n index = values[0]\n if values[0] == \"G\"\n index = GameManager.variableStore.numbers[parseInt(values[1])-1]\n else if values[0] == \"P\"\n index = GameManager.variableStore.persistentNumbers[parseInt(values[1])-1]\n else if values[0] == \"L\"\n index = GameManager.variableStore.numberValueOf({ scope: 0, index: parseInt(values[1])-1})\n \n return \"\" + list[index]\n \n \n ###*\n * Parses and returns the variable identifier which is an array containing\n * the optional domain name and the variable index as: [domain, index].\n * \n * @method parseVariableIdentifier\n * @param {string} identifier - The variable identifier e.g. com.degica.vnm.default.1 or com.degica.vnm.default.VarName\n * @param {string} type - The variable type to parse: number, string, boolean or list\n * @param {string} type - The scope of the variable to parse: 0 = local, 1 = global, 2 = persistent.\n * @return {Array} An array containing two values as: [domain, index]. If the identifier doesn't contain a domain-string, the domain will be 0 (default).\n ### \n parseVariableIdentifier: (identifier, type, scope) ->\n result = [0, identifier]\n \n if isNaN(identifier)\n index = identifier.lastIndexOf(\".\")\n if index != -1\n result[0] = identifier.substring(0, index)\n result[1] = identifier.substring(index+1)\n if isNaN(result[1])\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1\n else\n result[1] = parseInt(result[1])\n else\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1\n else\n result[1] = parseInt(result[1])\n \n return result\n \n ###*\n * Creates a token-object for a specified text-code.\n * \n * @method createToken\n * @param {string} code - The code/type of the text-code.\n * @param {string} value - The value of the text-code.\n * @return {Object} The token-object.\n ###\n createToken: (code, value) ->\n tokenObject = null\n value = if isNaN(value) then value else parseInt(value)\n switch code\n when \"SZ\" \n tokenObject = new gs.RendererToken(code, value)\n @font.size = tokenObject.value || @fontSize\n @spaceSize = @font.measureTextPlain(\" \")\n when \"Y\"\n tokenObject = { code: code, value: value }\n switch value\n when \"U\" then @font.underline = yes\n when \"S\" then @font.strikeThrough = yes\n when \"I\" then @font.italic = yes\n when \"B\" then @font.bold = yes\n when \"C\" then @font.smallCaps = yes\n when \"NU\" then @font.underline = no\n when \"NS\" then @font.strikeThrough = no\n when \"NI\" then @font.italic = no\n when \"NB\" then @font.bold = no\n when \"NC\" then @font.smallCaps = no\n when \"N\"\n @font.underline = no\n @font.strikeThrough = no\n @font.italic = no\n @font.bold = no\n @font.smallCaps = no\n @spaceSize = @font.measureTextPlain(\" \")\n when \"C\"\n tokenObject = new gs.RendererToken(code, value)\n if value <= 0\n @font.color = Font.defaultColor\n else\n @font.color = gs.Color.fromObject(RecordManager.system.colors[value-1] || Font.defaultColor)\n when \"GN\"\n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1]\n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 1)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.numbersByDomain[values[0]||0][values[1]-1] || 0))\n else\n values = @parseVariableIdentifier(values[0], \"number\", 1)\n tokenObject = (GameManager.variableStore.numbersByDomain[values[0]||0][values[1]-1] || 0).toString()\n when \"GT\" \n values = @parseVariableIdentifier(value, \"string\", 1)\n tokenObject = (GameManager.variableStore.stringsByDomain[values[0]||0][values[1]-1] || \"\")\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"GS\"\n \n values = @parseVariableIdentifier(value, \"boolean\", 1)\n tokenObject = (GameManager.variableStore.booleansByDomain[values[0]||0][values[1]-1] || false).toString()\n when \"GL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 1)\n tokenObject = @createListToken(GameManager.variableStore.listsByDomain[listIdentifier[0]][listIdentifier[1]-1] || [], values)\n when \"PN\"\n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1]\n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 2)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.persistentNumbers[values[0]][values[1]-1] || 0))\n else\n tokenObject = (GameManager.variableStore.persistentNumbers[0][values[0]-1] || 0).toString()\n when \"PT\" \n values = @parseVariableIdentifier(value, \"string\", 2)\n tokenObject = (GameManager.variableStore.persistentStrings[values[0]][values[1]-1] || \"\")\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"PS\"\n values = @parseVariableIdentifier(value, \"boolean\", 2)\n tokenObject = (GameManager.variableStore.persistentBooleans[values[0]][values[1]-1] || false).toString()\n when \"PL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 2)\n tokenObject = @createListToken(GameManager.variableStore.persistentLists[listIdentifier[0]][listIdentifier[1]-1] || [], values)\n when \"LN\" \n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1] \n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 0)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.numberValueOf({ scope: 0, index: values[1]-1}) || 0))\n else\n values = @parseVariableIdentifier(values[0], \"number\", 0)\n tokenObject = (GameManager.variableStore.numberValueOf({ scope: 0, index: values[1]-1}) || 0).toString()\n when \"LT\" \n values = @parseVariableIdentifier(value, \"string\", 0)\n tokenObject = (GameManager.variableStore.stringValueOf({ scope: 0, index: values[1]-1}) || \"\").toString()\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"LS\"\n values = @parseVariableIdentifier(value, \"boolean\", 0)\n tokenObject = (GameManager.variableStore.booleanValueOf({ scope: 0, index: values[1]-1}) || false).toString()\n when \"LL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 0)\n tokenObject = @createListToken(GameManager.variableStore.listObjectOf({ scope: 0, index: listIdentifier[1]-1}) || [], values)\n when \"N\" \n tokenObject = (if RecordManager.characters[value]? then lcs(RecordManager.characters[value].name) else \"\")\n when \"RT\"\n pair = value.split(\"/\")\n tokenObject = { code: code, rtStyleId: pair[2] ? 0, rb: pair[0], rt: pair[1], rbSize: { width: 0, height: 0 }, rtSize: { width: 0, height: 0 } }\n when \"M\"\n macro = RecordManager.system.textMacros.first (m) -> m.name == value\n if macro\n if macro.type == 0 # Text + Codes\n tokenObject = macro.content.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n tokenObject.pop()\n else if macro.type == 1 # Placeholder Script Macro\n if !macro.contentFunc\n macro.contentFunc = eval(\"(function(object, value){ #{macro.content} })\")\n tokenObject = macro.contentFunc(@object, value)\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else # Script Macro\n if !macro.contentFunc\n macro.contentFunc = eval(\"(function(object){ #{macro.content} })\")\n tokenObject = new gs.RendererToken(\"X\", macro.contentFunc)\n else\n tokenObject = \"\"\n else \n tokenObject = new gs.RendererToken(code, value)\n \n return tokenObject\n \n \n ###*\n * <p>Gets the correct font for the specified ruby-text token.</p> \n *\n * @param {Object} token - A ruby-text token.\n * @return {gs.Font} The font for the ruby-text which is shown above the original text.\n * @method getRubyTextFont\n ### \n getRubyTextFont: (token) ->\n style = null\n font = null\n \n if token.rtStyleId\n style = ui.UIManager.styles[\"rubyText-\"+token.rtStyleId]\n \n if !style\n style = ui.UIManager.styles[\"rubyText\"]\n \n font = style?.font ? @font\n font.size = font.size || @font.size / 2\n \n return font\n \n ###*\n * <p>Measures a control-token. If a token produces a visual result like displaying an icon then it must return the size taken by\n * the visual result. If the token has no visual result, <b>null</b> must be returned. This method is called for every token when the message is initialized.</p> \n *\n * @param {Object} token - A control-token.\n * @return {gs.Size} The size of the area taken by the visual result of the token or <b>null</b> if the token has no visual result.\n * @method measureControlToken\n * @protected\n ### \n measureControlToken: (token) -> # Can be implemented by derived classes\n size = null\n \n switch token.code\n when \"A\" # Animation\n animation = RecordManager.animations[Math.max(token.value-1, 0)]\n if animation?.graphic.name?\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/#{animation.graphic.name}\")\n if imageBitmap?\n size = width: Math.round(imageBitmap.width / animation.framesX), height: Math.round(imageBitmap.height / animation.framesY)\n when \"RT\" # Ruby Text\n font = @getRubyTextFont(token)\n fs = font.size\n font.size = font.size || @font.size / 2\n token.rbSize = @font.measureTextPlain(token.rb)\n token.rtSize = font.measureTextPlain(token.rt)\n font.size = fs\n \n size = width: Math.max(token.rbSize.width, token.rtSize.width), height: token.rbSize.height + token.rtSize.height\n \n return size\n \n ###*\n * <p>Draws the visual result of a token, like an icon for example, to the specified bitmap. This method is called for every token while the text is rendered.</p> \n *\n * @param {Object} token - A control-token.\n * @param {gs.Bitmap} bitmap - The bitmap used for the current text-line. Can be used to draw something on it like an icon, etc.\n * @param {number} offset - An x-offset for the draw-routine.\n * @method drawControlToken\n * @protected\n ###\n drawControlToken: (token, bitmap, offset) ->\n switch token.code\n when \"A\" # Animation\n animation = RecordManager.animations[Math.max(token.value-1, 0)]\n if animation?.graphic.name?\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/#{animation.graphic.name}\")\n if imageBitmap?\n rect = new gs.Rect(0, 0, Math.round(imageBitmap.width / animation.framesX), Math.round(imageBitmap.height / animation.framesY))\n bitmap.blt(offset, @currentY, imageBitmap, rect)\n when \"RT\" \n style = null\n if token.rtStyleId\n style = ui.UIManager.styles[\"rubyText-\"+token.rtStyleId]\n if !style\n style = ui.UIManager.styles[\"rubyText\"]\n \n font = style?.font ? @font\n fs = font.size\n font.size = font.size || @font.size / 2\n \n if style and !style.descriptor.font?.color\n font.color.set(@font.color)\n \n bitmap.font = font\n bitmap.drawText(offset, bitmap.font.descent, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rt, 1, 0)\n bitmap.font = @font\n font.size = fs\n bitmap.drawText(offset, token.rtSize.height, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rb, 1, 0)\n \n \n ###*\n * Splits up the specified token using a japanese word-wrap technique.\n * \n * @method wordWrapJapanese\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapJapanese: (token, line, width, height, result) ->\n startOfLine = '—…‥〳〴〵。.・、:;, ?!‼⁇⁈⁉‐゠–〜)]}〕〉》」』】〙〗〟’\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻'\n endOfLine = '([{〔〈《「『【〘〖〝‘\"⦅«'\n noSplit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789—…‥〳〴〵'\n descent = @font.descent\n size = @font.measureTextPlain(token)\n depth = 8\n depthLevel = 0\n i = 0\n j = 0\n lastCharacterIndex = 0\n \n if size.width > @object.dstRect.width-@spaceSize.width*3-@padding*2\n while i < token.length\n ch = token[i]\n size = @font.measureTextPlain(ch)\n width += size.width\n moved = no\n if width > @object.dstRect.width - @padding*2\n depthLevel = 0\n j = i\n \n loop\n moved = no\n \n while j > 0 and startOfLine.indexOf(token[j]) != -1\n j--\n moved = yes\n \n while j > 0 and endOfLine.indexOf(token[j-1]) != -1\n j--\n moved = yes\n \n while j > 0 and noSplit.indexOf(token[j-1]) != -1\n j--\n moved = yes\n \n if j == 0 and moved\n break\n else\n i = j\n \n depthLevel++\n break if depthLevel >= depth or !moved\n \n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), @font))\n lastCharacterIndex = i\n line.height = Math.max(height, @font.lineHeight)\n line.width = width - size.width\n line.descent = descent\n descent = @font.descent\n height = size.height\n result.push(line)\n line = new gs.RendererTextLine()\n width = width - (width - size.width)\n \n i++\n else\n line.content.push(new gs.RendererToken(null, token, @font))\n line.height = Math.max(height, @font.lineHeight)\n line.width = width + size.width\n line.descent = descent\n \n height = Math.max(height, @font.lineHeight) \n \n if lastCharacterIndex != i\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), @font))\n line.width = width\n line.height = Math.max(height, line.height)\n line.descent = descent\n \n return line\n \n \n ###*\n * Does not word-wrapping at all. It just adds the text token to the line as is.\n * \n * @method wordWrapNone\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapNone: (token, line, width, height, result) ->\n size = @font.measureTextPlain(token)\n height = Math.max(size.height, height || @font.lineHeight) \n \n if token.length > 0 \n line.width += size.width\n line.height = Math.max(height, line.height)\n line.descent = @font.descent\n line.content.push(new gs.RendererToken(null, token))\n \n return line\n \n ###*\n * Splits up the specified token using a space-based word-wrap technique.\n * \n * @method wordWrapSpaceBased\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapSpaceBased: (token, line, width, height, result) ->\n currentWords = []\n words = token.split(\" \")\n descent = @font.descent\n @spaceSize = @font.measureTextPlain(\" \")\n \n for word, i in words\n size = @font.measureTextPlain(word)\n width += size.width + @spaceSize.width\n \n if width > @object.dstRect.width - @padding*2\n token = new gs.RendererToken(null, currentWords.join(\" \"))\n token.takeFormat(@font)\n line.content.push(token)\n line.height = Math.max(height, line.height)\n line.width = width - size.width\n line.descent = Math.max(line.descent, descent)\n descent = Math.max(descent, @font.descent)\n height = size.height\n result.push(line)\n line = new gs.RendererTextLine()\n currentWords = [word]\n width = width - (width - size.width)\n else\n currentWords.push(word)\n \n height = Math.max(height, @font.lineHeight) \n \n if currentWords.length > 0\n token = new gs.RendererToken(null, currentWords.join(\" \"))\n token.takeFormat(@font)\n line.content.push(token)\n line.width = width\n line.height = Math.max(height, line.height)\n line.descent = Math.max(descent, line.descent)\n \n return line\n \n ###*\n * Splits up the specified token using a word-wrap technique. The kind of word-wrap technique\n * depends on the selected language. You can overwrite this method in derived classes to implement your\n * own custom word-wrap techniques.\n * \n * @method executeWordWrap\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ###\n executeWordWrap: (token, line, width, height, result, wordWrap) ->\n if wordWrap\n switch LanguageManager.language.wordWrap\n when \"spaceBased\"\n @wordWrapSpaceBased(token, line, width, height, result)\n when \"japanese\"\n @wordWrapJapanese(token, line, width, height, result)\n else\n @wordWrapNone(token, line, width, height, result)\n \n \n ###*\n * Creates an a of line-objects. Each line-object is a list of token-objects. \n * A token-object can be just a string or an object containing more information\n * about how to process the token at runtime.\n * \n * A line-object also contains additional information like the width and height\n * of the line(in pixels).\n * \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n * \n * @method calculateLines\n * @param {string} message - A message creating the line-objects for.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @param {number} [firstLineWidth=0] - The current width of the first line.\n * @return {Array} An array of line-objects.\n ###\n calculateLines: (message, wordWrap, firstLineWidth) ->\n result = []\n line = new gs.RendererTextLine()\n width = firstLineWidth || 0\n height = 0\n descent = @font.descent\n currentWords = []\n size = null\n @spaceSize = @font.measureChar(\" \")\n @fontSize = @font.size\n \n tokens = message.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n token = null\n t = 0\n \n underline = @font.underline\n strikeThrough = @font.strikeThrough\n italic = @font.italic\n bold = @font.bold\n smallCaps = @font.smallCaps\n \n while t < tokens.length\n token = tokens[t]\n \n if t % 4 != 0\n if token?\n tokenObject = @createToken(token, tokens[t+1])\n \n if tokenObject.push?\n Array.prototype.splice.apply(tokens, [t+3, 0].concat(tokenObject))\n else if not tokenObject.code?\n tokens[t+3] = tokenObject + tokens[t+3]\n else\n size = @measureControlToken(tokenObject)\n if size\n width += size.width\n height = Math.max(height, size.height)\n #descent = Math.max(@font.descent, descent)\n line.content.push(tokenObject)\n else # Must be a new-line\n line.height = height || @font.lineHeight\n line.width = width\n line.descent = descent\n result.push(line)\n line = new gs.RendererTextLine()\n line.content.push(new gs.RendererToken(null, \"\\n\", @font))\n width = 0\n height = 0\n descent = @font.descent\n t += 2\n else if token.length > 0\n line = @executeWordWrap(token, line, width, height, result, wordWrap)\n width = line.width\n height = line.height\n descent = line.descent\n \n t++\n \n if line.content.length > 0 or result.length == 0\n line.height = height\n line.width = width\n line.descent = descent\n result.push(line)\n \n \n @font.size = @fontSize \n @font.underline = underline\n @font.strikeThrough = strikeThrough\n @font.italic = italic\n @font.bold = bold\n @font.smallCaps = smallCaps\n \n return result\n \n \n ###*\n * Measures the dimensions of formatted lines in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedLines\n * @param {gs.RendererTextLine[]} lines - An array of text lines to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureFormattedLines: (lines, wordWrap) ->\n size = width: 0, height: 0\n \n for line in lines\n size.width = Math.max(line.width+2, size.width)\n size.height += line.height + @lineSpacing\n\n size.height -= @lineSpacing\n \n return size\n \n ###*\n * Measures the dimensions of a formatted text in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedText\n * @param {string} text - The text to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureFormattedText: (text, wordWrap) ->\n @font.set(@object.font)\n size = null\n lines = @calculateLines(text, wordWrap)\n \n size = @measureFormattedLines(lines, wordWrap)\n \n return size\n \n ###*\n * Measures the dimensions of a plain text in pixels. Formatting and\n * word-wrapping are not supported.\n *\n * @method measureText\n * @param {string} text - The text to measure.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureText: (text) ->\n size = width: 0, height: 0\n lines = text.toString().split(\"\\n\")\n\n for line in lines\n lineSize = @object.font.measureText(text)\n size.width = Math.max(size.width, lineSize.width)\n size.height += @object.font.lineHeight + @lineSpacing\n \n size.height -= @lineSpacing\n \n return size\n \n ###*\n * Searches for a token in a list of tokens and returns the first match.\n *\n * @method findToken\n * @param {number} startIndex - The index in the list of tokens where the search will start.\n * @param {string} code - The code of the token to search for.\n * @param {number} direction - The search direction, can be forward(1) or backward(-1).\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object} The first token which matches the specified code or <b>null</b> if the token cannot be found.\n ### \n findToken: (startIndex, code, direction, tokens) ->\n token = null\n i = startIndex\n if direction == -1\n while i >= 0\n t = tokens[i]\n if t.code == code\n token = t\n break\n i--\n \n return token\n \n ###*\n * Searches for a specific kind of tokens between a start and an end token.\n *\n * @method findTokensBetween\n * @param {number} startIndex - The index where the search will start.\n * @param {number} endIndex - The index where the search will end.\n * @param {string} code - The code of the token-type to search for.\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object[]} List of tokens matching the specified code. Its an empty list if no tokens were found.\n ### \n findTokensBetween: (startIndex, endIndex, code, tokens) ->\n result = []\n s = startIndex\n e = endIndex\n \n while s < e\n token = tokens[s]\n if `token.code == code`\n result.push(token)\n s++\n \n return result\n \n ###*\n * Processes a control-token. A control-token is a token which influences\n * the text-rendering like changing the fonts color, size or style.\n *\n * Changes will be automatically applied to the game object's font.\n *\n * @method processControlToken\n * @param {Object} token - A control-token.\n * @return {Object} An object which can contain additional info needed for processing.\n ###\n processControlToken: (token) ->\n result = null\n \n switch token.code\n when \"SZ\"\n @object.font.size = token.value || @fontSize\n when \"C\"\n if token.value <= 0\n @object.font.color = Font.defaultColor\n else\n @object.font.color = RecordManager.system.colors[token.value-1] || Font.defaultColor\n when \"Y\"\n switch token.value\n when \"U\" then @object.font.underline = yes\n when \"S\" then @object.font.strikeThrough = yes\n when \"I\" then @object.font.italic = yes\n when \"B\" then @object.font.bold = yes\n when \"C\" then @object.font.smallCaps = yes\n when \"NU\" then @object.font.underline = no\n when \"NS\" then @object.font.strikeThrough = no\n when \"NI\" then @object.font.underline = no\n when \"NB\" then @object.font.bold = no\n when \"NC\" then @object.font.smallCaps = no\n when \"N\"\n @object.font.underline = no\n @object.font.strikeThrough = no\n @object.font.italic = no\n @object.font.bold = no\n @object.font.smallCaps = no\n \n return result\n \n ###*\n * Draws a plain text. Formatting and word-wrapping are not supported.\n *\n * @method drawText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n ###\n drawText: (pl, pt, pr, pb, text) ->\n lines = text.toString().split(\"\\n\")\n font = @object.font\n height = font.lineHeight\n \n for line, i in lines\n size = font.measureText(line)\n @object.bitmap.drawText(pl, i * height + pt, size.width + pr+pl, height+pt+pb, line, 0, 0)\n \n return null\n \n ###*\n * Draws an array of formatted text lines. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedLines\n * @param {number} pl - The left-padding of the text's position.\n * @param {number} pt - The top-padding of the text's position.\n * @param {number} pr - The right-padding of the text's position.\n * @param {number} pb - The bottom-padding of the text's position.\n * @param {gs.RendererTextLine[]} lines - An array of lines to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n ### \n drawFormattedLines: (pl, pt, pr, pb, lines, wordWrap) ->\n @currentX = pl\n @currentY = pt\n @currentLineHeight = 0\n \n for line in lines\n for token in line.content\n if token.code?\n @processControlToken(token)\n size = @measureControlToken(token)\n if size\n @drawControlToken(token, @object.bitmap, @currentX)\n @currentX += size.width\n else if token.value.length > 0\n font = @object.font\n height = line.height\n if token.value != \"\\n\"\n size = font.measureTextPlain(token.value)\n @object.bitmap.drawText(@currentX, @currentY + height - size.height + font.descent - line.descent, size.width+pl+pr, height+pt+pb, token.value, 0, 0)\n @currentX += size.width\n @currentLineHeight = Math.max(@currentLineHeight, height)\n @currentY += (@currentLineHeight || @object.font.lineHeight) + @lineSpacing\n @currentX = pl\n @currentLineHeight = 0\n \n return null\n \n ###*\n * Draws a formatted text. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @return {gs.RendererTextLine[]} The drawn text lines.\n ###\n drawFormattedText: (pl, pt, pr, pb, text, wordWrap) ->\n lines = @calculateLines(text.toString(), wordWrap)\n \n @drawFormattedLines(pl, pt, pr, pb, lines, wordWrap)\n \n return lines\n \ngs.Component_TextRenderer = Component_TextRenderer",
9 + "content": "# ===================================================================\n#\n# Script: Component_TextRenderer\n#\n# $$COPYRIGHT$$\n#\n# ===================================================================\n\nclass RendererTextLine\n ###*\n * Stores a text line.\n * \n * @module gs.RendererTextLine\n * @class RendererTextLine\n * @memberof gs.RendererTextLine\n * @constructor\n ###\n constructor: ->\n ###\n * The width of the line in pixels.\n * @property width\n * @type number\n * @protected\n ###\n @width = 0\n ###\n * The height of the line in pixels.\n * @property width\n * @type number\n * @protected\n ###\n @height = 0\n ###\n * The descent of the line in pixels.\n * @property descent\n * @type number\n * @protected\n ###\n @descent = 0\n ###\n * The content of the line as token objects.\n * @property content\n * @type Object[]\n * @protected\n ###\n @content = []\n \ngs.RendererTextLine = RendererTextLine\n\nclass RendererToken\n ###*\n * Stores a token.\n * \n * @module gs\n * @class RendererToken\n * @memberof gs\n * @constructor\n ###\n constructor: (code, value, font) ->\n ###\n * The value of the token. That value depends on the token type. For text-tokens, it stores\n * the actual text.\n * @property content\n * @type string\n ###\n @value = value\n ###\n * The code describes what kind of token it is. For example, if the code is \"Y\" it means it is a\n * style-token. If the code is <b>null</b>, it means it is a text-token.\n * @property code\n * @type string\n ###\n @code = code\n ###\n * The format stores the font-style properties of the token like if it is italic, bold, etc. It can be <b>null</b>.\n * @property format\n * @type Object\n ###\n @format = null\n ###\n * A plain object to store custom data within the token.\n * @property customData\n * @type Object\n ###\n @customData = {}\n \n @takeFormat(font) if font?\n \n ###*\n * Takes the style from the specified font and stores it into the format-property. The token will\n * will be rendered with that style then.\n * \n * @method takeFormat\n * @param {gs.Font} font - The font to take the style from.\n ###\n takeFormat: (font) ->\n @format = font.toDataBundle()\n \n ###*\n * Applies the format-style of the token on the specified font. The font will have the style from\n * then token then.\n * \n * @method applyFormat\n * @param {gs.Font} font - The font to apply the format-style on.\n ### \n applyFormat: (font) ->\n font.set(@format)\n \ngs.RendererToken = RendererToken\n\nclass Component_TextRenderer extends gs.Component\n ###*\n * A text-renderer component allow to draw plain or formatted text on a\n * game object's bitmap. For formatted text, different text-codes can be\n * used to add formatting or define a placeholder.<br><br>\n * \n * A text-code uses the following syntax:<br><br>\n * \n * {code:value} <- Single Value<br />\n * {code:value1,value2,...} <- Multiple Values<br><br>\n * \n * Example:<br><br>\n * \n * \"This is {Y:I}a Text{Y:N}\" <- \"a Text\" will be italic here.<br>\n * \"The value is {GN:1}\" <- \"{GN:1}\" will be replaced for the value of the global number variable 0001.<br><br>\n * \n * For a list of all available text-codes with examples, just take a look into the offical help-file.\n * \n * @module gs\n * @class Component_TextRenderer\n * @extends gs.Component\n * @memberof gs\n * @constructor\n ###\n constructor: ->\n super\n \n ###*\n * @property currentX\n * @type number\n * @protected\n ###\n @currentX = 0\n \n ###*\n * @property currentY\n * @type number\n * @protected\n ###\n @currentY = 0\n \n ###*\n * @property currentLineHeight\n * @type number\n * @protected\n ###\n @currentLineHeight = 0\n \n ###*\n * @property font\n * @type gs.Font\n * @protected\n ###\n @font = new Font(\"Times New Roman\", 22)\n \n ###*\n * @property spaceSize\n * @type number\n * @protected\n ###\n @spaceSize = 0\n \n ###*\n * @property fontSize\n * @type number\n * @protected\n ###\n @fontSize = 0\n \n ###*\n * The left and right padding per line.\n * @property padding\n * @type number\n ###\n @padding = 0\n \n ###*\n * The spacing between text lines in pixels.\n * @property lineSpacing\n * @type number\n ###\n @lineSpacing = 0\n \n ###*\n * Creates the token-object for a list-placeholder. A list-placeholder\n * allows to insert a value from a list-variable.\n * \n * @method createListToken\n * @param {Array} list - The list.\n * @param {Array} values - The values of the list-placeholder text-code.\n * @return {string} The token-object.\n ###\n createListToken: (list, values) ->\n index = 0\n if values[1]?\n values = values[1].split(\":\")\n index = values[0]\n if values[0] == \"G\"\n index = GameManager.variableStore.numbers[parseInt(values[1])-1]\n else if values[0] == \"P\"\n index = GameManager.variableStore.persistentNumbers[parseInt(values[1])-1]\n else if values[0] == \"L\"\n index = GameManager.variableStore.numberValueOf({ scope: 0, index: parseInt(values[1])-1})\n \n return \"\" + list[index]\n \n \n ###*\n * Parses and returns the variable identifier which is an array containing\n * the optional domain name and the variable index as: [domain, index].\n * \n * @method parseVariableIdentifier\n * @param {string} identifier - The variable identifier e.g. com.degica.vnm.default.1 or com.degica.vnm.default.VarName\n * @param {string} type - The variable type to parse: number, string, boolean or list\n * @param {string} type - The scope of the variable to parse: 0 = local, 1 = global, 2 = persistent.\n * @return {Array} An array containing two values as: [domain, index]. If the identifier doesn't contain a domain-string, the domain will be 0 (default).\n ### \n parseVariableIdentifier: (identifier, type, scope) ->\n result = [0, identifier]\n \n if isNaN(identifier)\n index = identifier.lastIndexOf(\".\")\n if index != -1\n result[0] = identifier.substring(0, index)\n result[1] = identifier.substring(index+1)\n if isNaN(result[1])\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1\n else\n result[1] = parseInt(result[1])\n else\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1\n else\n result[1] = parseInt(result[1])\n \n return result\n \n ###*\n * Creates a token-object for a specified text-code.\n * \n * @method createToken\n * @param {string} code - The code/type of the text-code.\n * @param {string} value - The value of the text-code.\n * @return {Object} The token-object.\n ###\n createToken: (code, value) ->\n tokenObject = null\n value = if isNaN(value) then value else parseInt(value)\n switch code\n when \"SZ\" \n tokenObject = new gs.RendererToken(code, value)\n @font.size = tokenObject.value || @fontSize\n @spaceSize = @font.measureTextPlain(\" \")\n when \"Y\"\n tokenObject = { code: code, value: value }\n switch value\n when \"U\" then @font.underline = yes\n when \"S\" then @font.strikeThrough = yes\n when \"I\" then @font.italic = yes\n when \"B\" then @font.bold = yes\n when \"C\" then @font.smallCaps = yes\n when \"NU\" then @font.underline = no\n when \"NS\" then @font.strikeThrough = no\n when \"NI\" then @font.italic = no\n when \"NB\" then @font.bold = no\n when \"NC\" then @font.smallCaps = no\n when \"N\"\n @font.underline = no\n @font.strikeThrough = no\n @font.italic = no\n @font.bold = no\n @font.smallCaps = no\n @spaceSize = @font.measureTextPlain(\" \")\n when \"C\"\n tokenObject = new gs.RendererToken(code, value)\n if value <= 0\n @font.color = Font.defaultColor\n else\n @font.color = gs.Color.fromObject(RecordManager.system.colors[value-1] || Font.defaultColor)\n when \"GN\"\n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1]\n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 1)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.numbersByDomain[values[0]||0][values[1]-1] || 0))\n else\n values = @parseVariableIdentifier(values[0], \"number\", 1)\n tokenObject = (GameManager.variableStore.numbersByDomain[values[0]||0][values[1]-1] || 0).toString()\n when \"GT\" \n values = @parseVariableIdentifier(value, \"string\", 1)\n tokenObject = (GameManager.variableStore.stringsByDomain[values[0]||0][values[1]-1] || \"\")\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"GS\"\n \n values = @parseVariableIdentifier(value, \"boolean\", 1)\n tokenObject = (GameManager.variableStore.booleansByDomain[values[0]||0][values[1]-1] || false).toString()\n when \"GL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 1)\n tokenObject = @createListToken(GameManager.variableStore.listsByDomain[listIdentifier[0]][listIdentifier[1]-1] || [], values)\n when \"PN\"\n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1]\n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 2)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.persistentNumbers[values[0]]?[values[1]-1] || 0))\n else\n values = @parseVariableIdentifier(values[0], \"number\", 2)\n tokenObject = (GameManager.variableStore.persistentNumbersByDomain[values[0]||0]?[values[1]-1] || 0).toString()\n when \"PT\" \n values = @parseVariableIdentifier(value, \"string\", 2)\n tokenObject = (GameManager.variableStore.persistentStringsByDomain[values[0]]?[values[1]-1] || \"\")\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"PS\"\n values = @parseVariableIdentifier(value, \"boolean\", 2)\n tokenObject = (GameManager.variableStore.persistentBooleansByDomain[values[0]]?[values[1]-1] || false).toString()\n when \"PL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 2)\n tokenObject = @createListToken(GameManager.variableStore.persistentListsByDomain[listIdentifier[0]]?[listIdentifier[1]-1] || [], values)\n when \"LN\" \n values = if isNaN(value) then value.split(\",\") else [value]\n if values[1] \n format = values[1]\n values = @parseVariableIdentifier(values[0], \"number\", 0)\n tokenObject = sprintf(\"%\"+format+\"d\", (GameManager.variableStore.numberValueOf({ scope: 0, index: values[1]-1}) || 0))\n else\n values = @parseVariableIdentifier(values[0], \"number\", 0)\n tokenObject = (GameManager.variableStore.numberValueOf({ scope: 0, index: values[1]-1}) || 0).toString()\n when \"LT\" \n values = @parseVariableIdentifier(value, \"string\", 0)\n tokenObject = (GameManager.variableStore.stringValueOf({ scope: 0, index: values[1]-1}) || \"\").toString()\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else\n tokenObject = tokenObject[0] ? \"\"\n when \"LS\"\n values = @parseVariableIdentifier(value, \"boolean\", 0)\n tokenObject = (GameManager.variableStore.booleanValueOf({ scope: 0, index: values[1]-1}) || false).toString()\n when \"LL\"\n values = value.split(\",\")\n listIdentifier = @parseVariableIdentifier(values[0], \"list\", 0)\n tokenObject = @createListToken(GameManager.variableStore.listObjectOf({ scope: 0, index: listIdentifier[1]-1}) || [], values)\n when \"N\" \n tokenObject = (if RecordManager.characters[value]? then lcs(RecordManager.characters[value].name) else \"\")\n when \"RT\"\n pair = value.split(\"/\")\n tokenObject = { code: code, rtStyleId: pair[2] ? 0, rb: pair[0], rt: pair[1], rbSize: { width: 0, height: 0 }, rtSize: { width: 0, height: 0 } }\n when \"M\"\n macro = RecordManager.system.textMacros.first (m) -> m.name == value\n if macro\n if macro.type == 0 # Text + Codes\n tokenObject = macro.content.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n tokenObject.pop()\n else if macro.type == 1 # Placeholder Script Macro\n if !macro.contentFunc\n macro.contentFunc = eval(\"(function(object, value){ #{macro.content} })\")\n tokenObject = macro.contentFunc(@object, value)\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n if tokenObject.length > 1\n tokenObject.pop()\n else # Script Macro\n if !macro.contentFunc\n macro.contentFunc = eval(\"(function(object){ #{macro.content} })\")\n tokenObject = new gs.RendererToken(\"X\", macro.contentFunc)\n else\n tokenObject = \"\"\n else \n tokenObject = new gs.RendererToken(code, value)\n \n return tokenObject\n \n \n ###*\n * <p>Gets the correct font for the specified ruby-text token.</p> \n *\n * @param {Object} token - A ruby-text token.\n * @return {gs.Font} The font for the ruby-text which is shown above the original text.\n * @method getRubyTextFont\n ### \n getRubyTextFont: (token) ->\n style = null\n font = null\n \n if token.rtStyleId\n style = ui.UIManager.styles[\"rubyText-\"+token.rtStyleId]\n \n if !style\n style = ui.UIManager.styles[\"rubyText\"]\n \n font = style?.font ? @font\n font.size = font.size || @font.size / 2\n \n return font\n \n ###*\n * <p>Measures a control-token. If a token produces a visual result like displaying an icon then it must return the size taken by\n * the visual result. If the token has no visual result, <b>null</b> must be returned. This method is called for every token when the message is initialized.</p> \n *\n * @param {Object} token - A control-token.\n * @return {gs.Size} The size of the area taken by the visual result of the token or <b>null</b> if the token has no visual result.\n * @method measureControlToken\n * @protected\n ### \n measureControlToken: (token) -> # Can be implemented by derived classes\n size = null\n \n switch token.code\n when \"A\" # Animation\n animation = RecordManager.animations[Math.max(token.value-1, 0)]\n if animation?.graphic.name?\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/#{animation.graphic.name}\")\n if imageBitmap?\n size = width: Math.round(imageBitmap.width / animation.framesX), height: Math.round(imageBitmap.height / animation.framesY)\n when \"RT\" # Ruby Text\n font = @getRubyTextFont(token)\n fs = font.size\n font.size = font.size || @font.size / 2\n token.rbSize = @font.measureTextPlain(token.rb)\n token.rtSize = font.measureTextPlain(token.rt)\n font.size = fs\n \n size = width: Math.max(token.rbSize.width, token.rtSize.width), height: token.rbSize.height + token.rtSize.height\n \n return size\n \n ###*\n * <p>Draws the visual result of a token, like an icon for example, to the specified bitmap. This method is called for every token while the text is rendered.</p> \n *\n * @param {Object} token - A control-token.\n * @param {gs.Bitmap} bitmap - The bitmap used for the current text-line. Can be used to draw something on it like an icon, etc.\n * @param {number} offset - An x-offset for the draw-routine.\n * @method drawControlToken\n * @protected\n ###\n drawControlToken: (token, bitmap, offset) ->\n switch token.code\n when \"A\" # Animation\n animation = RecordManager.animations[Math.max(token.value-1, 0)]\n if animation?.graphic.name?\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/#{animation.graphic.name}\")\n if imageBitmap?\n rect = new gs.Rect(0, 0, Math.round(imageBitmap.width / animation.framesX), Math.round(imageBitmap.height / animation.framesY))\n bitmap.blt(offset, @currentY, imageBitmap, rect)\n when \"RT\" \n style = null\n if token.rtStyleId\n style = ui.UIManager.styles[\"rubyText-\"+token.rtStyleId]\n if !style\n style = ui.UIManager.styles[\"rubyText\"]\n \n font = style?.font ? @font\n fs = font.size\n font.size = font.size || @font.size / 2\n \n if style and !style.descriptor.font?.color\n font.color.set(@font.color)\n \n bitmap.font = font\n bitmap.drawText(offset, bitmap.font.descent, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rt, 1, 0)\n bitmap.font = @font\n font.size = fs\n bitmap.drawText(offset, token.rtSize.height, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rb, 1, 0)\n \n \n ###*\n * Splits up the specified token using a japanese word-wrap technique.\n * \n * @method wordWrapJapanese\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapJapanese: (token, line, width, height, result) ->\n startOfLine = '—…‥〳〴〵。.・、:;, ?!‼⁇⁈⁉‐゠–〜)]}〕〉》」』】〙〗〟’\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻'\n endOfLine = '([{〔〈《「『【〘〖〝‘\"⦅«'\n noSplit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789—…‥〳〴〵'\n descent = @font.descent\n size = @font.measureTextPlain(token)\n depth = 8\n depthLevel = 0\n i = 0\n j = 0\n lastCharacterIndex = 0\n \n if size.width > @object.dstRect.width-@spaceSize.width*3-@padding*2\n while i < token.length\n ch = token[i]\n size = @font.measureTextPlain(ch)\n width += size.width\n moved = no\n if width > @object.dstRect.width - @padding*2\n depthLevel = 0\n j = i\n \n loop\n moved = no\n \n while j > 0 and startOfLine.indexOf(token[j]) != -1\n j--\n moved = yes\n \n while j > 0 and endOfLine.indexOf(token[j-1]) != -1\n j--\n moved = yes\n \n while j > 0 and noSplit.indexOf(token[j-1]) != -1\n j--\n moved = yes\n \n if j == 0 and moved\n break\n else\n i = j\n \n depthLevel++\n break if depthLevel >= depth or !moved\n \n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), @font))\n lastCharacterIndex = i\n line.height = Math.max(height, @font.lineHeight)\n line.width = width - size.width\n line.descent = descent\n descent = @font.descent\n height = size.height\n result.push(line)\n line = new gs.RendererTextLine()\n width = width - (width - size.width)\n \n i++\n else\n line.content.push(new gs.RendererToken(null, token, @font))\n line.height = Math.max(height, @font.lineHeight)\n line.width = width + size.width\n line.descent = descent\n \n height = Math.max(height, @font.lineHeight) \n \n if lastCharacterIndex != i\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), @font))\n line.width = width\n line.height = Math.max(height, line.height)\n line.descent = descent\n \n return line\n \n \n ###*\n * Does not word-wrapping at all. It just adds the text token to the line as is.\n * \n * @method wordWrapNone\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapNone: (token, line, width, height, result) ->\n size = @font.measureTextPlain(token)\n height = Math.max(size.height, height || @font.lineHeight) \n \n if token.length > 0 \n line.width += size.width\n line.height = Math.max(height, line.height)\n line.descent = @font.descent\n line.content.push(new gs.RendererToken(null, token))\n \n return line\n \n ###*\n * Splits up the specified token using a space-based word-wrap technique.\n * \n * @method wordWrapSpaceBased\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ### \n wordWrapSpaceBased: (token, line, width, height, result) ->\n currentWords = []\n words = token.split(\" \")\n descent = @font.descent\n @spaceSize = @font.measureTextPlain(\" \")\n \n for word, i in words\n size = @font.measureTextPlain(word)\n width += size.width + @spaceSize.width\n \n if width > @object.dstRect.width - @padding*2\n token = new gs.RendererToken(null, currentWords.join(\" \"))\n token.takeFormat(@font)\n line.content.push(token)\n line.height = Math.max(height, line.height)\n line.width = width - size.width\n line.descent = Math.max(line.descent, descent)\n descent = Math.max(descent, @font.descent)\n height = size.height\n result.push(line)\n line = new gs.RendererTextLine()\n currentWords = [word]\n width = width - (width - size.width)\n else\n currentWords.push(word)\n \n height = Math.max(height, @font.lineHeight) \n \n if currentWords.length > 0\n token = new gs.RendererToken(null, currentWords.join(\" \"))\n token.takeFormat(@font)\n line.content.push(token)\n line.width = width\n line.height = Math.max(height, line.height)\n line.descent = Math.max(descent, line.descent)\n \n return line\n \n ###*\n * Splits up the specified token using a word-wrap technique. The kind of word-wrap technique\n * depends on the selected language. You can overwrite this method in derived classes to implement your\n * own custom word-wrap techniques.\n * \n * @method executeWordWrap\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n ###\n executeWordWrap: (token, line, width, height, result, wordWrap) ->\n if wordWrap\n switch LanguageManager.language.wordWrap\n when \"spaceBased\"\n @wordWrapSpaceBased(token, line, width, height, result)\n when \"japanese\"\n @wordWrapJapanese(token, line, width, height, result)\n else\n @wordWrapNone(token, line, width, height, result)\n \n \n ###*\n * Creates an a of line-objects. Each line-object is a list of token-objects. \n * A token-object can be just a string or an object containing more information\n * about how to process the token at runtime.\n * \n * A line-object also contains additional information like the width and height\n * of the line(in pixels).\n * \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n * \n * @method calculateLines\n * @param {string} message - A message creating the line-objects for.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @param {number} [firstLineWidth=0] - The current width of the first line.\n * @return {Array} An array of line-objects.\n ###\n calculateLines: (message, wordWrap, firstLineWidth) ->\n result = []\n line = new gs.RendererTextLine()\n width = firstLineWidth || 0\n height = 0\n descent = @font.descent\n currentWords = []\n size = null\n @spaceSize = @font.measureChar(\" \")\n @fontSize = @font.size\n \n tokens = message.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm)\n token = null\n t = 0\n \n underline = @font.underline\n strikeThrough = @font.strikeThrough\n italic = @font.italic\n bold = @font.bold\n smallCaps = @font.smallCaps\n \n while t < tokens.length\n token = tokens[t]\n \n if t % 4 != 0\n if token?\n tokenObject = @createToken(token, tokens[t+1])\n \n if tokenObject.push?\n Array.prototype.splice.apply(tokens, [t+3, 0].concat(tokenObject))\n else if not tokenObject.code?\n tokens[t+3] = tokenObject + tokens[t+3]\n else\n size = @measureControlToken(tokenObject)\n if size\n width += size.width\n height = Math.max(height, size.height)\n #descent = Math.max(@font.descent, descent)\n line.content.push(tokenObject)\n else # Must be a new-line\n line.height = height || @font.lineHeight\n line.width = width\n line.descent = descent\n result.push(line)\n line = new gs.RendererTextLine()\n line.content.push(new gs.RendererToken(null, \"\\n\", @font))\n width = 0\n height = 0\n descent = @font.descent\n t += 2\n else if token.length > 0\n line = @executeWordWrap(token, line, width, height, result, wordWrap)\n width = line.width\n height = line.height\n descent = line.descent\n \n t++\n \n if line.content.length > 0 or result.length == 0\n line.height = height\n line.width = width\n line.descent = descent\n result.push(line)\n \n \n @font.size = @fontSize \n @font.underline = underline\n @font.strikeThrough = strikeThrough\n @font.italic = italic\n @font.bold = bold\n @font.smallCaps = smallCaps\n \n return result\n \n \n ###*\n * Measures the dimensions of formatted lines in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedLines\n * @param {gs.RendererTextLine[]} lines - An array of text lines to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureFormattedLines: (lines, wordWrap) ->\n size = width: 0, height: 0\n \n for line in lines\n size.width = Math.max(line.width+2, size.width)\n size.height += line.height + @lineSpacing\n\n size.height -= @lineSpacing\n \n return size\n \n ###*\n * Measures the dimensions of a formatted text in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedText\n * @param {string} text - The text to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureFormattedText: (text, wordWrap) ->\n @font.set(@object.font)\n size = null\n lines = @calculateLines(text, wordWrap)\n \n size = @measureFormattedLines(lines, wordWrap)\n \n return size\n \n ###*\n * Measures the dimensions of a plain text in pixels. Formatting and\n * word-wrapping are not supported.\n *\n * @method measureText\n * @param {string} text - The text to measure.\n * @result {Object} An object containing the width and height of the text.\n ###\n measureText: (text) ->\n size = width: 0, height: 0\n lines = text.toString().split(\"\\n\")\n\n for line in lines\n lineSize = @object.font.measureText(text)\n size.width = Math.max(size.width, lineSize.width)\n size.height += @object.font.lineHeight + @lineSpacing\n \n size.height -= @lineSpacing\n \n return size\n \n ###*\n * Searches for a token in a list of tokens and returns the first match.\n *\n * @method findToken\n * @param {number} startIndex - The index in the list of tokens where the search will start.\n * @param {string} code - The code of the token to search for.\n * @param {number} direction - The search direction, can be forward(1) or backward(-1).\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object} The first token which matches the specified code or <b>null</b> if the token cannot be found.\n ### \n findToken: (startIndex, code, direction, tokens) ->\n token = null\n i = startIndex\n if direction == -1\n while i >= 0\n t = tokens[i]\n if t.code == code\n token = t\n break\n i--\n \n return token\n \n ###*\n * Searches for a specific kind of tokens between a start and an end token.\n *\n * @method findTokensBetween\n * @param {number} startIndex - The index where the search will start.\n * @param {number} endIndex - The index where the search will end.\n * @param {string} code - The code of the token-type to search for.\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object[]} List of tokens matching the specified code. Its an empty list if no tokens were found.\n ### \n findTokensBetween: (startIndex, endIndex, code, tokens) ->\n result = []\n s = startIndex\n e = endIndex\n \n while s < e\n token = tokens[s]\n if `token.code == code`\n result.push(token)\n s++\n \n return result\n \n ###*\n * Processes a control-token. A control-token is a token which influences\n * the text-rendering like changing the fonts color, size or style.\n *\n * Changes will be automatically applied to the game object's font.\n *\n * @method processControlToken\n * @param {Object} token - A control-token.\n * @return {Object} An object which can contain additional info needed for processing.\n ###\n processControlToken: (token) ->\n result = null\n \n switch token.code\n when \"SZ\"\n @object.font.size = token.value || @fontSize\n when \"C\"\n if token.value <= 0\n @object.font.color = Font.defaultColor\n else\n @object.font.color = RecordManager.system.colors[token.value-1] || Font.defaultColor\n when \"Y\"\n switch token.value\n when \"U\" then @object.font.underline = yes\n when \"S\" then @object.font.strikeThrough = yes\n when \"I\" then @object.font.italic = yes\n when \"B\" then @object.font.bold = yes\n when \"C\" then @object.font.smallCaps = yes\n when \"NU\" then @object.font.underline = no\n when \"NS\" then @object.font.strikeThrough = no\n when \"NI\" then @object.font.underline = no\n when \"NB\" then @object.font.bold = no\n when \"NC\" then @object.font.smallCaps = no\n when \"N\"\n @object.font.underline = no\n @object.font.strikeThrough = no\n @object.font.italic = no\n @object.font.bold = no\n @object.font.smallCaps = no\n \n return result\n \n ###*\n * Draws a plain text. Formatting and word-wrapping are not supported.\n *\n * @method drawText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n ###\n drawText: (pl, pt, pr, pb, text) ->\n lines = text.toString().split(\"\\n\")\n font = @object.font\n height = font.lineHeight\n \n for line, i in lines\n size = font.measureText(line)\n @object.bitmap.drawText(pl, i * height + pt, size.width + pr+pl, height+pt+pb, line, 0, 0)\n \n return null\n \n ###*\n * Draws an array of formatted text lines. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedLines\n * @param {number} pl - The left-padding of the text's position.\n * @param {number} pt - The top-padding of the text's position.\n * @param {number} pr - The right-padding of the text's position.\n * @param {number} pb - The bottom-padding of the text's position.\n * @param {gs.RendererTextLine[]} lines - An array of lines to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n ### \n drawFormattedLines: (pl, pt, pr, pb, lines, wordWrap) ->\n @currentX = pl\n @currentY = pt\n @currentLineHeight = 0\n \n for line in lines\n for token in line.content\n if token.code?\n @processControlToken(token)\n size = @measureControlToken(token)\n if size\n @drawControlToken(token, @object.bitmap, @currentX)\n @currentX += size.width\n else if token.value.length > 0\n font = @object.font\n height = line.height\n if token.value != \"\\n\"\n size = font.measureTextPlain(token.value)\n @object.bitmap.drawText(@currentX, @currentY + height - size.height + font.descent - line.descent, size.width+pl+pr, height+pt+pb, token.value, 0, 0)\n @currentX += size.width\n @currentLineHeight = Math.max(@currentLineHeight, height)\n @currentY += (@currentLineHeight || @object.font.lineHeight) + @lineSpacing\n @currentX = pl\n @currentLineHeight = 0\n \n return null\n \n ###*\n * Draws a formatted text. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @return {gs.RendererTextLine[]} The drawn text lines.\n ###\n drawFormattedText: (pl, pt, pr, pb, text, wordWrap) ->\n lines = @calculateLines(text.toString(), wordWrap)\n \n @drawFormattedLines(pl, pt, pr, pb, lines, wordWrap)\n \n return lines\n \ngs.Component_TextRenderer = Component_TextRenderer",
10 10 "parentId": "D3325122KACDEA4515SB731E37A42B9D779F",
11 11 "folder": false,
12 - "compiledContent": "var Component_TextRenderer, RendererTextLine, RendererToken,\n extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n hasProp = {}.hasOwnProperty;\n\nRendererTextLine = (function() {\n\n /**\n * Stores a text line.\n * \n * @module gs.RendererTextLine\n * @class RendererTextLine\n * @memberof gs.RendererTextLine\n * @constructor\n */\n function RendererTextLine() {\n\n /*\n * The width of the line in pixels.\n * @property width\n * @type number\n * @protected\n */\n this.width = 0;\n\n /*\n * The height of the line in pixels.\n * @property width\n * @type number\n * @protected\n */\n this.height = 0;\n\n /*\n * The descent of the line in pixels.\n * @property descent\n * @type number\n * @protected\n */\n this.descent = 0;\n\n /*\n * The content of the line as token objects.\n * @property content\n * @type Object[]\n * @protected\n */\n this.content = [];\n }\n\n return RendererTextLine;\n\n})();\n\ngs.RendererTextLine = RendererTextLine;\n\nRendererToken = (function() {\n\n /**\n * Stores a token.\n * \n * @module gs\n * @class RendererToken\n * @memberof gs\n * @constructor\n */\n function RendererToken(code, value, font) {\n\n /*\n * The value of the token. That value depends on the token type. For text-tokens, it stores\n * the actual text.\n * @property content\n * @type string\n */\n this.value = value;\n\n /*\n * The code describes what kind of token it is. For example, if the code is \"Y\" it means it is a\n * style-token. If the code is <b>null</b>, it means it is a text-token.\n * @property code\n * @type string\n */\n this.code = code;\n\n /*\n * The format stores the font-style properties of the token like if it is italic, bold, etc. It can be <b>null</b>.\n * @property format\n * @type Object\n */\n this.format = null;\n if (font != null) {\n this.takeFormat(font);\n }\n }\n\n\n /**\n * Takes the style from the specified font and stores it into the format-property. The token will\n * will be rendered with that style then.\n * \n * @method takeFormat\n * @param {gs.Font} font - The font to take the style from.\n */\n\n RendererToken.prototype.takeFormat = function(font) {\n return this.format = font.toDataBundle();\n };\n\n\n /**\n * Applies the format-style of the token on the specified font. The font will have the style from\n * then token then.\n * \n * @method applyFormat\n * @param {gs.Font} font - The font to apply the format-style on.\n */\n\n RendererToken.prototype.applyFormat = function(font) {\n return font.set(this.format);\n };\n\n return RendererToken;\n\n})();\n\ngs.RendererToken = RendererToken;\n\nComponent_TextRenderer = (function(superClass) {\n extend(Component_TextRenderer, superClass);\n\n\n /**\n * A text-renderer component allow to draw plain or formatted text on a\n * game object's bitmap. For formatted text, different text-codes can be\n * used to add formatting or define a placeholder.<br><br>\n * \n * A text-code uses the following syntax:<br><br>\n * \n * {code:value} <- Single Value<br />\n * {code:value1,value2,...} <- Multiple Values<br><br>\n * \n * Example:<br><br>\n * \n * \"This is {Y:I}a Text{Y:N}\" <- \"a Text\" will be italic here.<br>\n * \"The value is {GN:1}\" <- \"{GN:1}\" will be replaced for the value of the global number variable 0001.<br><br>\n * \n * For a list of all available text-codes with examples, just take a look into the offical help-file.\n * \n * @module gs\n * @class Component_TextRenderer\n * @extends gs.Component\n * @memberof gs\n * @constructor\n */\n\n function Component_TextRenderer() {\n Component_TextRenderer.__super__.constructor.apply(this, arguments);\n\n /**\n * @property currentX\n * @type number\n * @protected\n */\n this.currentX = 0;\n\n /**\n * @property currentY\n * @type number\n * @protected\n */\n this.currentY = 0;\n\n /**\n * @property currentLineHeight\n * @type number\n * @protected\n */\n this.currentLineHeight = 0;\n\n /**\n * @property font\n * @type gs.Font\n * @protected\n */\n this.font = new Font(\"Times New Roman\", 22);\n\n /**\n * @property spaceSize\n * @type number\n * @protected\n */\n this.spaceSize = 0;\n\n /**\n * @property fontSize\n * @type number\n * @protected\n */\n this.fontSize = 0;\n\n /**\n * The left and right padding per line.\n * @property padding\n * @type number\n */\n this.padding = 0;\n\n /**\n * The spacing between text lines in pixels.\n * @property lineSpacing\n * @type number\n */\n this.lineSpacing = 0;\n }\n\n\n /**\n * Creates the token-object for a list-placeholder. A list-placeholder\n * allows to insert a value from a list-variable.\n * \n * @method createListToken\n * @param {Array} list - The list.\n * @param {Array} values - The values of the list-placeholder text-code.\n * @return {string} The token-object.\n */\n\n Component_TextRenderer.prototype.createListToken = function(list, values) {\n var index;\n index = 0;\n if (values[1] != null) {\n values = values[1].split(\":\");\n index = values[0];\n if (values[0] === \"G\") {\n index = GameManager.variableStore.numbers[parseInt(values[1]) - 1];\n } else if (values[0] === \"P\") {\n index = GameManager.variableStore.persistentNumbers[parseInt(values[1]) - 1];\n } else if (values[0] === \"L\") {\n index = GameManager.variableStore.numberValueOf({\n scope: 0,\n index: parseInt(values[1]) - 1\n });\n }\n }\n return \"\" + list[index];\n };\n\n\n /**\n * Parses and returns the variable identifier which is an array containing\n * the optional domain name and the variable index as: [domain, index].\n * \n * @method parseVariableIdentifier\n * @param {string} identifier - The variable identifier e.g. com.degica.vnm.default.1 or com.degica.vnm.default.VarName\n * @param {string} type - The variable type to parse: number, string, boolean or list\n * @param {string} type - The scope of the variable to parse: 0 = local, 1 = global, 2 = persistent.\n * @return {Array} An array containing two values as: [domain, index]. If the identifier doesn't contain a domain-string, the domain will be 0 (default).\n */\n\n Component_TextRenderer.prototype.parseVariableIdentifier = function(identifier, type, scope) {\n var index, result;\n result = [0, identifier];\n if (isNaN(identifier)) {\n index = identifier.lastIndexOf(\".\");\n if (index !== -1) {\n result[0] = identifier.substring(0, index);\n result[1] = identifier.substring(index + 1);\n if (isNaN(result[1])) {\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1;\n } else {\n result[1] = parseInt(result[1]);\n }\n } else {\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1;\n }\n } else {\n result[1] = parseInt(result[1]);\n }\n return result;\n };\n\n\n /**\n * Creates a token-object for a specified text-code.\n * \n * @method createToken\n * @param {string} code - The code/type of the text-code.\n * @param {string} value - The value of the text-code.\n * @return {Object} The token-object.\n */\n\n Component_TextRenderer.prototype.createToken = function(code, value) {\n var format, listIdentifier, macro, pair, ref, ref1, ref2, ref3, tokenObject, values;\n tokenObject = null;\n value = isNaN(value) ? value : parseInt(value);\n switch (code) {\n case \"SZ\":\n tokenObject = new gs.RendererToken(code, value);\n this.font.size = tokenObject.value || this.fontSize;\n this.spaceSize = this.font.measureTextPlain(\" \");\n break;\n case \"Y\":\n tokenObject = {\n code: code,\n value: value\n };\n switch (value) {\n case \"U\":\n this.font.underline = true;\n break;\n case \"S\":\n this.font.strikeThrough = true;\n break;\n case \"I\":\n this.font.italic = true;\n break;\n case \"B\":\n this.font.bold = true;\n break;\n case \"C\":\n this.font.smallCaps = true;\n break;\n case \"NU\":\n this.font.underline = false;\n break;\n case \"NS\":\n this.font.strikeThrough = false;\n break;\n case \"NI\":\n this.font.italic = false;\n break;\n case \"NB\":\n this.font.bold = false;\n break;\n case \"NC\":\n this.font.smallCaps = false;\n break;\n case \"N\":\n this.font.underline = false;\n this.font.strikeThrough = false;\n this.font.italic = false;\n this.font.bold = false;\n this.font.smallCaps = false;\n }\n this.spaceSize = this.font.measureTextPlain(\" \");\n break;\n case \"C\":\n tokenObject = new gs.RendererToken(code, value);\n if (value <= 0) {\n this.font.color = Font.defaultColor;\n } else {\n this.font.color = gs.Color.fromObject(RecordManager.system.colors[value - 1] || Font.defaultColor);\n }\n break;\n case \"GN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 1);\n tokenObject = sprintf(\"%\" + format + \"d\", GameManager.variableStore.numbersByDomain[values[0] || 0][values[1] - 1] || 0);\n } else {\n values = this.parseVariableIdentifier(values[0], \"number\", 1);\n tokenObject = (GameManager.variableStore.numbersByDomain[values[0] || 0][values[1] - 1] || 0).toString();\n }\n break;\n case \"GT\":\n values = this.parseVariableIdentifier(value, \"string\", 1);\n tokenObject = GameManager.variableStore.stringsByDomain[values[0] || 0][values[1] - 1] || \"\";\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref = tokenObject[0]) != null ? ref : \"\";\n }\n break;\n case \"GS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 1);\n tokenObject = (GameManager.variableStore.booleansByDomain[values[0] || 0][values[1] - 1] || false).toString();\n break;\n case \"GL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 1);\n tokenObject = this.createListToken(GameManager.variableStore.listsByDomain[listIdentifier[0]][listIdentifier[1] - 1] || [], values);\n break;\n case \"PN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 2);\n tokenObject = sprintf(\"%\" + format + \"d\", GameManager.variableStore.persistentNumbers[values[0]][values[1] - 1] || 0);\n } else {\n tokenObject = (GameManager.variableStore.persistentNumbers[0][values[0] - 1] || 0).toString();\n }\n break;\n case \"PT\":\n values = this.parseVariableIdentifier(value, \"string\", 2);\n tokenObject = GameManager.variableStore.persistentStrings[values[0]][values[1] - 1] || \"\";\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref1 = tokenObject[0]) != null ? ref1 : \"\";\n }\n break;\n case \"PS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 2);\n tokenObject = (GameManager.variableStore.persistentBooleans[values[0]][values[1] - 1] || false).toString();\n break;\n case \"PL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 2);\n tokenObject = this.createListToken(GameManager.variableStore.persistentLists[listIdentifier[0]][listIdentifier[1] - 1] || [], values);\n break;\n case \"LN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 0);\n tokenObject = sprintf(\"%\" + format + \"d\", GameManager.variableStore.numberValueOf({\n scope: 0,\n index: values[1] - 1\n }) || 0);\n } else {\n values = this.parseVariableIdentifier(values[0], \"number\", 0);\n tokenObject = (GameManager.variableStore.numberValueOf({\n scope: 0,\n index: values[1] - 1\n }) || 0).toString();\n }\n break;\n case \"LT\":\n values = this.parseVariableIdentifier(value, \"string\", 0);\n tokenObject = (GameManager.variableStore.stringValueOf({\n scope: 0,\n index: values[1] - 1\n }) || \"\").toString();\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref2 = tokenObject[0]) != null ? ref2 : \"\";\n }\n break;\n case \"LS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 0);\n tokenObject = (GameManager.variableStore.booleanValueOf({\n scope: 0,\n index: values[1] - 1\n }) || false).toString();\n break;\n case \"LL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 0);\n tokenObject = this.createListToken(GameManager.variableStore.listObjectOf({\n scope: 0,\n index: listIdentifier[1] - 1\n }) || [], values);\n break;\n case \"N\":\n tokenObject = (RecordManager.characters[value] != null ? lcs(RecordManager.characters[value].name) : \"\");\n break;\n case \"RT\":\n pair = value.split(\"/\");\n tokenObject = {\n code: code,\n rtStyleId: (ref3 = pair[2]) != null ? ref3 : 0,\n rb: pair[0],\n rt: pair[1],\n rbSize: {\n width: 0,\n height: 0\n },\n rtSize: {\n width: 0,\n height: 0\n }\n };\n break;\n case \"M\":\n macro = RecordManager.system.textMacros.first(function(m) {\n return m.name === value;\n });\n if (macro) {\n if (macro.type === 0) {\n tokenObject = macro.content.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n tokenObject.pop();\n } else if (macro.type === 1) {\n if (!macro.contentFunc) {\n macro.contentFunc = eval(\"(function(object, value){ \" + macro.content + \" })\");\n }\n tokenObject = macro.contentFunc(this.object, value);\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n }\n } else {\n if (!macro.contentFunc) {\n macro.contentFunc = eval(\"(function(object){ \" + macro.content + \" })\");\n }\n tokenObject = new gs.RendererToken(\"X\", macro.contentFunc);\n }\n } else {\n tokenObject = \"\";\n }\n break;\n default:\n tokenObject = new gs.RendererToken(code, value);\n }\n return tokenObject;\n };\n\n\n /**\n * <p>Gets the correct font for the specified ruby-text token.</p> \n *\n * @param {Object} token - A ruby-text token.\n * @return {gs.Font} The font for the ruby-text which is shown above the original text.\n * @method getRubyTextFont\n */\n\n Component_TextRenderer.prototype.getRubyTextFont = function(token) {\n var font, ref, style;\n style = null;\n font = null;\n if (token.rtStyleId) {\n style = ui.UIManager.styles[\"rubyText-\" + token.rtStyleId];\n }\n if (!style) {\n style = ui.UIManager.styles[\"rubyText\"];\n }\n font = (ref = style != null ? style.font : void 0) != null ? ref : this.font;\n font.size = font.size || this.font.size / 2;\n return font;\n };\n\n\n /**\n * <p>Measures a control-token. If a token produces a visual result like displaying an icon then it must return the size taken by\n * the visual result. If the token has no visual result, <b>null</b> must be returned. This method is called for every token when the message is initialized.</p> \n *\n * @param {Object} token - A control-token.\n * @return {gs.Size} The size of the area taken by the visual result of the token or <b>null</b> if the token has no visual result.\n * @method measureControlToken\n * @protected\n */\n\n Component_TextRenderer.prototype.measureControlToken = function(token) {\n var animation, font, fs, imageBitmap, size;\n size = null;\n switch (token.code) {\n case \"A\":\n animation = RecordManager.animations[Math.max(token.value - 1, 0)];\n if ((animation != null ? animation.graphic.name : void 0) != null) {\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/\" + animation.graphic.name);\n if (imageBitmap != null) {\n size = {\n width: Math.round(imageBitmap.width / animation.framesX),\n height: Math.round(imageBitmap.height / animation.framesY)\n };\n }\n }\n break;\n case \"RT\":\n font = this.getRubyTextFont(token);\n fs = font.size;\n font.size = font.size || this.font.size / 2;\n token.rbSize = this.font.measureTextPlain(token.rb);\n token.rtSize = font.measureTextPlain(token.rt);\n font.size = fs;\n size = {\n width: Math.max(token.rbSize.width, token.rtSize.width),\n height: token.rbSize.height + token.rtSize.height\n };\n }\n return size;\n };\n\n\n /**\n * <p>Draws the visual result of a token, like an icon for example, to the specified bitmap. This method is called for every token while the text is rendered.</p> \n *\n * @param {Object} token - A control-token.\n * @param {gs.Bitmap} bitmap - The bitmap used for the current text-line. Can be used to draw something on it like an icon, etc.\n * @param {number} offset - An x-offset for the draw-routine.\n * @method drawControlToken\n * @protected\n */\n\n Component_TextRenderer.prototype.drawControlToken = function(token, bitmap, offset) {\n var animation, font, fs, imageBitmap, rect, ref, ref1, style;\n switch (token.code) {\n case \"A\":\n animation = RecordManager.animations[Math.max(token.value - 1, 0)];\n if ((animation != null ? animation.graphic.name : void 0) != null) {\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/\" + animation.graphic.name);\n if (imageBitmap != null) {\n rect = new gs.Rect(0, 0, Math.round(imageBitmap.width / animation.framesX), Math.round(imageBitmap.height / animation.framesY));\n return bitmap.blt(offset, this.currentY, imageBitmap, rect);\n }\n }\n break;\n case \"RT\":\n style = null;\n if (token.rtStyleId) {\n style = ui.UIManager.styles[\"rubyText-\" + token.rtStyleId];\n }\n if (!style) {\n style = ui.UIManager.styles[\"rubyText\"];\n }\n font = (ref = style != null ? style.font : void 0) != null ? ref : this.font;\n fs = font.size;\n font.size = font.size || this.font.size / 2;\n if (style && !((ref1 = style.descriptor.font) != null ? ref1.color : void 0)) {\n font.color.set(this.font.color);\n }\n bitmap.font = font;\n bitmap.drawText(offset, bitmap.font.descent, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rt, 1, 0);\n bitmap.font = this.font;\n font.size = fs;\n return bitmap.drawText(offset, token.rtSize.height, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rb, 1, 0);\n }\n };\n\n\n /**\n * Splits up the specified token using a japanese word-wrap technique.\n * \n * @method wordWrapJapanese\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapJapanese = function(token, line, width, height, result) {\n var ch, depth, depthLevel, descent, endOfLine, i, j, lastCharacterIndex, moved, noSplit, size, startOfLine;\n startOfLine = '—…‥〳〴〵。.・、:;, ?!‼⁇⁈⁉‐゠–〜)]}〕〉》」』】〙〗〟’\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻';\n endOfLine = '([{〔〈《「『【〘〖〝‘\"⦅«';\n noSplit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789—…‥〳〴〵';\n descent = this.font.descent;\n size = this.font.measureTextPlain(token);\n depth = 8;\n depthLevel = 0;\n i = 0;\n j = 0;\n lastCharacterIndex = 0;\n if (size.width > this.object.dstRect.width - this.spaceSize.width * 3 - this.padding * 2) {\n while (i < token.length) {\n ch = token[i];\n size = this.font.measureTextPlain(ch);\n width += size.width;\n moved = false;\n if (width > this.object.dstRect.width - this.padding * 2) {\n depthLevel = 0;\n j = i;\n while (true) {\n moved = false;\n while (j > 0 && startOfLine.indexOf(token[j]) !== -1) {\n j--;\n moved = true;\n }\n while (j > 0 && endOfLine.indexOf(token[j - 1]) !== -1) {\n j--;\n moved = true;\n }\n while (j > 0 && noSplit.indexOf(token[j - 1]) !== -1) {\n j--;\n moved = true;\n }\n if (j === 0 && moved) {\n break;\n } else {\n i = j;\n }\n depthLevel++;\n if (depthLevel >= depth || !moved) {\n break;\n }\n }\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), this.font));\n lastCharacterIndex = i;\n line.height = Math.max(height, this.font.lineHeight);\n line.width = width - size.width;\n line.descent = descent;\n descent = this.font.descent;\n height = size.height;\n result.push(line);\n line = new gs.RendererTextLine();\n width = width - (width - size.width);\n }\n i++;\n }\n } else {\n line.content.push(new gs.RendererToken(null, token, this.font));\n line.height = Math.max(height, this.font.lineHeight);\n line.width = width + size.width;\n line.descent = descent;\n }\n height = Math.max(height, this.font.lineHeight);\n if (lastCharacterIndex !== i) {\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), this.font));\n line.width = width;\n line.height = Math.max(height, line.height);\n line.descent = descent;\n }\n return line;\n };\n\n\n /**\n * Does not word-wrapping at all. It just adds the text token to the line as is.\n * \n * @method wordWrapNone\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapNone = function(token, line, width, height, result) {\n var size;\n size = this.font.measureTextPlain(token);\n height = Math.max(size.height, height || this.font.lineHeight);\n if (token.length > 0) {\n line.width += size.width;\n line.height = Math.max(height, line.height);\n line.descent = this.font.descent;\n line.content.push(new gs.RendererToken(null, token));\n }\n return line;\n };\n\n\n /**\n * Splits up the specified token using a space-based word-wrap technique.\n * \n * @method wordWrapSpaceBased\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapSpaceBased = function(token, line, width, height, result) {\n var currentWords, descent, i, k, len, size, word, words;\n currentWords = [];\n words = token.split(\" \");\n descent = this.font.descent;\n this.spaceSize = this.font.measureTextPlain(\" \");\n for (i = k = 0, len = words.length; k < len; i = ++k) {\n word = words[i];\n size = this.font.measureTextPlain(word);\n width += size.width + this.spaceSize.width;\n if (width > this.object.dstRect.width - this.padding * 2) {\n token = new gs.RendererToken(null, currentWords.join(\" \"));\n token.takeFormat(this.font);\n line.content.push(token);\n line.height = Math.max(height, line.height);\n line.width = width - size.width;\n line.descent = Math.max(line.descent, descent);\n descent = Math.max(descent, this.font.descent);\n height = size.height;\n result.push(line);\n line = new gs.RendererTextLine();\n currentWords = [word];\n width = width - (width - size.width);\n } else {\n currentWords.push(word);\n }\n height = Math.max(height, this.font.lineHeight);\n }\n if (currentWords.length > 0) {\n token = new gs.RendererToken(null, currentWords.join(\" \"));\n token.takeFormat(this.font);\n line.content.push(token);\n line.width = width;\n line.height = Math.max(height, line.height);\n line.descent = Math.max(descent, line.descent);\n }\n return line;\n };\n\n\n /**\n * Splits up the specified token using a word-wrap technique. The kind of word-wrap technique\n * depends on the selected language. You can overwrite this method in derived classes to implement your\n * own custom word-wrap techniques.\n * \n * @method executeWordWrap\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.executeWordWrap = function(token, line, width, height, result, wordWrap) {\n if (wordWrap) {\n switch (LanguageManager.language.wordWrap) {\n case \"spaceBased\":\n return this.wordWrapSpaceBased(token, line, width, height, result);\n case \"japanese\":\n return this.wordWrapJapanese(token, line, width, height, result);\n }\n } else {\n return this.wordWrapNone(token, line, width, height, result);\n }\n };\n\n\n /**\n * Creates an a of line-objects. Each line-object is a list of token-objects. \n * A token-object can be just a string or an object containing more information\n * about how to process the token at runtime.\n * \n * A line-object also contains additional information like the width and height\n * of the line(in pixels).\n * \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n * \n * @method calculateLines\n * @param {string} message - A message creating the line-objects for.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @param {number} [firstLineWidth=0] - The current width of the first line.\n * @return {Array} An array of line-objects.\n */\n\n Component_TextRenderer.prototype.calculateLines = function(message, wordWrap, firstLineWidth) {\n var bold, currentWords, descent, height, italic, line, result, size, smallCaps, strikeThrough, t, token, tokenObject, tokens, underline, width;\n result = [];\n line = new gs.RendererTextLine();\n width = firstLineWidth || 0;\n height = 0;\n descent = this.font.descent;\n currentWords = [];\n size = null;\n this.spaceSize = this.font.measureChar(\" \");\n this.fontSize = this.font.size;\n tokens = message.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n token = null;\n t = 0;\n underline = this.font.underline;\n strikeThrough = this.font.strikeThrough;\n italic = this.font.italic;\n bold = this.font.bold;\n smallCaps = this.font.smallCaps;\n while (t < tokens.length) {\n token = tokens[t];\n if (t % 4 !== 0) {\n if (token != null) {\n tokenObject = this.createToken(token, tokens[t + 1]);\n if (tokenObject.push != null) {\n Array.prototype.splice.apply(tokens, [t + 3, 0].concat(tokenObject));\n } else if (tokenObject.code == null) {\n tokens[t + 3] = tokenObject + tokens[t + 3];\n } else {\n size = this.measureControlToken(tokenObject);\n if (size) {\n width += size.width;\n height = Math.max(height, size.height);\n }\n line.content.push(tokenObject);\n }\n } else {\n line.height = height || this.font.lineHeight;\n line.width = width;\n line.descent = descent;\n result.push(line);\n line = new gs.RendererTextLine();\n line.content.push(new gs.RendererToken(null, \"\\n\", this.font));\n width = 0;\n height = 0;\n descent = this.font.descent;\n }\n t += 2;\n } else if (token.length > 0) {\n line = this.executeWordWrap(token, line, width, height, result, wordWrap);\n width = line.width;\n height = line.height;\n descent = line.descent;\n }\n t++;\n }\n if (line.content.length > 0 || result.length === 0) {\n line.height = height;\n line.width = width;\n line.descent = descent;\n result.push(line);\n }\n this.font.size = this.fontSize;\n this.font.underline = underline;\n this.font.strikeThrough = strikeThrough;\n this.font.italic = italic;\n this.font.bold = bold;\n this.font.smallCaps = smallCaps;\n return result;\n };\n\n\n /**\n * Measures the dimensions of formatted lines in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedLines\n * @param {gs.RendererTextLine[]} lines - An array of text lines to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureFormattedLines = function(lines, wordWrap) {\n var k, len, line, size;\n size = {\n width: 0,\n height: 0\n };\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n size.width = Math.max(line.width + 2, size.width);\n size.height += line.height + this.lineSpacing;\n }\n size.height -= this.lineSpacing;\n return size;\n };\n\n\n /**\n * Measures the dimensions of a formatted text in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedText\n * @param {string} text - The text to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureFormattedText = function(text, wordWrap) {\n var lines, size;\n this.font.set(this.object.font);\n size = null;\n lines = this.calculateLines(text, wordWrap);\n size = this.measureFormattedLines(lines, wordWrap);\n return size;\n };\n\n\n /**\n * Measures the dimensions of a plain text in pixels. Formatting and\n * word-wrapping are not supported.\n *\n * @method measureText\n * @param {string} text - The text to measure.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureText = function(text) {\n var k, len, line, lineSize, lines, size;\n size = {\n width: 0,\n height: 0\n };\n lines = text.toString().split(\"\\n\");\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n lineSize = this.object.font.measureText(text);\n size.width = Math.max(size.width, lineSize.width);\n size.height += this.object.font.lineHeight + this.lineSpacing;\n }\n size.height -= this.lineSpacing;\n return size;\n };\n\n\n /**\n * Searches for a token in a list of tokens and returns the first match.\n *\n * @method findToken\n * @param {number} startIndex - The index in the list of tokens where the search will start.\n * @param {string} code - The code of the token to search for.\n * @param {number} direction - The search direction, can be forward(1) or backward(-1).\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object} The first token which matches the specified code or <b>null</b> if the token cannot be found.\n */\n\n Component_TextRenderer.prototype.findToken = function(startIndex, code, direction, tokens) {\n var i, t, token;\n token = null;\n i = startIndex;\n if (direction === -1) {\n while (i >= 0) {\n t = tokens[i];\n if (t.code === code) {\n token = t;\n break;\n }\n i--;\n }\n }\n return token;\n };\n\n\n /**\n * Searches for a specific kind of tokens between a start and an end token.\n *\n * @method findTokensBetween\n * @param {number} startIndex - The index where the search will start.\n * @param {number} endIndex - The index where the search will end.\n * @param {string} code - The code of the token-type to search for.\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object[]} List of tokens matching the specified code. Its an empty list if no tokens were found.\n */\n\n Component_TextRenderer.prototype.findTokensBetween = function(startIndex, endIndex, code, tokens) {\n var e, result, s, token;\n result = [];\n s = startIndex;\n e = endIndex;\n while (s < e) {\n token = tokens[s];\n if (token.code == code) {\n result.push(token);\n }\n s++;\n }\n return result;\n };\n\n\n /**\n * Processes a control-token. A control-token is a token which influences\n * the text-rendering like changing the fonts color, size or style.\n *\n * Changes will be automatically applied to the game object's font.\n *\n * @method processControlToken\n * @param {Object} token - A control-token.\n * @return {Object} An object which can contain additional info needed for processing.\n */\n\n Component_TextRenderer.prototype.processControlToken = function(token) {\n var result;\n result = null;\n switch (token.code) {\n case \"SZ\":\n this.object.font.size = token.value || this.fontSize;\n break;\n case \"C\":\n if (token.value <= 0) {\n this.object.font.color = Font.defaultColor;\n } else {\n this.object.font.color = RecordManager.system.colors[token.value - 1] || Font.defaultColor;\n }\n break;\n case \"Y\":\n switch (token.value) {\n case \"U\":\n this.object.font.underline = true;\n break;\n case \"S\":\n this.object.font.strikeThrough = true;\n break;\n case \"I\":\n this.object.font.italic = true;\n break;\n case \"B\":\n this.object.font.bold = true;\n break;\n case \"C\":\n this.object.font.smallCaps = true;\n break;\n case \"NU\":\n this.object.font.underline = false;\n break;\n case \"NS\":\n this.object.font.strikeThrough = false;\n break;\n case \"NI\":\n this.object.font.underline = false;\n break;\n case \"NB\":\n this.object.font.bold = false;\n break;\n case \"NC\":\n this.object.font.smallCaps = false;\n break;\n case \"N\":\n this.object.font.underline = false;\n this.object.font.strikeThrough = false;\n this.object.font.italic = false;\n this.object.font.bold = false;\n this.object.font.smallCaps = false;\n }\n }\n return result;\n };\n\n\n /**\n * Draws a plain text. Formatting and word-wrapping are not supported.\n *\n * @method drawText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n */\n\n Component_TextRenderer.prototype.drawText = function(pl, pt, pr, pb, text) {\n var font, height, i, k, len, line, lines, size;\n lines = text.toString().split(\"\\n\");\n font = this.object.font;\n height = font.lineHeight;\n for (i = k = 0, len = lines.length; k < len; i = ++k) {\n line = lines[i];\n size = font.measureText(line);\n this.object.bitmap.drawText(pl, i * height + pt, size.width + pr + pl, height + pt + pb, line, 0, 0);\n }\n return null;\n };\n\n\n /**\n * Draws an array of formatted text lines. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedLines\n * @param {number} pl - The left-padding of the text's position.\n * @param {number} pt - The top-padding of the text's position.\n * @param {number} pr - The right-padding of the text's position.\n * @param {number} pb - The bottom-padding of the text's position.\n * @param {gs.RendererTextLine[]} lines - An array of lines to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n */\n\n Component_TextRenderer.prototype.drawFormattedLines = function(pl, pt, pr, pb, lines, wordWrap) {\n var font, height, k, l, len, len1, line, ref, size, token;\n this.currentX = pl;\n this.currentY = pt;\n this.currentLineHeight = 0;\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n ref = line.content;\n for (l = 0, len1 = ref.length; l < len1; l++) {\n token = ref[l];\n if (token.code != null) {\n this.processControlToken(token);\n size = this.measureControlToken(token);\n if (size) {\n this.drawControlToken(token, this.object.bitmap, this.currentX);\n this.currentX += size.width;\n }\n } else if (token.value.length > 0) {\n font = this.object.font;\n height = line.height;\n if (token.value !== \"\\n\") {\n size = font.measureTextPlain(token.value);\n this.object.bitmap.drawText(this.currentX, this.currentY + height - size.height + font.descent - line.descent, size.width + pl + pr, height + pt + pb, token.value, 0, 0);\n this.currentX += size.width;\n }\n this.currentLineHeight = Math.max(this.currentLineHeight, height);\n }\n }\n this.currentY += (this.currentLineHeight || this.object.font.lineHeight) + this.lineSpacing;\n this.currentX = pl;\n this.currentLineHeight = 0;\n }\n return null;\n };\n\n\n /**\n * Draws a formatted text. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @return {gs.RendererTextLine[]} The drawn text lines.\n */\n\n Component_TextRenderer.prototype.drawFormattedText = function(pl, pt, pr, pb, text, wordWrap) {\n var lines;\n lines = this.calculateLines(text.toString(), wordWrap);\n this.drawFormattedLines(pl, pt, pr, pb, lines, wordWrap);\n return lines;\n };\n\n return Component_TextRenderer;\n\n})(gs.Component);\n\ngs.Component_TextRenderer = Component_TextRenderer;\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLElBQUEsdURBQUE7RUFBQTs7O0FBQU07O0FBQ0Y7Ozs7Ozs7O0VBUWEsMEJBQUE7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxLQUFELEdBQVM7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxNQUFELEdBQVU7O0FBQ1Y7Ozs7OztJQU1BLElBQUMsQ0FBQSxPQUFELEdBQVc7O0FBQ1g7Ozs7OztJQU1BLElBQUMsQ0FBQSxPQUFELEdBQVc7RUE1QkY7Ozs7OztBQThCakIsRUFBRSxDQUFDLGdCQUFILEdBQXNCOztBQUVoQjs7QUFDRjs7Ozs7Ozs7RUFRYSx1QkFBQyxJQUFELEVBQU8sS0FBUCxFQUFjLElBQWQ7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxLQUFELEdBQVM7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxJQUFELEdBQVE7O0FBQ1I7Ozs7O0lBS0EsSUFBQyxDQUFBLE1BQUQsR0FBVTtJQUVWLElBQXFCLFlBQXJCO01BQUEsSUFBQyxDQUFBLFVBQUQsQ0FBWSxJQUFaLEVBQUE7O0VBdEJTOzs7QUF3QmI7Ozs7Ozs7OzBCQU9BLFVBQUEsR0FBWSxTQUFDLElBQUQ7V0FDUixJQUFDLENBQUEsTUFBRCxHQUFVLElBQUksQ0FBQyxZQUFMLENBQUE7RUFERjs7O0FBR1o7Ozs7Ozs7OzBCQU9BLFdBQUEsR0FBYSxTQUFDLElBQUQ7V0FDVCxJQUFJLENBQUMsR0FBTCxDQUFTLElBQUMsQ0FBQSxNQUFWO0VBRFM7Ozs7OztBQUdqQixFQUFFLENBQUMsYUFBSCxHQUFtQjs7QUFFYjs7OztBQUNGOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7RUF1QmEsZ0NBQUE7SUFDVCx5REFBQSxTQUFBOztBQUVBOzs7OztJQUtBLElBQUMsQ0FBQSxRQUFELEdBQVk7O0FBRVo7Ozs7O0lBS0EsSUFBQyxDQUFBLFFBQUQsR0FBWTs7QUFFWjs7Ozs7SUFLQSxJQUFDLENB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QyxRQUEzQztBQUVBLFdBQU87RUFMUTs7OztHQTMyQmMsRUFBRSxDQUFDOztBQWszQnhDLEVBQUUsQ0FBQyxzQkFBSCxHQUE0QiIsInNvdXJjZXNDb250ZW50IjpbIiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuI1xuIyAgIFNjcmlwdDogQ29tcG9uZW50X1RleHRSZW5kZXJlclxuI1xuIyAgICQkQ09QWVJJR0hUJCRcbiNcbiMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5jbGFzcyBSZW5kZXJlclRleHRMaW5lXG4gICAgIyMjKlxuICAgICogU3RvcmVzIGEgdGV4dCBsaW5lLlxuICAgICogXG4gICAgKiBAbW9kdWxlIGdzLlJlbmRlcmVyVGV4dExpbmVcbiAgICAqIEBjbGFzcyBSZW5kZXJlclRleHRMaW5lXG4gICAgKiBAbWVtYmVyb2YgZ3MuUmVuZGVyZXJUZXh0TGluZVxuICAgICogQGNvbnN0cnVjdG9yXG4gICAgIyMjXG4gICAgY29uc3RydWN0b3I6IC0+XG4gICAgICAgICMjI1xuICAgICAgICAqIFRoZSB3aWR0aCBvZiB0aGUgbGluZSBpbiBwaXhlbHMuXG4gICAgICAgICogQHByb3BlcnR5IHdpZHRoXG4gICAgICAgICogQHR5cGUgbnVtYmVyXG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQHdpZHRoID0gMFxuICAgICAgICAjIyNcbiAgICAgICAgKiBUaGUgaGVpZ2h0IG9mIHRoZSBsaW5lIGluIHBpeGVscy5cbiAgICAgICAgKiBAcHJvcGVydHkgd2lkdGhcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAaGVpZ2h0ID0gMFxuICAgICAgICAjIyNcbiAgICAgICAgKiBUaGUgZGVzY2VudCBvZiB0aGUgbGluZSBpbiBwaXhlbHMuXG4gICAgICAgICogQHByb3BlcnR5IGRlc2NlbnRcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAZGVzY2VudCA9IDBcbiAgICAgICAgIyMjXG4gICAgICAgICogVGhlIGNvbnRlbnQgb2YgdGhlIGxpbmUgYXMgdG9rZW4gb2JqZWN0cy5cbiAgICAgICAgKiBAcHJvcGVydHkgY29udGVudFxuICAgICAgICAqIEB0eXBlIE9iamVjdFtdXG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQGNvbnRlbnQgPSBbXVxuICAgICAgICBcbmdzLlJlbmRlcmVyVGV4dExpbmUgPSBSZW5kZXJlclRleHRMaW5lXG5cbmNsYXNzIFJlbmRlcmVyVG9rZW5cbiAgICAjIyMqXG4gICAgKiBTdG9yZXMgYSB0b2tlbi5cbiAgICAqIFxuICAgICogQG1vZHVsZSBnc1xuICAgICogQGNsYXNzIFJlbmRlcmVyVG9rZW5cbiAgICAqIEBtZW1iZXJvZiBnc1xuICAgICogQGNvbnN0cnVjdG9yXG4gICAgIyMjXG4gICAgY29uc3RydWN0b3I6IChjb2RlLCB2YWx1ZSwgZm9udCkgLT5cbiAgICAgICAgIyMjXG4gICAgICAgICogVGhlIHZhbHVlIG9mIHRoZSB0b2tlbi4gVGhhdCB2YWx1ZSBkZXBlbmRzIG9uIHRoZSB0b2tlbiB0eXBlLiBGb3IgdGV4dC10b2tlbnMsIGl0IHN0b3Jlc1xuICAgICAgICAqIHRoZSBhY3R1YWwgdGV4dC5cbiAgICAgICAgKiBAcHJvcGVydHkgY29udGVudFxuICAgICAgICAqIEB0eXBlIHN0cmluZ1xuICAgICAgICAjIyNcbiAgICAgICAgQHZhbHVlID0gdmFsdWVcbiAgICAgICAgIyMjXG4gICAgICAgICogVGhlIGNvZGUgZGVzY3JpYmVzIHdoYXQga2luZCBvZiB0b2tlbiBpdCBpcy4gRm9yIGV4YW1wbGUsIGlmIHRoZSBjb2RlIGlzIFwiWVwiIGl0IG1lYW5zIGl0IGlzIGFcbiAgICAgICAgKiBzdHlsZS10b2tlbi4gSWYgdGhlIGNvZGUgaXMgPGI+bnVsbDwvYj4sIGl0IG1lYW5zIGl0IGlzIGEgdGV4dC10b2tlbi5cbiAgICAgICAgKiBAcHJvcGVydHkgY29kZVxuICAgICAgICAqIEB0eXBlIHN0cmluZ1xuICAgICAgICAjIyNcbiAgICAgICAgQGNvZGUgPSBjb2RlXG4gICAgICAgICMjI1xuICAgICAgICAqIFRoZSBmb3JtYXQgc3RvcmVzIHRoZSBmb250LXN0eWxlIHByb3BlcnRpZXMgb2YgdGhlIHRva2VuIGxpa2UgaWYgaXQgaXMgaXRhbGljLCBib2xkLCBldGMuIEl0IGNhbiBiZSA8Yj5udWxsPC9iPi5cbiAgICAgICAgKiBAcHJvcGVydHkgZm9ybWF0XG4gICAgICAgICogQHR5cGUgT2JqZWN0XG4gICAgICAgICMjI1xuICAgICAgICBAZm9ybWF0ID0gbnVsbFxuICAgICAgICBcbiAgICAgICAgQHRha2VGb3JtYXQoZm9udCkgaWYgZm9udD9cbiAgICAgICAgICAgIFxuICAgICMjIypcbiAgICAqIFRha2VzIHRoZSBzdHlsZSBmcm9tIHRoZSBzcGVjaWZpZWQgZm9udCBhbmQgc3RvcmVzIGl0IGludG8gdGhlIGZvcm1hdC1wcm9wZXJ0eS4gVGhlIHRva2VuIHdpbGxcbiAgICAqIHdpbGwgYmUgcmVuZGVyZWQgd2l0aCB0aGF0IHN0eWxlIHRoZW4uXG4gICAgKiBcbiAgICAqIEBtZXRob2QgdGFrZUZvcm1hdFxuICAgICogQHBhcmFtIHtncy5Gb250fSBmb250IC0gVGhlIGZvbnQgdG8gdGFrZSB0aGUgc3R5bGUgZnJvbS5cbiAgICAjIyNcbiAgICB0YWtlRm9ybWF0OiAoZm9udCkgLT5cbiAgICAgICAgQGZvcm1hdCA9IGZvbnQudG9EYXRhQnVuZGxlKClcbiAgICBcbiAgICAjIyMqXG4gICAgKiBBcHBsaWVzIHRoZSBmb3JtYXQtc3R5bGUgb2YgdGhlIHRva2VuIG9uIHRoZSBzcGVjaWZpZWQgZm9udC4gVGhlIGZvbnQgd2lsbCBoYXZlIHRoZSBzdHlsZSBmcm9tXG4gICAgKiB0aGVuIHRva2VuIHRoZW4uXG4gICAgKiBcbiAgICAqIEBtZXRob2QgYXBwbHlGb3JtYXRcbiAgICAqIEBwYXJhbSB7Z3MuRm9udH0gZm9udCAtIFRoZSBmb250IHRvIGFwcGx5IHRoZSBmb3JtYXQtc3R5bGUgb24uXG4gICAgIyMjICAgIFxuICAgIGFwcGx5Rm9ybWF0OiAoZm9udCkgLT5cbiAgICAgICAgZm9udC5zZXQoQGZvcm1hdClcbiAgICAgICAgXG5ncy5SZW5kZXJlclRva2VuID0gUmVuZGVyZXJUb2tlblxuXG5jbGFzcyBDb21wb25lbnRfVGV4dFJlbmRlcmVyIGV4dGVuZHMgZ3MuQ29tcG9uZW50XG4gICAgIyMjKlxuICAgICogQSB0ZXh0LXJlbmRlcmVyIGNvbXBvbmVudCBhbGxvdyB0byBkcmF3IHBsYWluIG9yIGZvcm1hdHRlZCB0ZXh0IG9uIGFcbiAgICAqIGdhbWUgb2JqZWN0J3MgYml0bWFwLiBGb3IgZm9ybWF0dGVkIHRleHQsIGRpZmZlcmVudCB0ZXh0LWNvZGVzIGNhbiBiZVxuICAgICogdXNlZCB0byBhZGQgZm9ybWF0dGluZyBvciBkZWZpbmUgYSBwbGFjZWhvbGRlci48YnI+PGJyPlxuICAgICogXG4gICAgKiBBIHRleHQtY29kZSB1c2VzIHRoZSBmb2xsb3dpbmcgc3ludGF4Ojxicj48YnI+XG4gICAgKiBcbiAgICAqIHtjb2RlOnZhbHVlfSA8LSBTaW5nbGUgVmFsdWU8YnIgLz5cbiAgICAqIHtjb2RlOnZhbHVlMSx2YWx1ZTIsLi4ufSA8LSBNdWx0aXBsZSBWYWx1ZXM8YnI+PGJyPlxuICAgICogXG4gICAgKiBFeGFtcGxlOjxicj48YnI+XG4gICAgKiBcbiAgICAqIFwiVGhpcyBpcyB7WTpJfWEgVGV4dHtZOk59XCIgPC0gXCJhIFRleHRcIiB3aWxsIGJlIGl0YWxpYyBoZXJlLjxicj5cbiAgICAqIFwiVGhlIHZhbHVlIGlzIHtHTjoxfVwiIDwtIFwie0dOOjF9XCIgd2lsbCBiZSByZXBsYWNlZCBmb3IgdGhlIHZhbHVlIG9mIHRoZSBnbG9iYWwgbnVtYmVyIHZhcmlhYmxlIDAwMDEuPGJyPjxicj5cbiAgICAqIFxuICAgICogRm9yIGEgbGlzdCBvZiBhbGwgYXZhaWxhYmxlIHRleHQtY29kZXMgd2l0aCBleGFtcGxlcywganVzdCB0YWtlIGEgbG9vayBpbnRvIHRoZSBvZmZpY2FsIGhlbHAtZmlsZS5cbiAgICAqIFxuICAgICogQG1vZHVsZSBnc1xuICAgICogQGNsYXNzIENvbXBvbmVudF9UZXh0UmVuZGVyZXJcbiAgICAqIEBleHRlbmRzIGdzLkNvbXBvbmVudFxuICAgICogQG1lbWJlcm9mIGdzXG4gICAgKiBAY29uc3RydWN0b3JcbiAgICAjIyNcbiAgICBjb25zdHJ1Y3RvcjogLT5cbiAgICAgICAgc3VwZXJcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBAcHJvcGVydHkgY3VycmVudFhcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAY3VycmVudFggPSAwXG4gICAgICAgIFxuICAgICAgICAjIyMqXG4gICAgICAgICogQHByb3BlcnR5IGN1cnJlbnRZXG4gICAgICAgICogQHR5cGUgbnVtYmVyXG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQGN1cnJlbnRZID0gMFxuICAgICAgICBcbiAgICAgICAgIyMjKlxuICAgICAgICAqIEBwcm9wZXJ0eSBjdXJyZW50TGluZUhlaWdodFxuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgICAgIyMjXG4gICAgICAgIEBjdXJyZW50TGluZUhlaWdodCA9IDBcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBAcHJvcGVydHkgZm9udFxuICAgICAgICAqIEB0eXBlIGdzLkZvbnRcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAZm9udCA9IG5ldyBGb250KFwiVGltZXMgTmV3IFJvbWFuXCIsIDIyKVxuICAgICAgICBcbiAgICAgICAgIyMjKlxuICAgICAgICAqIEBwcm9wZXJ0eSBzcGFjZVNpemVcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAc3BhY2VTaXplID0gMFxuICAgICAgICBcbiAgICAgICAgIyMjKlxuICAgICAgICAqIEBwcm9wZXJ0eSBmb250U2l6ZVxuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgICAgIyMjXG4gICAgICAgIEBmb250U2l6ZSA9IDBcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBUaGUgbGVmdCBhbmQgcmlnaHQgcGFkZGluZyBwZXIgbGluZS5cbiAgICAgICAgKiBAcHJvcGVydHkgcGFkZGluZ1xuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAjIyNcbiAgICAgICAgQHBhZGRpbmcgPSAwXG4gICAgICAgIFxuICAgICAgICAjIyMqXG4gICAgICAgICogVGhlIHNwYWNpbmcgYmV0d2VlbiB0ZXh0IGxpbmVzIGluIHBpeGVscy5cbiAgICAgICAgKiBAcHJvcGVydHkgbGluZVNwYWNpbmdcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgIyMjXG4gICAgICAgIEBsaW5lU3BhY2luZyA9IDBcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogQ3JlYXRlcyB0aGUgdG9rZW4tb2JqZWN0IGZvciBhIGxpc3QtcGxhY2Vob2xkZXIuIEEgbGlzdC1wbGFjZWhvbGRlclxuICAgICogYWxsb3dzIHRvIGluc2VydCBhIHZhbHVlIGZyb20gYSBsaXN0LXZhcmlhYmxlLlxuICAgICogXG4gICAgKiBAbWV0aG9kIGNyZWF0ZUxpc3RUb2tlblxuICAgICogQHBhcmFtIHtBcnJheX0gbGlzdCAtIFRoZSBsaXN0LlxuICAgICogQHBhcmFtIHtBcnJheX0gdmFsdWVzIC0gVGhlIHZhbHVlcyBvZiB0aGUgbGlzdC1wbGFjZWhvbGRlciB0ZXh0LWNvZGUuXG4gICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSB0b2tlbi1vYmplY3QuXG4gICAgIyMjXG4gICAgY3JlYXRlTGlzdFRva2VuOiAobGlzdCwgdmFsdWVzKSAtPlxuICAgICAgICBpbmRleCA9IDBcbiAgICAgICAgaWYgdmFsdWVzWzFdP1xuICAgICAgICAgICAgdmFsdWVzID0gdmFsdWVzWzFdLnNwbGl0KFwiOlwiKVxuICAgICAgICAgICAgaW5kZXggPSB2YWx1ZXNbMF1cbiAgICAgICAgICAgIGlmIHZhbHVlc1swXSA9PSBcIkdcIlxuICAgICAgICAgICAgICAgIGluZGV4ID0gR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5udW1iZXJzW3BhcnNlSW50KHZhbHVlc1sxXSktMV1cbiAgICAgICAgICAgIGVsc2UgaWYgdmFsdWVzWzBdID09IFwiUFwiXG4gICAgICAgICAgICAgICAgaW5kZXggPSBHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnROdW1iZXJzW3BhcnNlSW50KHZhbHVlc1sxXSktMV1cbiAgICAgICAgICAgIGVsc2UgaWYgdmFsdWVzWzBdID09IFwiTFwiXG4gICAgICAgICAgICAgICAgaW5kZXggPSBHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLm51bWJlclZhbHVlT2YoeyBzY29wZTogMCwgaW5kZXg6IHBhcnNlSW50KHZhbHVlc1sxXSktMX0pXG4gICAgICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBcIlwiICsgbGlzdFtpbmRleF1cbiAgICAgICBcbiAgICAgIFxuICAgICMjIypcbiAgICAqIFBhcnNlcyBhbmQgcmV0dXJucyB0aGUgdmFyaWFibGUgaWRlbnRpZmllciB3aGljaCBpcyBhbiBhcnJheSBjb250YWluaW5nXG4gICAgKiB0aGUgb3B0aW9uYWwgZG9tYWluIG5hbWUgYW5kIHRoZSB2YXJpYWJsZSBpbmRleCBhczogW2RvbWFpbiwgaW5kZXhdLlxuICAgICogXG4gICAgKiBAbWV0aG9kIHBhcnNlVmFyaWFibGVJZGVudGlmaWVyXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gaWRlbnRpZmllciAtIFRoZSB2YXJpYWJsZSBpZGVudGlmaWVyIGUuZy4gY29tLmRlZ2ljYS52bm0uZGVmYXVsdC4xIG9yIGNvbS5kZWdpY2Eudm5tLmRlZmF1bHQuVmFyTmFtZVxuICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgdmFyaWFibGUgdHlwZSB0byBwYXJzZTogbnVtYmVyLCBzdHJpbmcsIGJvb2xlYW4gb3IgbGlzdFxuICAgICogQHBhcmFtIHtzdHJpbmd9IHR5cGUgLSBUaGUgc2NvcGUgb2YgdGhlIHZhcmlhYmxlIHRvIHBhcnNlOiAwID0gbG9jYWwsIDEgPSBnbG9iYWwsIDIgPSBwZXJzaXN0ZW50LlxuICAgICogQHJldHVybiB7QXJyYXl9IEFuIGFycmF5IGNvbnRhaW5pbmcgdHdvIHZhbHVlcyBhczogW2RvbWFpbiwgaW5kZXhdLiBJZiB0aGUgaWRlbnRpZmllciBkb2Vzbid0IGNvbnRhaW4gYSBkb21haW4tc3RyaW5nLCB0aGUgZG9tYWluIHdpbGwgYmUgMCAoZGVmYXVsdCkuXG4gICAgIyMjIFxuICAgIHBhcnNlVmFyaWFibGVJZGVudGlmaWVyOiAoaWRlbnRpZmllciwgdHlwZSwgc2NvcGUpIC0+XG4gICAgICAgIHJlc3VsdCA9IFswLCBpZGVudGlmaWVyXVxuICAgICAgICBcbiAgICAgICAgaWYgaXNOYU4oaWRlbnRpZmllcilcbiAgICAgICAgICAgIGluZGV4ID0gaWRlbnRpZmllci5sYXN0SW5kZXhPZihcIi5cIilcbiAgICAgICAgICAgIGlmIGluZGV4ICE9IC0xXG4gICAgICAgICAgICAgICAgcmVzdWx0WzBdID0gaWRlbnRpZmllci5zdWJzdHJpbmcoMCwgaW5kZXgpXG4gICAgICAgICAgICAgICAgcmVzdWx0WzFdID0gaWRlbnRpZmllci5zdWJzdHJpbmcoaW5kZXgrMSlcbiAgICAgICAgICAgICAgICBpZiBpc05hTihyZXN1bHRbMV0pXG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdFsxXSA9IEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUuaW5kZXhPZlZhcmlhYmxlKHJlc3VsdFsxXSwgdHlwZSwgc2NvcGUsIHJlc3VsdFswXSkgKyAxXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICByZXN1bHRbMV0gPSBwYXJzZUludChyZXN1bHRbMV0pXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgcmVzdWx0WzFdID0gR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5pbmRleE9mVmFyaWFibGUocmVzdWx0WzFdLCB0eXBlLCBzY29wZSwgcmVzdWx0WzBdKSArIDFcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgcmVzdWx0WzFdID0gcGFyc2VJbnQocmVzdWx0WzFdKVxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogQ3JlYXRlcyBhIHRva2VuLW9iamVjdCBmb3IgYSBzcGVjaWZpZWQgdGV4dC1jb2RlLlxuICAgICogXG4gICAgKiBAbWV0aG9kIGNyZWF0ZVRva2VuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gY29kZSAtIFRoZSBjb2RlL3R5cGUgb2YgdGhlIHRleHQtY29kZS5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB2YWx1ZSAtIFRoZSB2YWx1ZSBvZiB0aGUgdGV4dC1jb2RlLlxuICAgICogQHJldHVybiB7T2JqZWN0fSBUaGUgdG9rZW4tb2JqZWN0LlxuICAgICMjI1xuICAgIGNyZWF0ZVRva2VuOiAoY29kZSwgdmFsdWUpIC0+XG4gICAgICAgIHRva2VuT2JqZWN0ID0gbnVsbFxuICAgICAgICB2YWx1ZSA9IGlmIGlzTmFOKHZhbHVlKSB0aGVuIHZhbHVlIGVsc2UgcGFyc2VJbnQodmFsdWUpXG4gICAgICAgIHN3aXRjaCBjb2RlXG4gICAgICAgICAgICB3aGVuIFwiU1pcIiBcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG5ldyBncy5SZW5kZXJlclRva2VuKGNvZGUsIHZhbHVlKVxuICAgICAgICAgICAgICAgIEBmb250LnNpemUgPSB0b2tlbk9iamVjdC52YWx1ZSB8fCBAZm9udFNpemVcbiAgICAgICAgICAgICAgICBAc3BhY2VTaXplID0gQGZvbnQubWVhc3VyZVRleHRQbGFpbihcIiBcIilcbiAgICAgICAgICAgIHdoZW4gXCJZXCJcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHsgY29kZTogY29kZSwgdmFsdWU6IHZhbHVlIH1cbiAgICAgICAgICAgICAgICBzd2l0Y2ggdmFsdWVcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIlVcIiB0aGVuIEBmb250LnVuZGVybGluZSA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiU1wiIHRoZW4gQGZvbnQuc3RyaWtlVGhyb3VnaCA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiSVwiIHRoZW4gQGZvbnQuaXRhbGljID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJCXCIgdGhlbiBAZm9udC5ib2xkID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJDXCIgdGhlbiBAZm9udC5zbWFsbENhcHMgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5VXCIgdGhlbiBAZm9udC51bmRlcmxpbmUgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTlNcIiB0aGVuIEBmb250LnN0cmlrZVRocm91Z2ggPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTklcIiB0aGVuIEBmb250Lml0YWxpYyA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOQlwiIHRoZW4gQGZvbnQuYm9sZCA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOQ1wiIHRoZW4gQGZvbnQuc21hbGxDYXBzID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5cIlxuICAgICAgICAgICAgICAgICAgICAgICAgQGZvbnQudW5kZXJsaW5lID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBmb250LnN0cmlrZVRocm91Z2ggPSBub1xuICAgICAgICAgICAgICAgICAgICAgICAgQGZvbnQuaXRhbGljID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBmb250LmJvbGQgPSBub1xuICAgICAgICAgICAgICAgICAgICAgICAgQGZvbnQuc21hbGxDYXBzID0gbm9cbiAgICAgICAgICAgICAgICBAc3BhY2VTaXplID0gQGZvbnQubWVhc3VyZVRleHRQbGFpbihcIiBcIilcbiAgICAgICAgICAgIHdoZW4gXCJDXCJcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG5ldyBncy5SZW5kZXJlclRva2VuKGNvZGUsIHZhbHVlKVxuICAgICAgICAgICAgICAgIGlmIHZhbHVlIDw9IDBcbiAgICAgICAgICAgICAgICAgICAgQGZvbnQuY29sb3IgPSBGb250LmRlZmF1bHRDb2xvclxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgQGZvbnQuY29sb3IgPSBncy5Db2xvci5mcm9tT2JqZWN0KFJlY29yZE1hbmFnZXIuc3lzdGVtLmNvbG9yc1t2YWx1ZS0xXSB8fCBGb250LmRlZmF1bHRDb2xvcilcbiAgICAgICAgICAgIHdoZW4gXCJHTlwiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gaWYgaXNOYU4odmFsdWUpIHRoZW4gdmFsdWUuc3BsaXQoXCIsXCIpIGVsc2UgW3ZhbHVlXVxuICAgICAgICAgICAgICAgIGlmIHZhbHVlc1sxXVxuICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSB2YWx1ZXNbMV1cbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJudW1iZXJcIiwgMSlcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBzcHJpbnRmKFwiJVwiK2Zvcm1hdCtcImRcIiwgKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubnVtYmVyc0J5RG9tYWluW3ZhbHVlc1swXXx8MF1bdmFsdWVzWzFdLTFdIHx8IDApKVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJudW1iZXJcIiwgMSlcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5udW1iZXJzQnlEb21haW5bdmFsdWVzWzBdfHwwXVt2YWx1ZXNbMV0tMV0gfHwgMCkudG9TdHJpbmcoKVxuICAgICAgICAgICAgd2hlbiBcIkdUXCIgXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlLCBcInN0cmluZ1wiLCAxKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUuc3RyaW5nc0J5RG9tYWluW3ZhbHVlc1swXXx8MF1bdmFsdWVzWzFdLTFdIHx8IFwiXCIpXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB0b2tlbk9iamVjdC5zcGxpdCgvXFx7KFtBLXpdKyk6KFteXFx7XFx9XSspXFx9fChcXG4pL2dtKVxuICAgICAgICAgICAgICAgIGlmIHRva2VuT2JqZWN0Lmxlbmd0aCA+IDFcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QucG9wKClcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gdG9rZW5PYmplY3RbMF0gPyBcIlwiXG4gICAgICAgICAgICB3aGVuIFwiR1NcIlxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZSwgXCJib29sZWFuXCIsIDEpXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5ib29sZWFuc0J5RG9tYWluW3ZhbHVlc1swXXx8MF1bdmFsdWVzWzFdLTFdIHx8IGZhbHNlKS50b1N0cmluZygpXG4gICAgICAgICAgICB3aGVuIFwiR0xcIlxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZhbHVlLnNwbGl0KFwiLFwiKVxuICAgICAgICAgICAgICAgIGxpc3RJZGVudGlmaWVyID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJsaXN0XCIsIDEpXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBAY3JlYXRlTGlzdFRva2VuKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubGlzdHNCeURvbWFpbltsaXN0SWRlbnRpZmllclswXV1bbGlzdElkZW50aWZpZXJbMV0tMV0gfHwgW10sIHZhbHVlcylcbiAgICAgICAgICAgIHdoZW4gXCJQTlwiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gaWYgaXNOYU4odmFsdWUpIHRoZW4gdmFsdWUuc3BsaXQoXCIsXCIpIGVsc2UgW3ZhbHVlXVxuICAgICAgICAgICAgICAgIGlmIHZhbHVlc1sxXVxuICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSB2YWx1ZXNbMV1cbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJudW1iZXJcIiwgMilcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBzcHJpbnRmKFwiJVwiK2Zvcm1hdCtcImRcIiwgKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUucGVyc2lzdGVudE51bWJlcnNbdmFsdWVzWzBdXVt2YWx1ZXNbMV0tMV0gfHwgMCkpXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnROdW1iZXJzWzBdW3ZhbHVlc1swXS0xXSB8fCAwKS50b1N0cmluZygpXG4gICAgICAgICAgICB3aGVuIFwiUFRcIiAgXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlLCBcInN0cmluZ1wiLCAyKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUucGVyc2lzdGVudFN0cmluZ3NbdmFsdWVzWzBdXVt2YWx1ZXNbMV0tMV0gfHwgXCJcIilcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHRva2VuT2JqZWN0LnNwbGl0KC9cXHsoW0Etel0rKTooW15cXHtcXH1dKylcXH18KFxcbikvZ20pXG4gICAgICAgICAgICAgICAgaWYgdG9rZW5PYmplY3QubGVuZ3RoID4gMVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdC5wb3AoKVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB0b2tlbk9iamVjdFswXSA/IFwiXCJcbiAgICAgICAgICAgIHdoZW4gXCJQU1wiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlLCBcImJvb2xlYW5cIiwgMilcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnRCb29sZWFuc1t2YWx1ZXNbMF1dW3ZhbHVlc1sxXS0xXSB8fCBmYWxzZSkudG9TdHJpbmcoKVxuICAgICAgICAgICAgd2hlbiBcIlBMXCJcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSB2YWx1ZS5zcGxpdChcIixcIilcbiAgICAgICAgICAgICAgICBsaXN0SWRlbnRpZmllciA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibGlzdFwiLCAyKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gQGNyZWF0ZUxpc3RUb2tlbihHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnRMaXN0c1tsaXN0SWRlbnRpZmllclswXV1bbGlzdElkZW50aWZpZXJbMV0tMV0gfHwgW10sIHZhbHVlcylcbiAgICAgICAgICAgIHdoZW4gXCJMTlwiIFxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IGlmIGlzTmFOKHZhbHVlKSB0aGVuIHZhbHVlLnNwbGl0KFwiLFwiKSBlbHNlIFt2YWx1ZV1cbiAgICAgICAgICAgICAgICBpZiB2YWx1ZXNbMV0gXG4gICAgICAgICAgICAgICAgICAgIGZvcm1hdCA9IHZhbHVlc1sxXVxuICAgICAgICAgICAgICAgICAgICB2YWx1ZXMgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWVzWzBdLCBcIm51bWJlclwiLCAwKVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHNwcmludGYoXCIlXCIrZm9ybWF0K1wiZFwiLCAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5udW1iZXJWYWx1ZU9mKHsgc2NvcGU6IDAsIGluZGV4OiB2YWx1ZXNbMV0tMX0pIHx8IDApKVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJudW1iZXJcIiwgMClcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5udW1iZXJWYWx1ZU9mKHsgc2NvcGU6IDAsIGluZGV4OiB2YWx1ZXNbMV0tMX0pIHx8IDApLnRvU3RyaW5nKClcbiAgICAgICAgICAgIHdoZW4gXCJMVFwiIFxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZSwgXCJzdHJpbmdcIiwgMClcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnN0cmluZ1ZhbHVlT2YoeyBzY29wZTogMCwgaW5kZXg6IHZhbHVlc1sxXS0xfSkgfHwgXCJcIikudG9TdHJpbmcoKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gdG9rZW5PYmplY3Quc3BsaXQoL1xceyhbQS16XSspOihbXlxce1xcfV0rKVxcfXwoXFxuKS9nbSlcbiAgICAgICAgICAgICAgICBpZiB0b2tlbk9iamVjdC5sZW5ndGggPiAxXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0LnBvcCgpXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHRva2VuT2JqZWN0WzBdID8gXCJcIlxuICAgICAgICAgICAgd2hlbiBcIkxTXCJcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWUsIFwiYm9vbGVhblwiLCAwKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUuYm9vbGVhblZhbHVlT2YoeyBzY29wZTogMCwgaW5kZXg6IHZhbHVlc1sxXS0xfSkgfHwgZmFsc2UpLnRvU3RyaW5nKClcbiAgICAgICAgICAgIHdoZW4gXCJMTFwiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gdmFsdWUuc3BsaXQoXCIsXCIpXG4gICAgICAgICAgICAgICAgbGlzdElkZW50aWZpZXIgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWVzWzBdLCBcImxpc3RcIiwgMClcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IEBjcmVhdGVMaXN0VG9rZW4oR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5saXN0T2JqZWN0T2YoeyBzY29wZTogMCwgaW5kZXg6IGxpc3RJZGVudGlmaWVyWzFdLTF9KSB8fCBbXSwgdmFsdWVzKVxuICAgICAgICAgICAgd2hlbiBcIk5cIiBcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChpZiBSZWNvcmRNYW5hZ2VyLmNoYXJhY3RlcnNbdmFsdWVdPyB0aGVuIGxjcyhSZWNvcmRNYW5hZ2VyLmNoYXJhY3RlcnNbdmFsdWVdLm5hbWUpIGVsc2UgXCJcIilcbiAgICAgICAgICAgIHdoZW4gXCJSVFwiXG4gICAgICAgICAgICAgICAgcGFpciA9IHZhbHVlLnNwbGl0KFwiL1wiKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0geyBjb2RlOiBjb2RlLCBydFN0eWxlSWQ6IHBhaXJbMl0gPyAwLCByYjogcGFpclswXSwgcnQ6IHBhaXJbMV0sIHJiU2l6ZTogeyB3aWR0aDogMCwgaGVpZ2h0OiAwIH0sIHJ0U2l6ZTogeyB3aWR0aDogMCwgaGVpZ2h0OiAwIH0gfVxuICAgICAgICAgICAgd2hlbiBcIk1cIlxuICAgICAgICAgICAgICAgIG1hY3JvID0gUmVjb3JkTWFuYWdlci5zeXN0ZW0udGV4dE1hY3Jvcy5maXJzdCAobSkgLT4gbS5uYW1lID09IHZhbHVlXG4gICAgICAgICAgICAgICAgaWYgbWFjcm9cbiAgICAgICAgICAgICAgICAgICAgaWYgbWFjcm8udHlwZSA9PSAwICMgVGV4dCArIENvZGVzXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG1hY3JvLmNvbnRlbnQuc3BsaXQoL1xceyhbQS16XSspOihbXlxce1xcfV0rKVxcfXwoXFxuKS9nbSlcbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0LnBvcCgpXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgbWFjcm8udHlwZSA9PSAxICMgUGxhY2Vob2xkZXIgU2NyaXB0IE1hY3JvXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAhbWFjcm8uY29udGVudEZ1bmNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtYWNyby5jb250ZW50RnVuYyA9IGV2YWwoXCIoZnVuY3Rpb24ob2JqZWN0LCB2YWx1ZSl7ICN7bWFjcm8uY29udGVudH0gfSlcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gbWFjcm8uY29udGVudEZ1bmMoQG9iamVjdCwgdmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHRva2VuT2JqZWN0LnNwbGl0KC9cXHsoW0Etel0rKTooW15cXHtcXH1dKylcXH18KFxcbikvZ20pXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiB0b2tlbk9iamVjdC5sZW5ndGggPiAxXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QucG9wKClcbiAgICAgICAgICAgICAgICAgICAgZWxzZSAjIFNjcmlwdCBNYWNyb1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgIW1hY3JvLmNvbnRlbnRGdW5jXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFjcm8uY29udGVudEZ1bmMgPSBldmFsKFwiKGZ1bmN0aW9uKG9iamVjdCl7ICN7bWFjcm8uY29udGVudH0gfSlcIilcbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gbmV3IGdzLlJlbmRlcmVyVG9rZW4oXCJYXCIsIG1hY3JvLmNvbnRlbnRGdW5jKVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBcIlwiXG4gICAgICAgICAgICBlbHNlICAgIFxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gbmV3IGdzLlJlbmRlcmVyVG9rZW4oY29kZSwgdmFsdWUpXG4gICAgICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiB0b2tlbk9iamVjdFxuICAgIFxuICAgIFxuICAgICMjIypcbiAgICAqIDxwPkdldHMgdGhlIGNvcnJlY3QgZm9udCBmb3IgdGhlIHNwZWNpZmllZCBydWJ5LXRleHQgdG9rZW4uPC9wPiBcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gdG9rZW4gLSBBIHJ1YnktdGV4dCB0b2tlbi5cbiAgICAqIEByZXR1cm4ge2dzLkZvbnR9IFRoZSBmb250IGZvciB0aGUgcnVieS10ZXh0IHdoaWNoIGlzIHNob3duIGFib3ZlIHRoZSBvcmlnaW5hbCB0ZXh0LlxuICAgICogQG1ldGhvZCBnZXRSdWJ5VGV4dEZvbnRcbiAgICAjIyMgICBcbiAgICBnZXRSdWJ5VGV4dEZvbnQ6ICh0b2tlbikgLT5cbiAgICAgICAgc3R5bGUgPSBudWxsXG4gICAgICAgIGZvbnQgPSBudWxsXG4gICAgICAgICAgICAgICAgXG4gICAgICAgIGlmIHRva2VuLnJ0U3R5bGVJZFxuICAgICAgICAgICAgc3R5bGUgPSB1aS5VSU1hbmFnZXIuc3R5bGVzW1wicnVieVRleHQtXCIrdG9rZW4ucnRTdHlsZUlkXVxuICAgICAgICBcbiAgICAgICAgaWYgIXN0eWxlXG4gICAgICAgICAgICBzdHlsZSA9IHVpLlVJTWFuYWdlci5zdHlsZXNbXCJydWJ5VGV4dFwiXVxuICAgICAgICAgICAgXG4gICAgICAgIGZvbnQgPSBzdHlsZT8uZm9udCA/IEBmb250XG4gICAgICAgIGZvbnQuc2l6ZSA9IGZvbnQuc2l6ZSB8fCBAZm9udC5zaXplIC8gMlxuICAgICAgICBcbiAgICAgICAgcmV0dXJuIGZvbnRcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogPHA+TWVhc3VyZXMgYSBjb250cm9sLXRva2VuLiBJZiBhIHRva2VuIHByb2R1Y2VzIGEgdmlzdWFsIHJlc3VsdCBsaWtlIGRpc3BsYXlpbmcgYW4gaWNvbiB0aGVuIGl0IG11c3QgcmV0dXJuIHRoZSBzaXplIHRha2VuIGJ5XG4gICAgKiB0aGUgdmlzdWFsIHJlc3VsdC4gSWYgdGhlIHRva2VuIGhhcyBubyB2aXN1YWwgcmVzdWx0LCA8Yj5udWxsPC9iPiBtdXN0IGJlIHJldHVybmVkLiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgZm9yIGV2ZXJ5IHRva2VuIHdoZW4gdGhlIG1lc3NhZ2UgaXMgaW5pdGlhbGl6ZWQuPC9wPiBcbiAgICAqXG4gICAgKiBAcGFyYW0ge09iamVjdH0gdG9rZW4gLSBBIGNvbnRyb2wtdG9rZW4uXG4gICAgKiBAcmV0dXJuIHtncy5TaXplfSBUaGUgc2l6ZSBvZiB0aGUgYXJlYSB0YWtlbiBieSB0aGUgdmlzdWFsIHJlc3VsdCBvZiB0aGUgdG9rZW4gb3IgPGI+bnVsbDwvYj4gaWYgdGhlIHRva2VuIGhhcyBubyB2aXN1YWwgcmVzdWx0LlxuICAgICogQG1ldGhvZCBtZWFzdXJlQ29udHJvbFRva2VuXG4gICAgKiBAcHJvdGVjdGVkXG4gICAgIyMjICAgXG4gICAgbWVhc3VyZUNvbnRyb2xUb2tlbjogKHRva2VuKSAtPiAjIENhbiBiZSBpbXBsZW1lbnRlZCBieSBkZXJpdmVkIGNsYXNzZXNcbiAgICAgICAgc2l6ZSA9IG51bGxcbiAgICAgICAgXG4gICAgICAgIHN3aXRjaCB0b2tlbi5jb2RlXG4gICAgICAgICAgICB3aGVuIFwiQVwiICMgQW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgYW5pbWF0aW9uID0gUmVjb3JkTWFuYWdlci5hbmltYXRpb25zW01hdGgubWF4KHRva2VuLnZhbHVlLTEsIDApXVxuICAgICAgICAgICAgICAgIGlmIGFuaW1hdGlvbj8uZ3JhcGhpYy5uYW1lP1xuICAgICAgICAgICAgICAgICAgICBpbWFnZUJpdG1hcCA9IFJlc291cmNlTWFuYWdlci5nZXRCaXRtYXAoXCJHcmFwaGljcy9QaWN0dXJlcy8je2FuaW1hdGlvbi5ncmFwaGljLm5hbWV9XCIpXG4gICAgICAgICAgICAgICAgICAgIGlmIGltYWdlQml0bWFwP1xuICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IHdpZHRoOiBNYXRoLnJvdW5kKGltYWdlQml0bWFwLndpZHRoIC8gYW5pbWF0aW9uLmZyYW1lc1gpLCBoZWlnaHQ6IE1hdGgucm91bmQoaW1hZ2VCaXRtYXAuaGVpZ2h0IC8gYW5pbWF0aW9uLmZyYW1lc1kpXG4gICAgICAgICAgICB3aGVuIFwiUlRcIiAjIFJ1YnkgVGV4dFxuICAgICAgICAgICAgICAgIGZvbnQgPSBAZ2V0UnVieVRleHRGb250KHRva2VuKVxuICAgICAgICAgICAgICAgIGZzID0gZm9udC5zaXplXG4gICAgICAgICAgICAgICAgZm9udC5zaXplID0gZm9udC5zaXplIHx8IEBmb250LnNpemUgLyAyXG4gICAgICAgICAgICAgICAgdG9rZW4ucmJTaXplID0gQGZvbnQubWVhc3VyZVRleHRQbGFpbih0b2tlbi5yYilcbiAgICAgICAgICAgICAgICB0b2tlbi5ydFNpemUgPSBmb250Lm1lYXN1cmVUZXh0UGxhaW4odG9rZW4ucnQpXG4gICAgICAgICAgICAgICAgZm9udC5zaXplID0gZnNcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICBzaXplID0gd2lkdGg6IE1hdGgubWF4KHRva2VuLnJiU2l6ZS53aWR0aCwgdG9rZW4ucnRTaXplLndpZHRoKSwgaGVpZ2h0OiB0b2tlbi5yYlNpemUuaGVpZ2h0ICsgdG9rZW4ucnRTaXplLmhlaWdodFxuICAgICAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gc2l6ZVxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiA8cD5EcmF3cyB0aGUgdmlzdWFsIHJlc3VsdCBvZiBhIHRva2VuLCBsaWtlIGFuIGljb24gZm9yIGV4YW1wbGUsIHRvIHRoZSBzcGVjaWZpZWQgYml0bWFwLiBUaGlzIG1ldGhvZCBpcyBjYWxsZWQgZm9yIGV2ZXJ5IHRva2VuIHdoaWxlIHRoZSB0ZXh0IGlzIHJlbmRlcmVkLjwvcD4gXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gQSBjb250cm9sLXRva2VuLlxuICAgICogQHBhcmFtIHtncy5CaXRtYXB9IGJpdG1hcCAtIFRoZSBiaXRtYXAgdXNlZCBmb3IgdGhlIGN1cnJlbnQgdGV4dC1saW5lLiBDYW4gYmUgdXNlZCB0byBkcmF3IHNvbWV0aGluZyBvbiBpdCBsaWtlIGFuIGljb24sIGV0Yy5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBvZmZzZXQgLSBBbiB4LW9mZnNldCBmb3IgdGhlIGRyYXctcm91dGluZS5cbiAgICAqIEBtZXRob2QgZHJhd0NvbnRyb2xUb2tlblxuICAgICogQHByb3RlY3RlZFxuICAgICMjI1xuICAgIGRyYXdDb250cm9sVG9rZW46ICh0b2tlbiwgYml0bWFwLCBvZmZzZXQpIC0+XG4gICAgICAgIHN3aXRjaCB0b2tlbi5jb2RlXG4gICAgICAgICAgICB3aGVuIFwiQVwiICMgQW5pbWF0aW9uXG4gICAgICAgICAgICAgICAgYW5pbWF0aW9uID0gUmVjb3JkTWFuYWdlci5hbmltYXRpb25zW01hdGgubWF4KHRva2VuLnZhbHVlLTEsIDApXVxuICAgICAgICAgICAgICAgIGlmIGFuaW1hdGlvbj8uZ3JhcGhpYy5uYW1lP1xuICAgICAgICAgICAgICAgICAgICBpbWFnZUJpdG1hcCA9IFJlc291cmNlTWFuYWdlci5nZXRCaXRtYXAoXCJHcmFwaGljcy9QaWN0dXJlcy8je2FuaW1hdGlvbi5ncmFwaGljLm5hbWV9XCIpXG4gICAgICAgICAgICAgICAgICAgIGlmIGltYWdlQml0bWFwP1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVjdCA9IG5ldyBncy5SZWN0KDAsIDAsIE1hdGgucm91bmQoaW1hZ2VCaXRtYXAud2lkdGggLyBhbmltYXRpb24uZnJhbWVzWCksIE1hdGgucm91bmQoaW1hZ2VCaXRtYXAuaGVpZ2h0IC8gYW5pbWF0aW9uLmZyYW1lc1kpKVxuICAgICAgICAgICAgICAgICAgICAgICAgYml0bWFwLmJsdChvZmZzZXQsIEBjdXJyZW50WSwgaW1hZ2VCaXRtYXAsIHJlY3QpXG4gICAgICAgICAgICB3aGVuIFwiUlRcIiBcbiAgICAgICAgICAgICAgICBzdHlsZSA9IG51bGxcbiAgICAgICAgICAgICAgICBpZiB0b2tlbi5ydFN0eWxlSWRcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUgPSB1aS5VSU1hbmFnZXIuc3R5bGVzW1wicnVieVRleHQtXCIrdG9rZW4ucnRTdHlsZUlkXVxuICAgICAgICAgICAgICAgIGlmICFzdHlsZVxuICAgICAgICAgICAgICAgICAgICBzdHlsZSA9IHVpLlVJTWFuYWdlci5zdHlsZXNbXCJydWJ5VGV4dFwiXVxuICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICBmb250ID0gc3R5bGU/LmZvbnQgPyBAZm9udFxuICAgICAgICAgICAgICAgIGZzID0gZm9udC5zaXplXG4gICAgICAgICAgICAgICAgZm9udC5zaXplID0gZm9udC5zaXplIHx8IEBmb250LnNpemUgLyAyXG4gICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgaWYgc3R5bGUgYW5kICFzdHlsZS5kZXNjcmlwdG9yLmZvbnQ/LmNvbG9yXG4gICAgICAgICAgICAgICAgICAgIGZvbnQuY29sb3Iuc2V0KEBmb250LmNvbG9yKVxuICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICBiaXRtYXAuZm9udCA9IGZvbnRcbiAgICAgICAgICAgICAgICBiaXRtYXAuZHJhd1RleHQob2Zmc2V0LCBiaXRtYXAuZm9udC5kZXNjZW50LCBNYXRoLm1heCh0b2tlbi5yYlNpemUud2lkdGgsIHRva2VuLnJ0U2l6ZS53aWR0aCksIGJpdG1hcC5oZWlnaHQsIHRva2VuLnJ0LCAxLCAwKVxuICAgICAgICAgICAgICAgIGJpdG1hcC5mb250ID0gQGZvbnRcbiAgICAgICAgICAgICAgICBmb250LnNpemUgPSBmc1xuICAgICAgICAgICAgICAgIGJpdG1hcC5kcmF3VGV4dChvZmZzZXQsIHRva2VuLnJ0U2l6ZS5oZWlnaHQsIE1hdGgubWF4KHRva2VuLnJiU2l6ZS53aWR0aCwgdG9rZW4ucnRTaXplLndpZHRoKSwgYml0bWFwLmhlaWdodCwgdG9rZW4ucmIsIDEsIDApXG4gICAgXG4gICAgXG4gICAgIyMjKlxuICAgICogU3BsaXRzIHVwIHRoZSBzcGVjaWZpZWQgdG9rZW4gdXNpbmcgYSBqYXBhbmVzZSB3b3JkLXdyYXAgdGVjaG5pcXVlLlxuICAgICogXG4gICAgKiBAbWV0aG9kIHdvcmRXcmFwSmFwYW5lc2VcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSB0b2tlbiAtIFRoZSB0b2tlbiB0byBzcGxpdCB1cC5cbiAgICAqIEBwYXJhbSB7Z3MuUmVuZGVyZXJUZXh0TGluZX0gbGluZSAtIFRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUaGUgd2lkdGggb2YgdGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBUaGUgaGVpZ2h0IG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gLSBBbiBhcnJheSBvZiBsaW5lcy4gSWYgdGhlIHRva2VuIGlzIHNwbGl0IHVwIGludG8gbXVsdGlwbGUgbGluZXMsIGFsbCBuZXdcbiAgICAqIGxpbmVzIGFyZSBhZGRlZCB0byB0aGlzIHJlc3VsdCBhcnJheS5cbiAgICAqIEByZXR1cm4ge2dzLlJlbmRlcmVyVGV4dExpbmV9IFRoZSBjdXJyZW50IGxpbmUsIHRoYXQgbWF5IGJlIHRoZSBzYW1lIGFzIHRoZSA8Yj5saW5lPC9iPiBwYXJhbWV0ZXJzIGJ1dCBpZiBuZXcgbGluZXNcbiAgICAqIGFyZSBjcmVhdGVkIGl0IGhhcyB0byBiZSB0aGUgbGFzdCBuZXcgY3JlYXRlZCBsaW5lLlxuICAgICMjIyAgICAgXG4gICAgd29yZFdyYXBKYXBhbmVzZTogKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQpIC0+XG4gICAgICAgIHN0YXJ0T2ZMaW5lID0gJ+KAlOKApuKApeOAs+OAtOOAteOAgi7jg7vjgIE6OywgPyHigLzigYfigYjigYnigJDjgqDigJPjgJwpXe+9neOAleOAieOAi+OAjeOAj+OAkeOAmeOAl+OAn+KAmVwi772gwrvjg73jg77jg7zjgqHjgqPjgqXjgqfjgqnjg4Pjg6Pjg6Xjg6fjg67jg7Xjg7bjgYHjgYPjgYXjgYfjgYnjgaPjgoPjgoXjgofjgo7jgpXjgpbjh7Djh7Hjh7Ljh7Pjh7Tjh7Xjh7bjh7fjh7jjh7njh7rjh7vjh7zjh73jh77jh7/jgIXjgLsnXG4gICAgICAgIGVuZE9mTGluZSA9ICcoW++9m+OAlOOAiOOAiuOAjOOAjuOAkOOAmOOAluOAneKAmFwi772fwqsnXG4gICAgICAgIG5vU3BsaXQgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODnvvJDvvJHvvJLvvJPvvJTvvJXvvJbvvJfvvJjvvJnigJTigKbigKXjgLPjgLTjgLUnXG4gICAgICAgIGRlc2NlbnQgPSBAZm9udC5kZXNjZW50XG4gICAgICAgIHNpemUgPSBAZm9udC5tZWFzdXJlVGV4dFBsYWluKHRva2VuKVxuICAgICAgICBkZXB0aCA9IDhcbiAgICAgICAgZGVwdGhMZXZlbCA9IDBcbiAgICAgICAgaSA9IDBcbiAgICAgICAgaiA9IDBcbiAgICAgICAgbGFzdENoYXJhY3RlckluZGV4ID0gMFxuICAgICAgICBcbiAgICAgICAgaWYgc2l6ZS53aWR0aCA+IEBvYmplY3QuZHN0UmVjdC53aWR0aC1Ac3BhY2VTaXplLndpZHRoKjMtQHBhZGRpbmcqMlxuICAgICAgICAgICAgd2hpbGUgaSA8IHRva2VuLmxlbmd0aFxuICAgICAgICAgICAgICAgIGNoID0gdG9rZW5baV1cbiAgICAgICAgICAgICAgICBzaXplID0gQGZvbnQubWVhc3VyZVRleHRQbGFpbihjaClcbiAgICAgICAgICAgICAgICB3aWR0aCArPSBzaXplLndpZHRoXG4gICAgICAgICAgICAgICAgbW92ZWQgPSBub1xuICAgICAgICAgICAgICAgIGlmIHdpZHRoID4gQG9iamVjdC5kc3RSZWN0LndpZHRoIC0gQHBhZGRpbmcqMlxuICAgICAgICAgICAgICAgICAgICBkZXB0aExldmVsID0gMFxuICAgICAgICAgICAgICAgICAgICBqID0gaVxuICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgbG9vcFxuICAgICAgICAgICAgICAgICAgICAgICAgbW92ZWQgPSBub1xuICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgaiA+IDAgYW5kIHN0YXJ0T2ZMaW5lLmluZGV4T2YodG9rZW5bal0pICE9IC0xXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgai0tXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbW92ZWQgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgaiA+IDAgYW5kIGVuZE9mTGluZS5pbmRleE9mKHRva2VuW2otMV0pICE9IC0xXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgai0tXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbW92ZWQgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIGogPiAwIGFuZCBub1NwbGl0LmluZGV4T2YodG9rZW5bai0xXSkgIT0gLTFcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqLS1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBtb3ZlZCA9IHllc1xuICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIGogPT0gMCBhbmQgbW92ZWRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBqXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgICAgICBkZXB0aExldmVsKytcbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrIGlmIGRlcHRoTGV2ZWwgPj0gZGVwdGggb3IgIW1vdmVkXG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2gobmV3IGdzLlJlbmRlcmVyVG9rZW4obnVsbCwgdG9rZW4uc3Vic3RyaW5nKGxhc3RDaGFyYWN0ZXJJbmRleCwgaSksIEBmb250KSlcbiAgICAgICAgICAgICAgICAgICAgbGFzdENoYXJhY3RlckluZGV4ID0gaVxuICAgICAgICAgICAgICAgICAgICBsaW5lLmhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgQGZvbnQubGluZUhlaWdodClcbiAgICAgICAgICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoIC0gc2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBkZXNjZW50XG4gICAgICAgICAgICAgICAgICAgIGRlc2NlbnQgPSBAZm9udC5kZXNjZW50XG4gICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IHNpemUuaGVpZ2h0XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGxpbmUpXG4gICAgICAgICAgICAgICAgICAgIGxpbmUgPSBuZXcgZ3MuUmVuZGVyZXJUZXh0TGluZSgpXG4gICAgICAgICAgICAgICAgICAgIHdpZHRoID0gd2lkdGggLSAod2lkdGggLSBzaXplLndpZHRoKVxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIGkrK1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaChuZXcgZ3MuUmVuZGVyZXJUb2tlbihudWxsLCB0b2tlbiwgQGZvbnQpKVxuICAgICAgICAgICAgbGluZS5oZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIEBmb250LmxpbmVIZWlnaHQpXG4gICAgICAgICAgICBsaW5lLndpZHRoID0gd2lkdGggKyBzaXplLndpZHRoXG4gICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBkZXNjZW50XG4gICAgICAgICAgICBcbiAgICAgICAgaGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBAZm9udC5saW5lSGVpZ2h0KSAgIFxuICAgICAgICAgICAgXG4gICAgICAgIGlmIGxhc3RDaGFyYWN0ZXJJbmRleCAhPSBpXG4gICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaChuZXcgZ3MuUmVuZGVyZXJUb2tlbihudWxsLCB0b2tlbi5zdWJzdHJpbmcobGFzdENoYXJhY3RlckluZGV4LCBpKSwgQGZvbnQpKVxuICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoXG4gICAgICAgICAgICBsaW5lLmhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgbGluZS5oZWlnaHQpXG4gICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBkZXNjZW50XG4gICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIGxpbmVcbiAgICAgICAgXG4gICAgXG4gICAgIyMjKlxuICAgICogRG9lcyBub3Qgd29yZC13cmFwcGluZyBhdCBhbGwuIEl0IGp1c3QgYWRkcyB0aGUgdGV4dCB0b2tlbiB0byB0aGUgbGluZSBhcyBpcy5cbiAgICAqIFxuICAgICogQG1ldGhvZCB3b3JkV3JhcE5vbmVcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSB0b2tlbiAtIFRoZSB0b2tlbiB0byBzcGxpdCB1cC5cbiAgICAqIEBwYXJhbSB7Z3MuUmVuZGVyZXJUZXh0TGluZX0gbGluZSAtIFRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUaGUgd2lkdGggb2YgdGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBUaGUgaGVpZ2h0IG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gLSBBbiBhcnJheSBvZiBsaW5lcy4gSWYgdGhlIHRva2VuIGlzIHNwbGl0IHVwIGludG8gbXVsdGlwbGUgbGluZXMsIGFsbCBuZXdcbiAgICAqIGxpbmVzIGFyZSBhZGRlZCB0byB0aGlzIHJlc3VsdCBhcnJheS5cbiAgICAqIEByZXR1cm4ge2dzLlJlbmRlcmVyVGV4dExpbmV9IFRoZSBjdXJyZW50IGxpbmUsIHRoYXQgbWF5IGJlIHRoZSBzYW1lIGFzIHRoZSA8Yj5saW5lPC9iPiBwYXJhbWV0ZXJzIGJ1dCBpZiBuZXcgbGluZXNcbiAgICAqIGFyZSBjcmVhdGVkIGl0IGhhcyB0byBiZSB0aGUgbGFzdCBuZXcgY3JlYXRlZCBsaW5lLlxuICAgICMjIyAgXG4gICAgd29yZFdyYXBOb25lOiAodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdCkgLT5cbiAgICAgICAgc2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4odG9rZW4pXG4gICAgICAgIGhlaWdodCA9IE1hdGgubWF4KHNpemUuaGVpZ2h0LCBoZWlnaHQgfHwgQGZvbnQubGluZUhlaWdodCkgICBcbiAgICAgICAgXG4gICAgICAgIGlmIHRva2VuLmxlbmd0aCA+IDAgICAgXG4gICAgICAgICAgICBsaW5lLndpZHRoICs9IHNpemUud2lkdGhcbiAgICAgICAgICAgIGxpbmUuaGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBsaW5lLmhlaWdodClcbiAgICAgICAgICAgIGxpbmUuZGVzY2VudCA9IEBmb250LmRlc2NlbnRcbiAgICAgICAgICAgIGxpbmUuY29udGVudC5wdXNoKG5ldyBncy5SZW5kZXJlclRva2VuKG51bGwsIHRva2VuKSlcbiAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gbGluZVxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBTcGxpdHMgdXAgdGhlIHNwZWNpZmllZCB0b2tlbiB1c2luZyBhIHNwYWNlLWJhc2VkIHdvcmQtd3JhcCB0ZWNobmlxdWUuXG4gICAgKiBcbiAgICAqIEBtZXRob2Qgd29yZFdyYXBTcGFjZUJhc2VkXG4gICAgKiBAcGFyYW0ge09iamVjdH0gdG9rZW4gLSBUaGUgdG9rZW4gdG8gc3BsaXQgdXAuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmV9IGxpbmUgLSBUaGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gVGhlIHdpZHRoIG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gVGhlIGhlaWdodCBvZiB0aGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lW119IC0gQW4gYXJyYXkgb2YgbGluZXMuIElmIHRoZSB0b2tlbiBpcyBzcGxpdCB1cCBpbnRvIG11bHRpcGxlIGxpbmVzLCBhbGwgbmV3XG4gICAgKiBsaW5lcyBhcmUgYWRkZWQgdG8gdGhpcyByZXN1bHQgYXJyYXkuXG4gICAgKiBAcmV0dXJuIHtncy5SZW5kZXJlclRleHRMaW5lfSBUaGUgY3VycmVudCBsaW5lLCB0aGF0IG1heSBiZSB0aGUgc2FtZSBhcyB0aGUgPGI+bGluZTwvYj4gcGFyYW1ldGVycyBidXQgaWYgbmV3IGxpbmVzXG4gICAgKiBhcmUgY3JlYXRlZCBpdCBoYXMgdG8gYmUgdGhlIGxhc3QgbmV3IGNyZWF0ZWQgbGluZS5cbiAgICAjIyMgICAgXG4gICAgd29yZFdyYXBTcGFjZUJhc2VkOiAodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdCkgLT5cbiAgICAgICAgY3VycmVudFdvcmRzID0gW11cbiAgICAgICAgd29yZHMgPSB0b2tlbi5zcGxpdChcIiBcIilcbiAgICAgICAgZGVzY2VudCA9IEBmb250LmRlc2NlbnRcbiAgICAgICAgQHNwYWNlU2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4oXCIgXCIpXG4gICAgICAgIFxuICAgICAgICBmb3Igd29yZCwgaSBpbiB3b3Jkc1xuICAgICAgICAgICAgc2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4od29yZClcbiAgICAgICAgICAgIHdpZHRoICs9IHNpemUud2lkdGggKyBAc3BhY2VTaXplLndpZHRoXG4gICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgd2lkdGggPiBAb2JqZWN0LmRzdFJlY3Qud2lkdGggLSBAcGFkZGluZyoyXG4gICAgICAgICAgICAgICAgdG9rZW4gPSBuZXcgZ3MuUmVuZGVyZXJUb2tlbihudWxsLCBjdXJyZW50V29yZHMuam9pbihcIiBcIikpXG4gICAgICAgICAgICAgICAgdG9rZW4udGFrZUZvcm1hdChAZm9udClcbiAgICAgICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaCh0b2tlbilcbiAgICAgICAgICAgICAgICBsaW5lLmhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgbGluZS5oZWlnaHQpXG4gICAgICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoIC0gc2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgIGxpbmUuZGVzY2VudCA9IE1hdGgubWF4KGxpbmUuZGVzY2VudCwgZGVzY2VudClcbiAgICAgICAgICAgICAgICBkZXNjZW50ID0gTWF0aC5tYXgoZGVzY2VudCwgQGZvbnQuZGVzY2VudClcbiAgICAgICAgICAgICAgICBoZWlnaHQgPSBzaXplLmhlaWdodFxuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGxpbmUpXG4gICAgICAgICAgICAgICAgbGluZSA9IG5ldyBncy5SZW5kZXJlclRleHRMaW5lKClcbiAgICAgICAgICAgICAgICBjdXJyZW50V29yZHMgPSBbd29yZF1cbiAgICAgICAgICAgICAgICB3aWR0aCA9IHdpZHRoIC0gKHdpZHRoIC0gc2l6ZS53aWR0aClcbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBjdXJyZW50V29yZHMucHVzaCh3b3JkKVxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgaGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBAZm9udC5saW5lSGVpZ2h0KSAgIFxuICAgICAgICAgICAgXG4gICAgICAgIGlmIGN1cnJlbnRXb3Jkcy5sZW5ndGggPiAwXG4gICAgICAgICAgICB0b2tlbiA9IG5ldyBncy5SZW5kZXJlclRva2VuKG51bGwsIGN1cnJlbnRXb3Jkcy5qb2luKFwiIFwiKSlcbiAgICAgICAgICAgIHRva2VuLnRha2VGb3JtYXQoQGZvbnQpXG4gICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaCh0b2tlbilcbiAgICAgICAgICAgIGxpbmUud2lkdGggPSB3aWR0aFxuICAgICAgICAgICAgbGluZS5oZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIGxpbmUuaGVpZ2h0KVxuICAgICAgICAgICAgbGluZS5kZXNjZW50ID0gTWF0aC5tYXgoZGVzY2VudCwgbGluZS5kZXNjZW50KVxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBsaW5lXG4gICAgXG4gICAgIyMjKlxuICAgICogU3BsaXRzIHVwIHRoZSBzcGVjaWZpZWQgdG9rZW4gdXNpbmcgYSB3b3JkLXdyYXAgdGVjaG5pcXVlLiBUaGUga2luZCBvZiB3b3JkLXdyYXAgdGVjaG5pcXVlXG4gICAgKiBkZXBlbmRzIG9uIHRoZSBzZWxlY3RlZCBsYW5ndWFnZS4gWW91IGNhbiBvdmVyd3JpdGUgdGhpcyBtZXRob2QgaW4gZGVyaXZlZCBjbGFzc2VzIHRvIGltcGxlbWVudCB5b3VyXG4gICAgKiBvd24gY3VzdG9tIHdvcmQtd3JhcCB0ZWNobmlxdWVzLlxuICAgICogXG4gICAgKiBAbWV0aG9kIGV4ZWN1dGVXb3JkV3JhcFxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gVGhlIHRva2VuIHRvIHNwbGl0IHVwLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lfSBsaW5lIC0gVGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFRoZSB3aWR0aCBvZiB0aGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFRoZSBoZWlnaHQgb2YgdGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7Z3MuUmVuZGVyZXJUZXh0TGluZVtdfSAtIEFuIGFycmF5IG9mIGxpbmVzLiBJZiB0aGUgdG9rZW4gaXMgc3BsaXQgdXAgaW50byBtdWx0aXBsZSBsaW5lcywgYWxsIG5ld1xuICAgICogbGluZXMgYXJlIGFkZGVkIHRvIHRoaXMgcmVzdWx0IGFycmF5LlxuICAgICogQHJldHVybiB7Z3MuUmVuZGVyZXJUZXh0TGluZX0gVGhlIGN1cnJlbnQgbGluZSwgdGhhdCBtYXkgYmUgdGhlIHNhbWUgYXMgdGhlIDxiPmxpbmU8L2I+IHBhcmFtZXRlcnMgYnV0IGlmIG5ldyBsaW5lc1xuICAgICogYXJlIGNyZWF0ZWQgaXQgaGFzIHRvIGJlIHRoZSBsYXN0IG5ldyBjcmVhdGVkIGxpbmUuXG4gICAgIyMjXG4gICAgZXhlY3V0ZVdvcmRXcmFwOiAodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdCwgd29yZFdyYXApIC0+XG4gICAgICAgIGlmIHdvcmRXcmFwXG4gICAgICAgICAgICBzd2l0Y2ggTGFuZ3VhZ2VNYW5hZ2VyLmxhbmd1YWdlLndvcmRXcmFwXG4gICAgICAgICAgICAgICAgd2hlbiBcInNwYWNlQmFzZWRcIlxuICAgICAgICAgICAgICAgICAgICBAd29yZFdyYXBTcGFjZUJhc2VkKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQpXG4gICAgICAgICAgICAgICAgd2hlbiBcImphcGFuZXNlXCJcbiAgICAgICAgICAgICAgICAgICAgQHdvcmRXcmFwSmFwYW5lc2UodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdClcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgQHdvcmRXcmFwTm9uZSh0b2tlbiwgbGluZSwgd2lkdGgsIGhlaWdodCwgcmVzdWx0KVxuICAgICAgICAgICAgXG4gIFxuICAgICMjIypcbiAgICAqIENyZWF0ZXMgYW4gYSBvZiBsaW5lLW9iamVjdHMuIEVhY2ggbGluZS1vYmplY3QgaXMgYSBsaXN0IG9mIHRva2VuLW9iamVjdHMuIFxuICAgICogQSB0b2tlbi1vYmplY3QgY2FuIGJlIGp1c3QgYSBzdHJpbmcgb3IgYW4gb2JqZWN0IGNvbnRhaW5pbmcgbW9yZSBpbmZvcm1hdGlvblxuICAgICogYWJvdXQgaG93IHRvIHByb2Nlc3MgdGhlIHRva2VuIGF0IHJ1bnRpbWUuXG4gICAgKiBcbiAgICAqIEEgbGluZS1vYmplY3QgYWxzbyBjb250YWlucyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGxpa2UgdGhlIHdpZHRoIGFuZCBoZWlnaHRcbiAgICAqIG9mIHRoZSBsaW5lKGluIHBpeGVscykuXG4gICAgKiBcbiAgICAqIElmIHRoZSB3b3JkV3JhcCBwYXJhbSBpcyBzZXQsIGxpbmUtYnJlYWtzIGFyZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgaWYgYSBsaW5lXG4gICAgKiBkb2Vzbid0IGZpdCBpbnRvIHRoZSB3aWR0aCBvZiB0aGUgZ2FtZSBvYmplY3QncyBiaXRtYXAuXG4gICAgKiBcbiAgICAqIEBtZXRob2QgY2FsY3VsYXRlTGluZXNcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSBtZXNzYWdlIC0gQSBtZXNzYWdlIGNyZWF0aW5nIHRoZSBsaW5lLW9iamVjdHMgZm9yLlxuICAgICogQHBhcmFtIHtib29sZWFufSB3b3JkV3JhcCAtIElmIHdvcmRXcmFwIGlzIHNldCB0byB0cnVlLCBsaW5lLWJyZWFrcyBhcmUgYXV0b21hdGljYWxseSBjcmVhdGVkLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IFtmaXJzdExpbmVXaWR0aD0wXSAtIFRoZSBjdXJyZW50IHdpZHRoIG9mIHRoZSBmaXJzdCBsaW5lLlxuICAgICogQHJldHVybiB7QXJyYXl9IEFuIGFycmF5IG9mIGxpbmUtb2JqZWN0cy5cbiAgICAjIyNcbiAgICBjYWxjdWxhdGVMaW5lczogKG1lc3NhZ2UsIHdvcmRXcmFwLCBmaXJzdExpbmVXaWR0aCkgLT5cbiAgICAgICAgcmVzdWx0ID0gW11cbiAgICAgICAgbGluZSA9IG5ldyBncy5SZW5kZXJlclRleHRMaW5lKClcbiAgICAgICAgd2lkdGggPSBmaXJzdExpbmVXaWR0aCB8fCAwXG4gICAgICAgIGhlaWdodCA9IDBcbiAgICAgICAgZGVzY2VudCA9IEBmb250LmRlc2NlbnRcbiAgICAgICAgY3VycmVudFdvcmRzID0gW11cbiAgICAgICAgc2l6ZSA9IG51bGxcbiAgICAgICAgQHNwYWNlU2l6ZSA9IEBmb250Lm1lYXN1cmVDaGFyKFwiIFwiKVxuICAgICAgICBAZm9udFNpemUgPSBAZm9udC5zaXplXG4gICAgICAgIFxuICAgICAgICB0b2tlbnMgPSBtZXNzYWdlLnNwbGl0KC9cXHsoW0Etel0rKTooW15cXHtcXH1dKylcXH18KFxcbikvZ20pXG4gICAgICAgIHRva2VuID0gbnVsbFxuICAgICAgICB0ID0gMFxuICAgICAgICBcbiAgICAgICAgdW5kZXJsaW5lID0gQGZvbnQudW5kZXJsaW5lXG4gICAgICAgIHN0cmlrZVRocm91Z2ggPSBAZm9udC5zdHJpa2VUaHJvdWdoXG4gICAgICAgIGl0YWxpYyA9IEBmb250Lml0YWxpY1xuICAgICAgICBib2xkID0gQGZvbnQuYm9sZFxuICAgICAgICBzbWFsbENhcHMgPSBAZm9udC5zbWFsbENhcHNcbiAgICAgICAgXG4gICAgICAgIHdoaWxlIHQgPCB0b2tlbnMubGVuZ3RoXG4gICAgICAgICAgICB0b2tlbiA9IHRva2Vuc1t0XVxuICAgICAgICAgICAgXG4gICAgICAgICAgICBpZiB0ICUgNCAhPSAwXG4gICAgICAgICAgICAgICAgaWYgdG9rZW4/XG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gQGNyZWF0ZVRva2VuKHRva2VuLCB0b2tlbnNbdCsxXSlcbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgIGlmIHRva2VuT2JqZWN0LnB1c2g/XG4gICAgICAgICAgICAgICAgICAgICAgICBBcnJheS5wcm90b3R5cGUuc3BsaWNlLmFwcGx5KHRva2VucywgW3QrMywgMF0uY29uY2F0KHRva2VuT2JqZWN0KSlcbiAgICAgICAgICAgICAgICAgICAgZWxzZSBpZiBub3QgdG9rZW5PYmplY3QuY29kZT9cbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2Vuc1t0KzNdID0gdG9rZW5PYmplY3QgKyB0b2tlbnNbdCszXVxuICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gQG1lYXN1cmVDb250cm9sVG9rZW4odG9rZW5PYmplY3QpXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiBzaXplXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2lkdGggKz0gc2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgc2l6ZS5oZWlnaHQpXG4gICAgICAgICAgICAgICAgICAgICAgICAjZGVzY2VudCA9IE1hdGgubWF4KEBmb250LmRlc2NlbnQsIGRlc2NlbnQpXG4gICAgICAgICAgICAgICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaCh0b2tlbk9iamVjdClcbiAgICAgICAgICAgICAgICBlbHNlICMgTXVzdCBiZSBhIG5ldy1saW5lXG4gICAgICAgICAgICAgICAgICAgIGxpbmUuaGVpZ2h0ID0gaGVpZ2h0IHx8IEBmb250LmxpbmVIZWlnaHRcbiAgICAgICAgICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoXG4gICAgICAgICAgICAgICAgICAgIGxpbmUuZGVzY2VudCA9IGRlc2NlbnRcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0LnB1c2gobGluZSlcbiAgICAgICAgICAgICAgICAgICAgbGluZSA9IG5ldyBncy5SZW5kZXJlclRleHRMaW5lKClcbiAgICAgICAgICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2gobmV3IGdzLlJlbmRlcmVyVG9rZW4obnVsbCwgXCJcXG5cIiwgQGZvbnQpKVxuICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IDBcbiAgICAgICAgICAgICAgICAgICAgaGVpZ2h0ID0gMFxuICAgICAgICAgICAgICAgICAgICBkZXNjZW50ID0gQGZvbnQuZGVzY2VudFxuICAgICAgICAgICAgICAgIHQgKz0gMlxuICAgICAgICAgICAgZWxzZSBpZiB0b2tlbi5sZW5ndGggPiAwXG4gICAgICAgICAgICAgICAgbGluZSA9IEBleGVjdXRlV29yZFdyYXAodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdCwgd29yZFdyYXApXG4gICAgICAgICAgICAgICAgd2lkdGggPSBsaW5lLndpZHRoXG4gICAgICAgICAgICAgICAgaGVpZ2h0ID0gbGluZS5oZWlnaHRcbiAgICAgICAgICAgICAgICBkZXNjZW50ID0gbGluZS5kZXNjZW50XG4gICAgICAgICAgICAgICAgXG4gICAgICAgICAgICB0KytcbiAgICAgICAgICAgIFxuICAgICAgICBpZiBsaW5lLmNvbnRlbnQubGVuZ3RoID4gMCBvciByZXN1bHQubGVuZ3RoID09IDBcbiAgICAgICAgICAgIGxpbmUuaGVpZ2h0ID0gaGVpZ2h0XG4gICAgICAgICAgICBsaW5lLndpZHRoID0gd2lkdGhcbiAgICAgICAgICAgIGxpbmUuZGVzY2VudCA9IGRlc2NlbnRcbiAgICAgICAgICAgIHJlc3VsdC5wdXNoKGxpbmUpXG4gICAgICAgXG4gICAgICAgICBcbiAgICAgICAgQGZvbnQuc2l6ZSA9IEBmb250U2l6ZSAgXG4gICAgICAgIEBmb250LnVuZGVybGluZSA9IHVuZGVybGluZVxuICAgICAgICBAZm9udC5zdHJpa2VUaHJvdWdoID0gc3RyaWtlVGhyb3VnaFxuICAgICAgICBAZm9udC5pdGFsaWMgPSBpdGFsaWNcbiAgICAgICAgQGZvbnQuYm9sZCA9IGJvbGRcbiAgICAgICAgQGZvbnQuc21hbGxDYXBzID0gc21hbGxDYXBzXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgXG4gICAgXG4gICAgIyMjKlxuICAgICogTWVhc3VyZXMgdGhlIGRpbWVuc2lvbnMgb2YgZm9ybWF0dGVkIGxpbmVzIGluIHBpeGVscy4gVGhlIHJlc3VsdCBpcyBub3RcbiAgICAqIHBpeGVsLXBlcmZlY3QuXG4gICAgKiBcbiAgICAqIEBtZXRob2QgbWVhc3VyZUZvcm1hdHRlZExpbmVzXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gbGluZXMgLSBBbiBhcnJheSBvZiB0ZXh0IGxpbmVzIHRvIG1lYXN1cmUuXG4gICAgKiBAcGFyYW0ge2Jvb2xlYW59IHdvcmRXcmFwIC0gSWYgd29yZFdyYXAgaXMgc2V0IHRvIHRydWUsIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBsaW5lLWJyZWFrcyB3aWxsIGJlIGNhbGN1bGF0ZWQuXG4gICAgKiBAcmVzdWx0IHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSB0ZXh0LlxuICAgICMjI1xuICAgIG1lYXN1cmVGb3JtYXR0ZWRMaW5lczogKGxpbmVzLCB3b3JkV3JhcCkgLT5cbiAgICAgICAgc2l6ZSA9IHdpZHRoOiAwLCBoZWlnaHQ6IDBcbiAgICAgICAgXG4gICAgICAgIGZvciBsaW5lIGluIGxpbmVzXG4gICAgICAgICAgICBzaXplLndpZHRoID0gTWF0aC5tYXgobGluZS53aWR0aCsyLCBzaXplLndpZHRoKVxuICAgICAgICAgICAgc2l6ZS5oZWlnaHQgKz0gbGluZS5oZWlnaHQgKyBAbGluZVNwYWNpbmdcblxuICAgICAgICBzaXplLmhlaWdodCAtPSBAbGluZVNwYWNpbmdcbiAgICAgICAgXG4gICAgICAgIHJldHVybiBzaXplXG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIE1lYXN1cmVzIHRoZSBkaW1lbnNpb25zIG9mIGEgZm9ybWF0dGVkIHRleHQgaW4gcGl4ZWxzLiBUaGUgcmVzdWx0IGlzIG5vdFxuICAgICogcGl4ZWwtcGVyZmVjdC5cbiAgICAqIFxuICAgICogQG1ldGhvZCBtZWFzdXJlRm9ybWF0dGVkVGV4dFxuICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgdGV4dCB0byBtZWFzdXJlLlxuICAgICogQHBhcmFtIHtib29sZWFufSB3b3JkV3JhcCAtIElmIHdvcmRXcmFwIGlzIHNldCB0byB0cnVlLCBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgbGluZS1icmVha3Mgd2lsbCBiZSBjYWxjdWxhdGVkLlxuICAgICogQHJlc3VsdCB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd2lkdGggYW5kIGhlaWdodCBvZiB0aGUgdGV4dC5cbiAgICAjIyNcbiAgICBtZWFzdXJlRm9ybWF0dGVkVGV4dDogKHRleHQsIHdvcmRXcmFwKSAtPlxuICAgICAgICBAZm9udC5zZXQoQG9iamVjdC5mb250KVxuICAgICAgICBzaXplID0gbnVsbFxuICAgICAgICBsaW5lcyA9IEBjYWxjdWxhdGVMaW5lcyh0ZXh0LCB3b3JkV3JhcClcbiAgICAgICAgXG4gICAgICAgIHNpemUgPSBAbWVhc3VyZUZvcm1hdHRlZExpbmVzKGxpbmVzLCB3b3JkV3JhcClcbiAgICAgICAgXG4gICAgICAgIHJldHVybiBzaXplXG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIE1lYXN1cmVzIHRoZSBkaW1lbnNpb25zIG9mIGEgcGxhaW4gdGV4dCBpbiBwaXhlbHMuIEZvcm1hdHRpbmcgYW5kXG4gICAgKiB3b3JkLXdyYXBwaW5nIGFyZSBub3Qgc3VwcG9ydGVkLlxuICAgICpcbiAgICAqIEBtZXRob2QgbWVhc3VyZVRleHRcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIHRleHQgdG8gbWVhc3VyZS5cbiAgICAqIEByZXN1bHQge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIHRleHQuXG4gICAgIyMjXG4gICAgbWVhc3VyZVRleHQ6ICh0ZXh0KSAtPlxuICAgICAgICBzaXplID0gd2lkdGg6IDAsIGhlaWdodDogMFxuICAgICAgICBsaW5lcyA9IHRleHQudG9TdHJpbmcoKS5zcGxpdChcIlxcblwiKVxuXG4gICAgICAgIGZvciBsaW5lIGluIGxpbmVzXG4gICAgICAgICAgICBsaW5lU2l6ZSA9IEBvYmplY3QuZm9udC5tZWFzdXJlVGV4dCh0ZXh0KVxuICAgICAgICAgICAgc2l6ZS53aWR0aCA9IE1hdGgubWF4KHNpemUud2lkdGgsIGxpbmVTaXplLndpZHRoKVxuICAgICAgICAgICAgc2l6ZS5oZWlnaHQgKz0gQG9iamVjdC5mb250LmxpbmVIZWlnaHQgKyBAbGluZVNwYWNpbmdcbiAgICAgICAgICAgIFxuICAgICAgICBzaXplLmhlaWdodCAtPSBAbGluZVNwYWNpbmdcbiAgICAgICAgXG4gICAgICAgIHJldHVybiBzaXplXG4gICAgXG4gICAgIyMjKlxuICAgICogU2VhcmNoZXMgZm9yIGEgdG9rZW4gaW4gYSBsaXN0IG9mIHRva2VucyBhbmQgcmV0dXJucyB0aGUgZmlyc3QgbWF0Y2guXG4gICAgKlxuICAgICogQG1ldGhvZCBmaW5kVG9rZW5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydEluZGV4IC0gVGhlIGluZGV4IGluIHRoZSBsaXN0IG9mIHRva2VucyB3aGVyZSB0aGUgc2VhcmNoIHdpbGwgc3RhcnQuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gY29kZSAtIFRoZSBjb2RlIG9mIHRoZSB0b2tlbiB0byBzZWFyY2ggZm9yLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IGRpcmVjdGlvbiAtIFRoZSBzZWFyY2ggZGlyZWN0aW9uLCBjYW4gYmUgZm9yd2FyZCgxKSBvciBiYWNrd2FyZCgtMSkuXG4gICAgKiBAcGFyYW0ge09iamVjdFtdfSB0b2tlbnMgLSBUaGUgbGlzdCBvZiB0b2tlbnMgdG8gc2VhcmNoLlxuICAgICogQHJlc3VsdCB7T2JqZWN0fSBUaGUgZmlyc3QgdG9rZW4gd2hpY2ggbWF0Y2hlcyB0aGUgc3BlY2lmaWVkIGNvZGUgb3IgPGI+bnVsbDwvYj4gaWYgdGhlIHRva2VuIGNhbm5vdCBiZSBmb3VuZC5cbiAgICAjIyMgIFxuICAgIGZpbmRUb2tlbjogKHN0YXJ0SW5kZXgsIGNvZGUsIGRpcmVjdGlvbiwgdG9rZW5zKSAtPlxuICAgICAgICB0b2tlbiA9IG51bGxcbiAgICAgICAgaSA9IHN0YXJ0SW5kZXhcbiAgICAgICAgaWYgZGlyZWN0aW9uID09IC0xXG4gICAgICAgICAgICB3aGlsZSBpID49IDBcbiAgICAgICAgICAgICAgICB0ID0gdG9rZW5zW2ldXG4gICAgICAgICAgICAgICAgaWYgdC5jb2RlID09IGNvZGVcbiAgICAgICAgICAgICAgICAgICAgdG9rZW4gPSB0XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgICAgICAgaS0tXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gdG9rZW5cbiAgICAgXG4gICAgIyMjKlxuICAgICogU2VhcmNoZXMgZm9yIGEgc3BlY2lmaWMga2luZCBvZiB0b2tlbnMgYmV0d2VlbiBhIHN0YXJ0IGFuZCBhbiBlbmQgdG9rZW4uXG4gICAgKlxuICAgICogQG1ldGhvZCBmaW5kVG9rZW5zQmV0d2VlblxuICAgICogQHBhcmFtIHtudW1iZXJ9IHN0YXJ0SW5kZXggLSBUaGUgaW5kZXggd2hlcmUgdGhlIHNlYXJjaCB3aWxsIHN0YXJ0LlxuICAgICogQHBhcmFtIHtudW1iZXJ9IGVuZEluZGV4IC0gVGhlIGluZGV4IHdoZXJlIHRoZSBzZWFyY2ggd2lsbCBlbmQuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gY29kZSAtIFRoZSBjb2RlIG9mIHRoZSB0b2tlbi10eXBlIHRvIHNlYXJjaCBmb3IuXG4gICAgKiBAcGFyYW0ge09iamVjdFtdfSB0b2tlbnMgLSBUaGUgbGlzdCBvZiB0b2tlbnMgdG8gc2VhcmNoLlxuICAgICogQHJlc3VsdCB7T2JqZWN0W119IExpc3Qgb2YgdG9rZW5zIG1hdGNoaW5nIHRoZSBzcGVjaWZpZWQgY29kZS4gSXRzIGFuIGVtcHR5IGxpc3QgaWYgbm8gdG9rZW5zIHdlcmUgZm91bmQuXG4gICAgIyMjICAgICBcbiAgICBmaW5kVG9rZW5zQmV0d2VlbjogKHN0YXJ0SW5kZXgsIGVuZEluZGV4LCBjb2RlLCB0b2tlbnMpIC0+XG4gICAgICAgIHJlc3VsdCA9IFtdXG4gICAgICAgIHMgPSBzdGFydEluZGV4XG4gICAgICAgIGUgPSBlbmRJbmRleFxuICAgICAgICBcbiAgICAgICAgd2hpbGUgcyA8IGVcbiAgICAgICAgICAgIHRva2VuID0gdG9rZW5zW3NdXG4gICAgICAgICAgICBpZiBgdG9rZW4uY29kZSA9PSBjb2RlYFxuICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKHRva2VuKVxuICAgICAgICAgICAgcysrXG4gICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBQcm9jZXNzZXMgYSBjb250cm9sLXRva2VuLiBBIGNvbnRyb2wtdG9rZW4gaXMgYSB0b2tlbiB3aGljaCBpbmZsdWVuY2VzXG4gICAgKiB0aGUgdGV4dC1yZW5kZXJpbmcgbGlrZSBjaGFuZ2luZyB0aGUgZm9udHMgY29sb3IsIHNpemUgb3Igc3R5bGUuXG4gICAgKlxuICAgICogQ2hhbmdlcyB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgYXBwbGllZCB0byB0aGUgZ2FtZSBvYmplY3QncyBmb250LlxuICAgICpcbiAgICAqIEBtZXRob2QgcHJvY2Vzc0NvbnRyb2xUb2tlblxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gQSBjb250cm9sLXRva2VuLlxuICAgICogQHJldHVybiB7T2JqZWN0fSBBbiBvYmplY3Qgd2hpY2ggY2FuIGNvbnRhaW4gYWRkaXRpb25hbCBpbmZvIG5lZWRlZCBmb3IgcHJvY2Vzc2luZy5cbiAgICAjIyNcbiAgICBwcm9jZXNzQ29udHJvbFRva2VuOiAodG9rZW4pIC0+XG4gICAgICAgIHJlc3VsdCA9IG51bGxcbiAgICAgICAgXG4gICAgICAgIHN3aXRjaCB0b2tlbi5jb2RlXG4gICAgICAgICAgICB3aGVuIFwiU1pcIlxuICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5zaXplID0gdG9rZW4udmFsdWUgfHwgQGZvbnRTaXplXG4gICAgICAgICAgICB3aGVuIFwiQ1wiXG4gICAgICAgICAgICAgICAgaWYgdG9rZW4udmFsdWUgPD0gMFxuICAgICAgICAgICAgICAgICAgICBAb2JqZWN0LmZvbnQuY29sb3IgPSBGb250LmRlZmF1bHRDb2xvclxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5mb250LmNvbG9yID0gUmVjb3JkTWFuYWdlci5zeXN0ZW0uY29sb3JzW3Rva2VuLnZhbHVlLTFdIHx8IEZvbnQuZGVmYXVsdENvbG9yXG4gICAgICAgICAgICB3aGVuIFwiWVwiXG4gICAgICAgICAgICAgICAgc3dpdGNoIHRva2VuLnZhbHVlXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJVXCIgdGhlbiBAb2JqZWN0LmZvbnQudW5kZXJsaW5lID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJTXCIgdGhlbiBAb2JqZWN0LmZvbnQuc3RyaWtlVGhyb3VnaCA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiSVwiIHRoZW4gQG9iamVjdC5mb250Lml0YWxpYyA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiQlwiIHRoZW4gQG9iamVjdC5mb250LmJvbGQgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIkNcIiB0aGVuIEBvYmplY3QuZm9udC5zbWFsbENhcHMgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5VXCIgdGhlbiBAb2JqZWN0LmZvbnQudW5kZXJsaW5lID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5TXCIgdGhlbiBAb2JqZWN0LmZvbnQuc3RyaWtlVGhyb3VnaCA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOSVwiIHRoZW4gQG9iamVjdC5mb250LnVuZGVybGluZSA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOQlwiIHRoZW4gQG9iamVjdC5mb250LmJvbGQgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTkNcIiB0aGVuIEBvYmplY3QuZm9udC5zbWFsbENhcHMgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTlwiXG4gICAgICAgICAgICAgICAgICAgICAgICBAb2JqZWN0LmZvbnQudW5kZXJsaW5lID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5zdHJpa2VUaHJvdWdoID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5pdGFsaWMgPSBub1xuICAgICAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5mb250LmJvbGQgPSBub1xuICAgICAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5mb250LnNtYWxsQ2FwcyA9IG5vXG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBEcmF3cyBhIHBsYWluIHRleHQuIEZvcm1hdHRpbmcgYW5kIHdvcmQtd3JhcHBpbmcgYXJlIG5vdCBzdXBwb3J0ZWQuXG4gICAgKlxuICAgICogQG1ldGhvZCBkcmF3VGV4dFxuICAgICogQHBhcmFtIHtudW1iZXJ9IHggLSBUaGUgeC1jb29yZGluYXRlIG9mIHRoZSB0ZXh0J3MgcG9zaXRpb24uXG4gICAgKiBAcGFyYW0ge251bWJlcn0geSAtIFRoZSB5LWNvb3JkaW5hdGUgb2YgdGhlIHRleHQncyBwb3NpdGlvbi5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIERlcHJlY2F0ZWQuIENhbiBiZSBudWxsLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIERlcHJlY2F0ZWQuIENhbiBiZSBudWxsLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IHRleHQgLSBUaGUgdGV4dCB0byBkcmF3LlxuICAgICMjI1xuICAgIGRyYXdUZXh0OiAocGwsIHB0LCBwciwgcGIsIHRleHQpIC0+XG4gICAgICAgIGxpbmVzID0gdGV4dC50b1N0cmluZygpLnNwbGl0KFwiXFxuXCIpXG4gICAgICAgIGZvbnQgPSBAb2JqZWN0LmZvbnRcbiAgICAgICAgaGVpZ2h0ID0gZm9udC5saW5lSGVpZ2h0XG4gICAgICAgIFxuICAgICAgICBmb3IgbGluZSwgaSBpbiBsaW5lc1xuICAgICAgICAgICAgc2l6ZSA9IGZvbnQubWVhc3VyZVRleHQobGluZSlcbiAgICAgICAgICAgIEBvYmplY3QuYml0bWFwLmRyYXdUZXh0KHBsLCBpICogaGVpZ2h0ICsgcHQsIHNpemUud2lkdGggKyBwcitwbCwgaGVpZ2h0K3B0K3BiLCBsaW5lLCAwLCAwKVxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBudWxsXG4gICAgXG4gICAgIyMjKlxuICAgICogRHJhd3MgYW4gYXJyYXkgb2YgZm9ybWF0dGVkIHRleHQgbGluZXMuIFxuICAgICogSWYgdGhlIHdvcmRXcmFwIHBhcmFtIGlzIHNldCwgbGluZS1icmVha3MgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBpZiBhIGxpbmVcbiAgICAqIGRvZXNuJ3QgZml0IGludG8gdGhlIHdpZHRoIG9mIHRoZSBnYW1lIG9iamVjdCdzIGJpdG1hcC5cbiAgICAqXG4gICAgKiBAbWV0aG9kIGRyYXdGb3JtYXR0ZWRMaW5lc1xuICAgICogQHBhcmFtIHtudW1iZXJ9IHBsIC0gVGhlIGxlZnQtcGFkZGluZyBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHB0IC0gVGhlIHRvcC1wYWRkaW5nIG9mIHRoZSB0ZXh0J3MgcG9zaXRpb24uXG4gICAgKiBAcGFyYW0ge251bWJlcn0gcHIgLSBUaGUgcmlnaHQtcGFkZGluZyBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHBiIC0gVGhlIGJvdHRvbS1wYWRkaW5nIG9mIHRoZSB0ZXh0J3MgcG9zaXRpb24uXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gbGluZXMgLSBBbiBhcnJheSBvZiBsaW5lcyB0byBkcmF3LlxuICAgICogQHBhcmFtIHtib29sZWFufSB3b3JkV3JhcCAtIElmIHdvcmRXcmFwIGlzIHNldCB0byB0cnVlLCBsaW5lLWJyZWFrcyBhcmUgYXV0b21hdGljYWxseSBjcmVhdGVkLlxuICAgICMjIyBcbiAgICBkcmF3Rm9ybWF0dGVkTGluZXM6IChwbCwgcHQsIHByLCBwYiwgbGluZXMsIHdvcmRXcmFwKSAtPlxuICAgICAgICBAY3VycmVudFggPSBwbFxuICAgICAgICBAY3VycmVudFkgPSBwdFxuICAgICAgICBAY3VycmVudExpbmVIZWlnaHQgPSAwXG4gICAgXG4gICAgICAgIGZvciBsaW5lIGluIGxpbmVzXG4gICAgICAgICAgICBmb3IgdG9rZW4gaW4gbGluZS5jb250ZW50XG4gICAgICAgICAgICAgICAgaWYgdG9rZW4uY29kZT9cbiAgICAgICAgICAgICAgICAgICAgQHByb2Nlc3NDb250cm9sVG9rZW4odG9rZW4pXG4gICAgICAgICAgICAgICAgICAgIHNpemUgPSBAbWVhc3VyZUNvbnRyb2xUb2tlbih0b2tlbilcbiAgICAgICAgICAgICAgICAgICAgaWYgc2l6ZVxuICAgICAgICAgICAgICAgICAgICAgICAgQGRyYXdDb250cm9sVG9rZW4odG9rZW4sIEBvYmplY3QuYml0bWFwLCBAY3VycmVudFgpXG4gICAgICAgICAgICAgICAgICAgICAgICBAY3VycmVudFggKz0gc2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgIGVsc2UgaWYgdG9rZW4udmFsdWUubGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgICAgICBmb250ID0gQG9iamVjdC5mb250XG4gICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IGxpbmUuaGVpZ2h0XG4gICAgICAgICAgICAgICAgICAgIGlmIHRva2VuLnZhbHVlICE9IFwiXFxuXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSBmb250Lm1lYXN1cmVUZXh0UGxhaW4odG9rZW4udmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgICBAb2JqZWN0LmJpdG1hcC5kcmF3VGV4dChAY3VycmVudFgsIEBjdXJyZW50WSArIGhlaWdodCAtIHNpemUuaGVpZ2h0ICsgZm9udC5kZXNjZW50IC0gbGluZS5kZXNjZW50LCBzaXplLndpZHRoK3BsK3ByLCBoZWlnaHQrcHQrcGIsIHRva2VuLnZhbHVlLCAwLCAwKVxuICAgICAgICAgICAgICAgICAgICAgICAgQGN1cnJlbnRYICs9IHNpemUud2lkdGhcbiAgICAgICAgICAgICAgICAgICAgQGN1cnJlbnRMaW5lSGVpZ2h0ID0gTWF0aC5tYXgoQGN1cnJlbnRMaW5lSGVpZ2h0LCBoZWlnaHQpXG4gICAgICAgICAgICBAY3VycmVudFkgKz0gKEBjdXJyZW50TGluZUhlaWdodCB8fCBAb2JqZWN0LmZvbnQubGluZUhlaWdodCkgKyBAbGluZVNwYWNpbmdcbiAgICAgICAgICAgIEBjdXJyZW50WCA9IHBsXG4gICAgICAgICAgICBAY3VycmVudExpbmVIZWlnaHQgPSAwXG4gICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIG51bGxcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogRHJhd3MgYSBmb3JtYXR0ZWQgdGV4dC4gXG4gICAgKiBJZiB0aGUgd29yZFdyYXAgcGFyYW0gaXMgc2V0LCBsaW5lLWJyZWFrcyBhcmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGlmIGEgbGluZVxuICAgICogZG9lc24ndCBmaXQgaW50byB0aGUgd2lkdGggb2YgdGhlIGdhbWUgb2JqZWN0J3MgYml0bWFwLlxuICAgICpcbiAgICAqIEBtZXRob2QgZHJhd0Zvcm1hdHRlZFRleHRcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB4IC0gVGhlIHgtY29vcmRpbmF0ZSBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHkgLSBUaGUgeS1jb29yZGluYXRlIG9mIHRoZSB0ZXh0J3MgcG9zaXRpb24uXG4gICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBEZXByZWNhdGVkLiBDYW4gYmUgbnVsbC5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBEZXByZWNhdGVkLiBDYW4gYmUgbnVsbC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIHRleHQgdG8gZHJhdy5cbiAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gd29yZFdyYXAgLSBJZiB3b3JkV3JhcCBpcyBzZXQgdG8gdHJ1ZSwgbGluZS1icmVha3MgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZC5cbiAgICAqIEByZXR1cm4ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gVGhlIGRyYXduIHRleHQgbGluZXMuXG4gICAgIyMjXG4gICAgZHJhd0Zvcm1hdHRlZFRleHQ6IChwbCwgcHQsIHByLCBwYiwgdGV4dCwgd29yZFdyYXApIC0+XG4gICAgICAgIGxpbmVzID0gQGNhbGN1bGF0ZUxpbmVzKHRleHQudG9TdHJpbmcoKSwgd29yZFdyYXApXG4gICAgICAgIFxuICAgICAgICBAZHJhd0Zvcm1hdHRlZExpbmVzKHBsLCBwdCwgcHIsIHBiLCBsaW5lcywgd29yZFdyYXApXG4gICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIGxpbmVzXG4gICAgICAgIFxuZ3MuQ29tcG9uZW50X1RleHRSZW5kZXJlciA9IENvbXBvbmVudF9UZXh0UmVuZGVyZXIiXX0=\n//# sourceURL=Component_TextRenderer_120.js"
12 + "compiledContent": "var Component_TextRenderer, RendererTextLine, RendererToken,\n extend = function(child, parent) { for (var key in parent) { if (hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child; },\n hasProp = {}.hasOwnProperty;\n\nRendererTextLine = (function() {\n\n /**\n * Stores a text line.\n * \n * @module gs.RendererTextLine\n * @class RendererTextLine\n * @memberof gs.RendererTextLine\n * @constructor\n */\n function RendererTextLine() {\n\n /*\n * The width of the line in pixels.\n * @property width\n * @type number\n * @protected\n */\n this.width = 0;\n\n /*\n * The height of the line in pixels.\n * @property width\n * @type number\n * @protected\n */\n this.height = 0;\n\n /*\n * The descent of the line in pixels.\n * @property descent\n * @type number\n * @protected\n */\n this.descent = 0;\n\n /*\n * The content of the line as token objects.\n * @property content\n * @type Object[]\n * @protected\n */\n this.content = [];\n }\n\n return RendererTextLine;\n\n})();\n\ngs.RendererTextLine = RendererTextLine;\n\nRendererToken = (function() {\n\n /**\n * Stores a token.\n * \n * @module gs\n * @class RendererToken\n * @memberof gs\n * @constructor\n */\n function RendererToken(code, value, font) {\n\n /*\n * The value of the token. That value depends on the token type. For text-tokens, it stores\n * the actual text.\n * @property content\n * @type string\n */\n this.value = value;\n\n /*\n * The code describes what kind of token it is. For example, if the code is \"Y\" it means it is a\n * style-token. If the code is <b>null</b>, it means it is a text-token.\n * @property code\n * @type string\n */\n this.code = code;\n\n /*\n * The format stores the font-style properties of the token like if it is italic, bold, etc. It can be <b>null</b>.\n * @property format\n * @type Object\n */\n this.format = null;\n\n /*\n * A plain object to store custom data within the token.\n * @property customData\n * @type Object\n */\n this.customData = {};\n if (font != null) {\n this.takeFormat(font);\n }\n }\n\n\n /**\n * Takes the style from the specified font and stores it into the format-property. The token will\n * will be rendered with that style then.\n * \n * @method takeFormat\n * @param {gs.Font} font - The font to take the style from.\n */\n\n RendererToken.prototype.takeFormat = function(font) {\n return this.format = font.toDataBundle();\n };\n\n\n /**\n * Applies the format-style of the token on the specified font. The font will have the style from\n * then token then.\n * \n * @method applyFormat\n * @param {gs.Font} font - The font to apply the format-style on.\n */\n\n RendererToken.prototype.applyFormat = function(font) {\n return font.set(this.format);\n };\n\n return RendererToken;\n\n})();\n\ngs.RendererToken = RendererToken;\n\nComponent_TextRenderer = (function(superClass) {\n extend(Component_TextRenderer, superClass);\n\n\n /**\n * A text-renderer component allow to draw plain or formatted text on a\n * game object's bitmap. For formatted text, different text-codes can be\n * used to add formatting or define a placeholder.<br><br>\n * \n * A text-code uses the following syntax:<br><br>\n * \n * {code:value} <- Single Value<br />\n * {code:value1,value2,...} <- Multiple Values<br><br>\n * \n * Example:<br><br>\n * \n * \"This is {Y:I}a Text{Y:N}\" <- \"a Text\" will be italic here.<br>\n * \"The value is {GN:1}\" <- \"{GN:1}\" will be replaced for the value of the global number variable 0001.<br><br>\n * \n * For a list of all available text-codes with examples, just take a look into the offical help-file.\n * \n * @module gs\n * @class Component_TextRenderer\n * @extends gs.Component\n * @memberof gs\n * @constructor\n */\n\n function Component_TextRenderer() {\n Component_TextRenderer.__super__.constructor.apply(this, arguments);\n\n /**\n * @property currentX\n * @type number\n * @protected\n */\n this.currentX = 0;\n\n /**\n * @property currentY\n * @type number\n * @protected\n */\n this.currentY = 0;\n\n /**\n * @property currentLineHeight\n * @type number\n * @protected\n */\n this.currentLineHeight = 0;\n\n /**\n * @property font\n * @type gs.Font\n * @protected\n */\n this.font = new Font(\"Times New Roman\", 22);\n\n /**\n * @property spaceSize\n * @type number\n * @protected\n */\n this.spaceSize = 0;\n\n /**\n * @property fontSize\n * @type number\n * @protected\n */\n this.fontSize = 0;\n\n /**\n * The left and right padding per line.\n * @property padding\n * @type number\n */\n this.padding = 0;\n\n /**\n * The spacing between text lines in pixels.\n * @property lineSpacing\n * @type number\n */\n this.lineSpacing = 0;\n }\n\n\n /**\n * Creates the token-object for a list-placeholder. A list-placeholder\n * allows to insert a value from a list-variable.\n * \n * @method createListToken\n * @param {Array} list - The list.\n * @param {Array} values - The values of the list-placeholder text-code.\n * @return {string} The token-object.\n */\n\n Component_TextRenderer.prototype.createListToken = function(list, values) {\n var index;\n index = 0;\n if (values[1] != null) {\n values = values[1].split(\":\");\n index = values[0];\n if (values[0] === \"G\") {\n index = GameManager.variableStore.numbers[parseInt(values[1]) - 1];\n } else if (values[0] === \"P\") {\n index = GameManager.variableStore.persistentNumbers[parseInt(values[1]) - 1];\n } else if (values[0] === \"L\") {\n index = GameManager.variableStore.numberValueOf({\n scope: 0,\n index: parseInt(values[1]) - 1\n });\n }\n }\n return \"\" + list[index];\n };\n\n\n /**\n * Parses and returns the variable identifier which is an array containing\n * the optional domain name and the variable index as: [domain, index].\n * \n * @method parseVariableIdentifier\n * @param {string} identifier - The variable identifier e.g. com.degica.vnm.default.1 or com.degica.vnm.default.VarName\n * @param {string} type - The variable type to parse: number, string, boolean or list\n * @param {string} type - The scope of the variable to parse: 0 = local, 1 = global, 2 = persistent.\n * @return {Array} An array containing two values as: [domain, index]. If the identifier doesn't contain a domain-string, the domain will be 0 (default).\n */\n\n Component_TextRenderer.prototype.parseVariableIdentifier = function(identifier, type, scope) {\n var index, result;\n result = [0, identifier];\n if (isNaN(identifier)) {\n index = identifier.lastIndexOf(\".\");\n if (index !== -1) {\n result[0] = identifier.substring(0, index);\n result[1] = identifier.substring(index + 1);\n if (isNaN(result[1])) {\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1;\n } else {\n result[1] = parseInt(result[1]);\n }\n } else {\n result[1] = GameManager.variableStore.indexOfVariable(result[1], type, scope, result[0]) + 1;\n }\n } else {\n result[1] = parseInt(result[1]);\n }\n return result;\n };\n\n\n /**\n * Creates a token-object for a specified text-code.\n * \n * @method createToken\n * @param {string} code - The code/type of the text-code.\n * @param {string} value - The value of the text-code.\n * @return {Object} The token-object.\n */\n\n Component_TextRenderer.prototype.createToken = function(code, value) {\n var format, listIdentifier, macro, pair, ref, ref1, ref2, ref3, ref4, ref5, ref6, ref7, ref8, tokenObject, values;\n tokenObject = null;\n value = isNaN(value) ? value : parseInt(value);\n switch (code) {\n case \"SZ\":\n tokenObject = new gs.RendererToken(code, value);\n this.font.size = tokenObject.value || this.fontSize;\n this.spaceSize = this.font.measureTextPlain(\" \");\n break;\n case \"Y\":\n tokenObject = {\n code: code,\n value: value\n };\n switch (value) {\n case \"U\":\n this.font.underline = true;\n break;\n case \"S\":\n this.font.strikeThrough = true;\n break;\n case \"I\":\n this.font.italic = true;\n break;\n case \"B\":\n this.font.bold = true;\n break;\n case \"C\":\n this.font.smallCaps = true;\n break;\n case \"NU\":\n this.font.underline = false;\n break;\n case \"NS\":\n this.font.strikeThrough = false;\n break;\n case \"NI\":\n this.font.italic = false;\n break;\n case \"NB\":\n this.font.bold = false;\n break;\n case \"NC\":\n this.font.smallCaps = false;\n break;\n case \"N\":\n this.font.underline = false;\n this.font.strikeThrough = false;\n this.font.italic = false;\n this.font.bold = false;\n this.font.smallCaps = false;\n }\n this.spaceSize = this.font.measureTextPlain(\" \");\n break;\n case \"C\":\n tokenObject = new gs.RendererToken(code, value);\n if (value <= 0) {\n this.font.color = Font.defaultColor;\n } else {\n this.font.color = gs.Color.fromObject(RecordManager.system.colors[value - 1] || Font.defaultColor);\n }\n break;\n case \"GN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 1);\n tokenObject = sprintf(\"%\" + format + \"d\", GameManager.variableStore.numbersByDomain[values[0] || 0][values[1] - 1] || 0);\n } else {\n values = this.parseVariableIdentifier(values[0], \"number\", 1);\n tokenObject = (GameManager.variableStore.numbersByDomain[values[0] || 0][values[1] - 1] || 0).toString();\n }\n break;\n case \"GT\":\n values = this.parseVariableIdentifier(value, \"string\", 1);\n tokenObject = GameManager.variableStore.stringsByDomain[values[0] || 0][values[1] - 1] || \"\";\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref = tokenObject[0]) != null ? ref : \"\";\n }\n break;\n case \"GS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 1);\n tokenObject = (GameManager.variableStore.booleansByDomain[values[0] || 0][values[1] - 1] || false).toString();\n break;\n case \"GL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 1);\n tokenObject = this.createListToken(GameManager.variableStore.listsByDomain[listIdentifier[0]][listIdentifier[1] - 1] || [], values);\n break;\n case \"PN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 2);\n tokenObject = sprintf(\"%\" + format + \"d\", ((ref1 = GameManager.variableStore.persistentNumbers[values[0]]) != null ? ref1[values[1] - 1] : void 0) || 0);\n } else {\n values = this.parseVariableIdentifier(values[0], \"number\", 2);\n tokenObject = (((ref2 = GameManager.variableStore.persistentNumbersByDomain[values[0] || 0]) != null ? ref2[values[1] - 1] : void 0) || 0).toString();\n }\n break;\n case \"PT\":\n values = this.parseVariableIdentifier(value, \"string\", 2);\n tokenObject = ((ref3 = GameManager.variableStore.persistentStringsByDomain[values[0]]) != null ? ref3[values[1] - 1] : void 0) || \"\";\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref4 = tokenObject[0]) != null ? ref4 : \"\";\n }\n break;\n case \"PS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 2);\n tokenObject = (((ref5 = GameManager.variableStore.persistentBooleansByDomain[values[0]]) != null ? ref5[values[1] - 1] : void 0) || false).toString();\n break;\n case \"PL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 2);\n tokenObject = this.createListToken(((ref6 = GameManager.variableStore.persistentListsByDomain[listIdentifier[0]]) != null ? ref6[listIdentifier[1] - 1] : void 0) || [], values);\n break;\n case \"LN\":\n values = isNaN(value) ? value.split(\",\") : [value];\n if (values[1]) {\n format = values[1];\n values = this.parseVariableIdentifier(values[0], \"number\", 0);\n tokenObject = sprintf(\"%\" + format + \"d\", GameManager.variableStore.numberValueOf({\n scope: 0,\n index: values[1] - 1\n }) || 0);\n } else {\n values = this.parseVariableIdentifier(values[0], \"number\", 0);\n tokenObject = (GameManager.variableStore.numberValueOf({\n scope: 0,\n index: values[1] - 1\n }) || 0).toString();\n }\n break;\n case \"LT\":\n values = this.parseVariableIdentifier(value, \"string\", 0);\n tokenObject = (GameManager.variableStore.stringValueOf({\n scope: 0,\n index: values[1] - 1\n }) || \"\").toString();\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n } else {\n tokenObject = (ref7 = tokenObject[0]) != null ? ref7 : \"\";\n }\n break;\n case \"LS\":\n values = this.parseVariableIdentifier(value, \"boolean\", 0);\n tokenObject = (GameManager.variableStore.booleanValueOf({\n scope: 0,\n index: values[1] - 1\n }) || false).toString();\n break;\n case \"LL\":\n values = value.split(\",\");\n listIdentifier = this.parseVariableIdentifier(values[0], \"list\", 0);\n tokenObject = this.createListToken(GameManager.variableStore.listObjectOf({\n scope: 0,\n index: listIdentifier[1] - 1\n }) || [], values);\n break;\n case \"N\":\n tokenObject = (RecordManager.characters[value] != null ? lcs(RecordManager.characters[value].name) : \"\");\n break;\n case \"RT\":\n pair = value.split(\"/\");\n tokenObject = {\n code: code,\n rtStyleId: (ref8 = pair[2]) != null ? ref8 : 0,\n rb: pair[0],\n rt: pair[1],\n rbSize: {\n width: 0,\n height: 0\n },\n rtSize: {\n width: 0,\n height: 0\n }\n };\n break;\n case \"M\":\n macro = RecordManager.system.textMacros.first(function(m) {\n return m.name === value;\n });\n if (macro) {\n if (macro.type === 0) {\n tokenObject = macro.content.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n tokenObject.pop();\n } else if (macro.type === 1) {\n if (!macro.contentFunc) {\n macro.contentFunc = eval(\"(function(object, value){ \" + macro.content + \" })\");\n }\n tokenObject = macro.contentFunc(this.object, value);\n tokenObject = tokenObject.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n if (tokenObject.length > 1) {\n tokenObject.pop();\n }\n } else {\n if (!macro.contentFunc) {\n macro.contentFunc = eval(\"(function(object){ \" + macro.content + \" })\");\n }\n tokenObject = new gs.RendererToken(\"X\", macro.contentFunc);\n }\n } else {\n tokenObject = \"\";\n }\n break;\n default:\n tokenObject = new gs.RendererToken(code, value);\n }\n return tokenObject;\n };\n\n\n /**\n * <p>Gets the correct font for the specified ruby-text token.</p> \n *\n * @param {Object} token - A ruby-text token.\n * @return {gs.Font} The font for the ruby-text which is shown above the original text.\n * @method getRubyTextFont\n */\n\n Component_TextRenderer.prototype.getRubyTextFont = function(token) {\n var font, ref, style;\n style = null;\n font = null;\n if (token.rtStyleId) {\n style = ui.UIManager.styles[\"rubyText-\" + token.rtStyleId];\n }\n if (!style) {\n style = ui.UIManager.styles[\"rubyText\"];\n }\n font = (ref = style != null ? style.font : void 0) != null ? ref : this.font;\n font.size = font.size || this.font.size / 2;\n return font;\n };\n\n\n /**\n * <p>Measures a control-token. If a token produces a visual result like displaying an icon then it must return the size taken by\n * the visual result. If the token has no visual result, <b>null</b> must be returned. This method is called for every token when the message is initialized.</p> \n *\n * @param {Object} token - A control-token.\n * @return {gs.Size} The size of the area taken by the visual result of the token or <b>null</b> if the token has no visual result.\n * @method measureControlToken\n * @protected\n */\n\n Component_TextRenderer.prototype.measureControlToken = function(token) {\n var animation, font, fs, imageBitmap, size;\n size = null;\n switch (token.code) {\n case \"A\":\n animation = RecordManager.animations[Math.max(token.value - 1, 0)];\n if ((animation != null ? animation.graphic.name : void 0) != null) {\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/\" + animation.graphic.name);\n if (imageBitmap != null) {\n size = {\n width: Math.round(imageBitmap.width / animation.framesX),\n height: Math.round(imageBitmap.height / animation.framesY)\n };\n }\n }\n break;\n case \"RT\":\n font = this.getRubyTextFont(token);\n fs = font.size;\n font.size = font.size || this.font.size / 2;\n token.rbSize = this.font.measureTextPlain(token.rb);\n token.rtSize = font.measureTextPlain(token.rt);\n font.size = fs;\n size = {\n width: Math.max(token.rbSize.width, token.rtSize.width),\n height: token.rbSize.height + token.rtSize.height\n };\n }\n return size;\n };\n\n\n /**\n * <p>Draws the visual result of a token, like an icon for example, to the specified bitmap. This method is called for every token while the text is rendered.</p> \n *\n * @param {Object} token - A control-token.\n * @param {gs.Bitmap} bitmap - The bitmap used for the current text-line. Can be used to draw something on it like an icon, etc.\n * @param {number} offset - An x-offset for the draw-routine.\n * @method drawControlToken\n * @protected\n */\n\n Component_TextRenderer.prototype.drawControlToken = function(token, bitmap, offset) {\n var animation, font, fs, imageBitmap, rect, ref, ref1, style;\n switch (token.code) {\n case \"A\":\n animation = RecordManager.animations[Math.max(token.value - 1, 0)];\n if ((animation != null ? animation.graphic.name : void 0) != null) {\n imageBitmap = ResourceManager.getBitmap(\"Graphics/Pictures/\" + animation.graphic.name);\n if (imageBitmap != null) {\n rect = new gs.Rect(0, 0, Math.round(imageBitmap.width / animation.framesX), Math.round(imageBitmap.height / animation.framesY));\n return bitmap.blt(offset, this.currentY, imageBitmap, rect);\n }\n }\n break;\n case \"RT\":\n style = null;\n if (token.rtStyleId) {\n style = ui.UIManager.styles[\"rubyText-\" + token.rtStyleId];\n }\n if (!style) {\n style = ui.UIManager.styles[\"rubyText\"];\n }\n font = (ref = style != null ? style.font : void 0) != null ? ref : this.font;\n fs = font.size;\n font.size = font.size || this.font.size / 2;\n if (style && !((ref1 = style.descriptor.font) != null ? ref1.color : void 0)) {\n font.color.set(this.font.color);\n }\n bitmap.font = font;\n bitmap.drawText(offset, bitmap.font.descent, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rt, 1, 0);\n bitmap.font = this.font;\n font.size = fs;\n return bitmap.drawText(offset, token.rtSize.height, Math.max(token.rbSize.width, token.rtSize.width), bitmap.height, token.rb, 1, 0);\n }\n };\n\n\n /**\n * Splits up the specified token using a japanese word-wrap technique.\n * \n * @method wordWrapJapanese\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapJapanese = function(token, line, width, height, result) {\n var ch, depth, depthLevel, descent, endOfLine, i, j, lastCharacterIndex, moved, noSplit, size, startOfLine;\n startOfLine = '—…‥〳〴〵。.・、:;, ?!‼⁇⁈⁉‐゠–〜)]}〕〉》」』】〙〗〟’\"⦆»ヽヾーァィゥェォッャュョヮヵヶぁぃぅぇぉっゃゅょゎゕゖㇰㇱㇲㇳㇴㇵㇶㇷㇸㇹㇺㇻㇼㇽㇾㇿ々〻';\n endOfLine = '([{〔〈《「『【〘〖〝‘\"⦅«';\n noSplit = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890123456789—…‥〳〴〵';\n descent = this.font.descent;\n size = this.font.measureTextPlain(token);\n depth = 8;\n depthLevel = 0;\n i = 0;\n j = 0;\n lastCharacterIndex = 0;\n if (size.width > this.object.dstRect.width - this.spaceSize.width * 3 - this.padding * 2) {\n while (i < token.length) {\n ch = token[i];\n size = this.font.measureTextPlain(ch);\n width += size.width;\n moved = false;\n if (width > this.object.dstRect.width - this.padding * 2) {\n depthLevel = 0;\n j = i;\n while (true) {\n moved = false;\n while (j > 0 && startOfLine.indexOf(token[j]) !== -1) {\n j--;\n moved = true;\n }\n while (j > 0 && endOfLine.indexOf(token[j - 1]) !== -1) {\n j--;\n moved = true;\n }\n while (j > 0 && noSplit.indexOf(token[j - 1]) !== -1) {\n j--;\n moved = true;\n }\n if (j === 0 && moved) {\n break;\n } else {\n i = j;\n }\n depthLevel++;\n if (depthLevel >= depth || !moved) {\n break;\n }\n }\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), this.font));\n lastCharacterIndex = i;\n line.height = Math.max(height, this.font.lineHeight);\n line.width = width - size.width;\n line.descent = descent;\n descent = this.font.descent;\n height = size.height;\n result.push(line);\n line = new gs.RendererTextLine();\n width = width - (width - size.width);\n }\n i++;\n }\n } else {\n line.content.push(new gs.RendererToken(null, token, this.font));\n line.height = Math.max(height, this.font.lineHeight);\n line.width = width + size.width;\n line.descent = descent;\n }\n height = Math.max(height, this.font.lineHeight);\n if (lastCharacterIndex !== i) {\n line.content.push(new gs.RendererToken(null, token.substring(lastCharacterIndex, i), this.font));\n line.width = width;\n line.height = Math.max(height, line.height);\n line.descent = descent;\n }\n return line;\n };\n\n\n /**\n * Does not word-wrapping at all. It just adds the text token to the line as is.\n * \n * @method wordWrapNone\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapNone = function(token, line, width, height, result) {\n var size;\n size = this.font.measureTextPlain(token);\n height = Math.max(size.height, height || this.font.lineHeight);\n if (token.length > 0) {\n line.width += size.width;\n line.height = Math.max(height, line.height);\n line.descent = this.font.descent;\n line.content.push(new gs.RendererToken(null, token));\n }\n return line;\n };\n\n\n /**\n * Splits up the specified token using a space-based word-wrap technique.\n * \n * @method wordWrapSpaceBased\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.wordWrapSpaceBased = function(token, line, width, height, result) {\n var currentWords, descent, i, k, len, size, word, words;\n currentWords = [];\n words = token.split(\" \");\n descent = this.font.descent;\n this.spaceSize = this.font.measureTextPlain(\" \");\n for (i = k = 0, len = words.length; k < len; i = ++k) {\n word = words[i];\n size = this.font.measureTextPlain(word);\n width += size.width + this.spaceSize.width;\n if (width > this.object.dstRect.width - this.padding * 2) {\n token = new gs.RendererToken(null, currentWords.join(\" \"));\n token.takeFormat(this.font);\n line.content.push(token);\n line.height = Math.max(height, line.height);\n line.width = width - size.width;\n line.descent = Math.max(line.descent, descent);\n descent = Math.max(descent, this.font.descent);\n height = size.height;\n result.push(line);\n line = new gs.RendererTextLine();\n currentWords = [word];\n width = width - (width - size.width);\n } else {\n currentWords.push(word);\n }\n height = Math.max(height, this.font.lineHeight);\n }\n if (currentWords.length > 0) {\n token = new gs.RendererToken(null, currentWords.join(\" \"));\n token.takeFormat(this.font);\n line.content.push(token);\n line.width = width;\n line.height = Math.max(height, line.height);\n line.descent = Math.max(descent, line.descent);\n }\n return line;\n };\n\n\n /**\n * Splits up the specified token using a word-wrap technique. The kind of word-wrap technique\n * depends on the selected language. You can overwrite this method in derived classes to implement your\n * own custom word-wrap techniques.\n * \n * @method executeWordWrap\n * @param {Object} token - The token to split up.\n * @param {gs.RendererTextLine} line - The current line.\n * @param {number} width - The width of the current line.\n * @param {number} height - The height of the current line.\n * @param {gs.RendererTextLine[]} - An array of lines. If the token is split up into multiple lines, all new\n * lines are added to this result array.\n * @return {gs.RendererTextLine} The current line, that may be the same as the <b>line</b> parameters but if new lines\n * are created it has to be the last new created line.\n */\n\n Component_TextRenderer.prototype.executeWordWrap = function(token, line, width, height, result, wordWrap) {\n if (wordWrap) {\n switch (LanguageManager.language.wordWrap) {\n case \"spaceBased\":\n return this.wordWrapSpaceBased(token, line, width, height, result);\n case \"japanese\":\n return this.wordWrapJapanese(token, line, width, height, result);\n }\n } else {\n return this.wordWrapNone(token, line, width, height, result);\n }\n };\n\n\n /**\n * Creates an a of line-objects. Each line-object is a list of token-objects. \n * A token-object can be just a string or an object containing more information\n * about how to process the token at runtime.\n * \n * A line-object also contains additional information like the width and height\n * of the line(in pixels).\n * \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n * \n * @method calculateLines\n * @param {string} message - A message creating the line-objects for.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @param {number} [firstLineWidth=0] - The current width of the first line.\n * @return {Array} An array of line-objects.\n */\n\n Component_TextRenderer.prototype.calculateLines = function(message, wordWrap, firstLineWidth) {\n var bold, currentWords, descent, height, italic, line, result, size, smallCaps, strikeThrough, t, token, tokenObject, tokens, underline, width;\n result = [];\n line = new gs.RendererTextLine();\n width = firstLineWidth || 0;\n height = 0;\n descent = this.font.descent;\n currentWords = [];\n size = null;\n this.spaceSize = this.font.measureChar(\" \");\n this.fontSize = this.font.size;\n tokens = message.split(/\\{([A-z]+):([^\\{\\}]+)\\}|(\\n)/gm);\n token = null;\n t = 0;\n underline = this.font.underline;\n strikeThrough = this.font.strikeThrough;\n italic = this.font.italic;\n bold = this.font.bold;\n smallCaps = this.font.smallCaps;\n while (t < tokens.length) {\n token = tokens[t];\n if (t % 4 !== 0) {\n if (token != null) {\n tokenObject = this.createToken(token, tokens[t + 1]);\n if (tokenObject.push != null) {\n Array.prototype.splice.apply(tokens, [t + 3, 0].concat(tokenObject));\n } else if (tokenObject.code == null) {\n tokens[t + 3] = tokenObject + tokens[t + 3];\n } else {\n size = this.measureControlToken(tokenObject);\n if (size) {\n width += size.width;\n height = Math.max(height, size.height);\n }\n line.content.push(tokenObject);\n }\n } else {\n line.height = height || this.font.lineHeight;\n line.width = width;\n line.descent = descent;\n result.push(line);\n line = new gs.RendererTextLine();\n line.content.push(new gs.RendererToken(null, \"\\n\", this.font));\n width = 0;\n height = 0;\n descent = this.font.descent;\n }\n t += 2;\n } else if (token.length > 0) {\n line = this.executeWordWrap(token, line, width, height, result, wordWrap);\n width = line.width;\n height = line.height;\n descent = line.descent;\n }\n t++;\n }\n if (line.content.length > 0 || result.length === 0) {\n line.height = height;\n line.width = width;\n line.descent = descent;\n result.push(line);\n }\n this.font.size = this.fontSize;\n this.font.underline = underline;\n this.font.strikeThrough = strikeThrough;\n this.font.italic = italic;\n this.font.bold = bold;\n this.font.smallCaps = smallCaps;\n return result;\n };\n\n\n /**\n * Measures the dimensions of formatted lines in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedLines\n * @param {gs.RendererTextLine[]} lines - An array of text lines to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureFormattedLines = function(lines, wordWrap) {\n var k, len, line, size;\n size = {\n width: 0,\n height: 0\n };\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n size.width = Math.max(line.width + 2, size.width);\n size.height += line.height + this.lineSpacing;\n }\n size.height -= this.lineSpacing;\n return size;\n };\n\n\n /**\n * Measures the dimensions of a formatted text in pixels. The result is not\n * pixel-perfect.\n * \n * @method measureFormattedText\n * @param {string} text - The text to measure.\n * @param {boolean} wordWrap - If wordWrap is set to true, automatically created line-breaks will be calculated.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureFormattedText = function(text, wordWrap) {\n var lines, size;\n this.font.set(this.object.font);\n size = null;\n lines = this.calculateLines(text, wordWrap);\n size = this.measureFormattedLines(lines, wordWrap);\n return size;\n };\n\n\n /**\n * Measures the dimensions of a plain text in pixels. Formatting and\n * word-wrapping are not supported.\n *\n * @method measureText\n * @param {string} text - The text to measure.\n * @result {Object} An object containing the width and height of the text.\n */\n\n Component_TextRenderer.prototype.measureText = function(text) {\n var k, len, line, lineSize, lines, size;\n size = {\n width: 0,\n height: 0\n };\n lines = text.toString().split(\"\\n\");\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n lineSize = this.object.font.measureText(text);\n size.width = Math.max(size.width, lineSize.width);\n size.height += this.object.font.lineHeight + this.lineSpacing;\n }\n size.height -= this.lineSpacing;\n return size;\n };\n\n\n /**\n * Searches for a token in a list of tokens and returns the first match.\n *\n * @method findToken\n * @param {number} startIndex - The index in the list of tokens where the search will start.\n * @param {string} code - The code of the token to search for.\n * @param {number} direction - The search direction, can be forward(1) or backward(-1).\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object} The first token which matches the specified code or <b>null</b> if the token cannot be found.\n */\n\n Component_TextRenderer.prototype.findToken = function(startIndex, code, direction, tokens) {\n var i, t, token;\n token = null;\n i = startIndex;\n if (direction === -1) {\n while (i >= 0) {\n t = tokens[i];\n if (t.code === code) {\n token = t;\n break;\n }\n i--;\n }\n }\n return token;\n };\n\n\n /**\n * Searches for a specific kind of tokens between a start and an end token.\n *\n * @method findTokensBetween\n * @param {number} startIndex - The index where the search will start.\n * @param {number} endIndex - The index where the search will end.\n * @param {string} code - The code of the token-type to search for.\n * @param {Object[]} tokens - The list of tokens to search.\n * @result {Object[]} List of tokens matching the specified code. Its an empty list if no tokens were found.\n */\n\n Component_TextRenderer.prototype.findTokensBetween = function(startIndex, endIndex, code, tokens) {\n var e, result, s, token;\n result = [];\n s = startIndex;\n e = endIndex;\n while (s < e) {\n token = tokens[s];\n if (token.code == code) {\n result.push(token);\n }\n s++;\n }\n return result;\n };\n\n\n /**\n * Processes a control-token. A control-token is a token which influences\n * the text-rendering like changing the fonts color, size or style.\n *\n * Changes will be automatically applied to the game object's font.\n *\n * @method processControlToken\n * @param {Object} token - A control-token.\n * @return {Object} An object which can contain additional info needed for processing.\n */\n\n Component_TextRenderer.prototype.processControlToken = function(token) {\n var result;\n result = null;\n switch (token.code) {\n case \"SZ\":\n this.object.font.size = token.value || this.fontSize;\n break;\n case \"C\":\n if (token.value <= 0) {\n this.object.font.color = Font.defaultColor;\n } else {\n this.object.font.color = RecordManager.system.colors[token.value - 1] || Font.defaultColor;\n }\n break;\n case \"Y\":\n switch (token.value) {\n case \"U\":\n this.object.font.underline = true;\n break;\n case \"S\":\n this.object.font.strikeThrough = true;\n break;\n case \"I\":\n this.object.font.italic = true;\n break;\n case \"B\":\n this.object.font.bold = true;\n break;\n case \"C\":\n this.object.font.smallCaps = true;\n break;\n case \"NU\":\n this.object.font.underline = false;\n break;\n case \"NS\":\n this.object.font.strikeThrough = false;\n break;\n case \"NI\":\n this.object.font.underline = false;\n break;\n case \"NB\":\n this.object.font.bold = false;\n break;\n case \"NC\":\n this.object.font.smallCaps = false;\n break;\n case \"N\":\n this.object.font.underline = false;\n this.object.font.strikeThrough = false;\n this.object.font.italic = false;\n this.object.font.bold = false;\n this.object.font.smallCaps = false;\n }\n }\n return result;\n };\n\n\n /**\n * Draws a plain text. Formatting and word-wrapping are not supported.\n *\n * @method drawText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n */\n\n Component_TextRenderer.prototype.drawText = function(pl, pt, pr, pb, text) {\n var font, height, i, k, len, line, lines, size;\n lines = text.toString().split(\"\\n\");\n font = this.object.font;\n height = font.lineHeight;\n for (i = k = 0, len = lines.length; k < len; i = ++k) {\n line = lines[i];\n size = font.measureText(line);\n this.object.bitmap.drawText(pl, i * height + pt, size.width + pr + pl, height + pt + pb, line, 0, 0);\n }\n return null;\n };\n\n\n /**\n * Draws an array of formatted text lines. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedLines\n * @param {number} pl - The left-padding of the text's position.\n * @param {number} pt - The top-padding of the text's position.\n * @param {number} pr - The right-padding of the text's position.\n * @param {number} pb - The bottom-padding of the text's position.\n * @param {gs.RendererTextLine[]} lines - An array of lines to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n */\n\n Component_TextRenderer.prototype.drawFormattedLines = function(pl, pt, pr, pb, lines, wordWrap) {\n var font, height, k, l, len, len1, line, ref, size, token;\n this.currentX = pl;\n this.currentY = pt;\n this.currentLineHeight = 0;\n for (k = 0, len = lines.length; k < len; k++) {\n line = lines[k];\n ref = line.content;\n for (l = 0, len1 = ref.length; l < len1; l++) {\n token = ref[l];\n if (token.code != null) {\n this.processControlToken(token);\n size = this.measureControlToken(token);\n if (size) {\n this.drawControlToken(token, this.object.bitmap, this.currentX);\n this.currentX += size.width;\n }\n } else if (token.value.length > 0) {\n font = this.object.font;\n height = line.height;\n if (token.value !== \"\\n\") {\n size = font.measureTextPlain(token.value);\n this.object.bitmap.drawText(this.currentX, this.currentY + height - size.height + font.descent - line.descent, size.width + pl + pr, height + pt + pb, token.value, 0, 0);\n this.currentX += size.width;\n }\n this.currentLineHeight = Math.max(this.currentLineHeight, height);\n }\n }\n this.currentY += (this.currentLineHeight || this.object.font.lineHeight) + this.lineSpacing;\n this.currentX = pl;\n this.currentLineHeight = 0;\n }\n return null;\n };\n\n\n /**\n * Draws a formatted text. \n * If the wordWrap param is set, line-breaks are automatically created if a line\n * doesn't fit into the width of the game object's bitmap.\n *\n * @method drawFormattedText\n * @param {number} x - The x-coordinate of the text's position.\n * @param {number} y - The y-coordinate of the text's position.\n * @param {number} width - Deprecated. Can be null.\n * @param {number} height - Deprecated. Can be null.\n * @param {string} text - The text to draw.\n * @param {boolean} wordWrap - If wordWrap is set to true, line-breaks are automatically created.\n * @return {gs.RendererTextLine[]} The drawn text lines.\n */\n\n Component_TextRenderer.prototype.drawFormattedText = function(pl, pt, pr, pb, text, wordWrap) {\n var lines;\n lines = this.calculateLines(text.toString(), wordWrap);\n this.drawFormattedLines(pl, pt, pr, pb, lines, wordWrap);\n return lines;\n };\n\n return Component_TextRenderer;\n\n})(gs.Component);\n\ngs.Component_TextRenderer = Component_TextRenderer;\n\n//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQVFBLElBQUEsdURBQUE7RUFBQTs7O0FBQU07O0FBQ0Y7Ozs7Ozs7O0VBUWEsMEJBQUE7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxLQUFELEdBQVM7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxNQUFELEdBQVU7O0FBQ1Y7Ozs7OztJQU1BLElBQUMsQ0FBQSxPQUFELEdBQVc7O0FBQ1g7Ozs7OztJQU1BLElBQUMsQ0FBQSxPQUFELEdBQVc7RUE1QkY7Ozs7OztBQThCakIsRUFBRSxDQUFDLGdCQUFILEdBQXNCOztBQUVoQjs7QUFDRjs7Ozs7Ozs7RUFRYSx1QkFBQyxJQUFELEVBQU8sS0FBUCxFQUFjLElBQWQ7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxLQUFELEdBQVM7O0FBQ1Q7Ozs7OztJQU1BLElBQUMsQ0FBQSxJQUFELEdBQVE7O0FBQ1I7Ozs7O0lBS0EsSUFBQyxDQUFBLE1BQUQsR0FBVTs7QUFDVjs7Ozs7SUFLQSxJQUFDLENBQUEsVUFBRCxHQUFjO0lBRWQsSUFBcUIsWUFBckI7TUFBQSxJQUFDLENBQUEsVUFBRCxDQUFZLElBQVosRUFBQTs7RUE1QlM7OztBQThCYjs7Ozs7Ozs7MEJBT0EsVUFBQSxHQUFZLFNBQUMsSUFBRDtXQUNSLElBQUMsQ0FBQSxNQUFELEdBQVUsSUFBSSxDQUFDLFlBQUwsQ0FBQTtFQURGOzs7QUFHWjs7Ozs7Ozs7MEJBT0EsV0FBQSxHQUFhLFNBQUMsSUFBRDtXQUNULElBQUksQ0FBQyxHQUFMLENBQVMsSUFBQyxDQUFBLE1BQVY7RUFEUzs7Ozs7O0FBR2pCLEVBQUUsQ0FBQyxhQUFILEdBQW1COztBQUViOzs7O0FBQ0Y7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztFQXVCYSxnQ0FBQTtJQUNULHlEQUFBLFNBQUE7O0FBRUE7Ozs7O0lBS0EsSUFBQyxDQUFBLFFBQUQsR0FBWTs7QUFFWjs7Ozs7SUFLQSxJQUFDLENB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QixHQUFtQyxJQUFJLENBQUMsT0FBeEMsR0FBa0QsSUFBSSxDQUFDLE9BQTFGLEVBQW1HLElBQUksQ0FBQyxLQUFMLEdBQVcsRUFBWCxHQUFjLEVBQWpILEVBQXFILE1BQUEsR0FBTyxFQUFQLEdBQVUsRUFBL0gsRUFBbUksS0FBSyxDQUFDLEtBQXpJLEVBQWdKLENBQWhKLEVBQW1KLENBQW5KO1lBQ0EsSUFBQyxDQUFBLFFBQUQsSUFBYSxJQUFJLENBQUMsTUFIdEI7O1VBSUEsSUFBQyxDQUFBLGlCQUFELEdBQXFCLElBQUksQ0FBQyxHQUFMLENBQVMsSUFBQyxDQUFBLGlCQUFWLEVBQTZCLE1BQTdCLEVBUHBCOztBQVBUO01BZUEsSUFBQyxDQUFBLFFBQUQsSUFBYSxDQUFDLElBQUMsQ0FBQSxpQkFBRCxJQUFzQixJQUFDLENBQUEsTUFBTSxDQUFDLElBQUksQ0FBQyxVQUFwQyxDQUFBLEdBQWtELElBQUMsQ0FBQTtNQUNoRSxJQUFDLENBQUEsUUFBRCxHQUFZO01BQ1osSUFBQyxDQUFBLGlCQUFELEdBQXFCO0FBbEJ6QjtBQW9CQSxXQUFPO0VBekJTOzs7QUEyQnBCOzs7Ozs7Ozs7Ozs7Ozs7bUNBY0EsaUJBQUEsR0FBbUIsU0FBQyxFQUFELEVBQUssRUFBTCxFQUFTLEVBQVQsRUFBYSxFQUFiLEVBQWlCLElBQWpCLEVBQXVCLFFBQXZCO0FBQ2YsUUFBQTtJQUFBLEtBQUEsR0FBUSxJQUFDLENBQUEsY0FBRCxDQUFnQixJQUFJLENBQUMsUUFBTCxDQUFBLENBQWhCLEVBQWlDLFFBQWpDO0lBRVIsSUFBQyxDQUFBLGtCQUFELENBQW9CLEVBQXBCLEVBQXdCLEVBQXhCLEVBQTRCLEVBQTVCLEVBQWdDLEVBQWhDLEVBQW9DLEtBQXBDLEVBQTJDLFFBQTNDO0FBRUEsV0FBTztFQUxROzs7O0dBNTJCYyxFQUFFLENBQUM7O0FBbTNCeEMsRUFBRSxDQUFDLHNCQUFILEdBQTRCIiwic291cmNlc0NvbnRlbnQiOlsiIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4jXG4jICAgU2NyaXB0OiBDb21wb25lbnRfVGV4dFJlbmRlcmVyXG4jXG4jICAgJCRDT1BZUklHSFQkJFxuI1xuIyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmNsYXNzIFJlbmRlcmVyVGV4dExpbmVcbiAgICAjIyMqXG4gICAgKiBTdG9yZXMgYSB0ZXh0IGxpbmUuXG4gICAgKiBcbiAgICAqIEBtb2R1bGUgZ3MuUmVuZGVyZXJUZXh0TGluZVxuICAgICogQGNsYXNzIFJlbmRlcmVyVGV4dExpbmVcbiAgICAqIEBtZW1iZXJvZiBncy5SZW5kZXJlclRleHRMaW5lXG4gICAgKiBAY29uc3RydWN0b3JcbiAgICAjIyNcbiAgICBjb25zdHJ1Y3RvcjogLT5cbiAgICAgICAgIyMjXG4gICAgICAgICogVGhlIHdpZHRoIG9mIHRoZSBsaW5lIGluIHBpeGVscy5cbiAgICAgICAgKiBAcHJvcGVydHkgd2lkdGhcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAd2lkdGggPSAwXG4gICAgICAgICMjI1xuICAgICAgICAqIFRoZSBoZWlnaHQgb2YgdGhlIGxpbmUgaW4gcGl4ZWxzLlxuICAgICAgICAqIEBwcm9wZXJ0eSB3aWR0aFxuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgICAgIyMjXG4gICAgICAgIEBoZWlnaHQgPSAwXG4gICAgICAgICMjI1xuICAgICAgICAqIFRoZSBkZXNjZW50IG9mIHRoZSBsaW5lIGluIHBpeGVscy5cbiAgICAgICAgKiBAcHJvcGVydHkgZGVzY2VudFxuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgICAgIyMjXG4gICAgICAgIEBkZXNjZW50ID0gMFxuICAgICAgICAjIyNcbiAgICAgICAgKiBUaGUgY29udGVudCBvZiB0aGUgbGluZSBhcyB0b2tlbiBvYmplY3RzLlxuICAgICAgICAqIEBwcm9wZXJ0eSBjb250ZW50XG4gICAgICAgICogQHR5cGUgT2JqZWN0W11cbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAY29udGVudCA9IFtdXG4gICAgICAgIFxuZ3MuUmVuZGVyZXJUZXh0TGluZSA9IFJlbmRlcmVyVGV4dExpbmVcblxuY2xhc3MgUmVuZGVyZXJUb2tlblxuICAgICMjIypcbiAgICAqIFN0b3JlcyBhIHRva2VuLlxuICAgICogXG4gICAgKiBAbW9kdWxlIGdzXG4gICAgKiBAY2xhc3MgUmVuZGVyZXJUb2tlblxuICAgICogQG1lbWJlcm9mIGdzXG4gICAgKiBAY29uc3RydWN0b3JcbiAgICAjIyNcbiAgICBjb25zdHJ1Y3RvcjogKGNvZGUsIHZhbHVlLCBmb250KSAtPlxuICAgICAgICAjIyNcbiAgICAgICAgKiBUaGUgdmFsdWUgb2YgdGhlIHRva2VuLiBUaGF0IHZhbHVlIGRlcGVuZHMgb24gdGhlIHRva2VuIHR5cGUuIEZvciB0ZXh0LXRva2VucywgaXQgc3RvcmVzXG4gICAgICAgICogdGhlIGFjdHVhbCB0ZXh0LlxuICAgICAgICAqIEBwcm9wZXJ0eSBjb250ZW50XG4gICAgICAgICogQHR5cGUgc3RyaW5nXG4gICAgICAgICMjI1xuICAgICAgICBAdmFsdWUgPSB2YWx1ZVxuICAgICAgICAjIyNcbiAgICAgICAgKiBUaGUgY29kZSBkZXNjcmliZXMgd2hhdCBraW5kIG9mIHRva2VuIGl0IGlzLiBGb3IgZXhhbXBsZSwgaWYgdGhlIGNvZGUgaXMgXCJZXCIgaXQgbWVhbnMgaXQgaXMgYVxuICAgICAgICAqIHN0eWxlLXRva2VuLiBJZiB0aGUgY29kZSBpcyA8Yj5udWxsPC9iPiwgaXQgbWVhbnMgaXQgaXMgYSB0ZXh0LXRva2VuLlxuICAgICAgICAqIEBwcm9wZXJ0eSBjb2RlXG4gICAgICAgICogQHR5cGUgc3RyaW5nXG4gICAgICAgICMjI1xuICAgICAgICBAY29kZSA9IGNvZGVcbiAgICAgICAgIyMjXG4gICAgICAgICogVGhlIGZvcm1hdCBzdG9yZXMgdGhlIGZvbnQtc3R5bGUgcHJvcGVydGllcyBvZiB0aGUgdG9rZW4gbGlrZSBpZiBpdCBpcyBpdGFsaWMsIGJvbGQsIGV0Yy4gSXQgY2FuIGJlIDxiPm51bGw8L2I+LlxuICAgICAgICAqIEBwcm9wZXJ0eSBmb3JtYXRcbiAgICAgICAgKiBAdHlwZSBPYmplY3RcbiAgICAgICAgIyMjXG4gICAgICAgIEBmb3JtYXQgPSBudWxsXG4gICAgICAgICMjI1xuICAgICAgICAqIEEgcGxhaW4gb2JqZWN0IHRvIHN0b3JlIGN1c3RvbSBkYXRhIHdpdGhpbiB0aGUgdG9rZW4uXG4gICAgICAgICogQHByb3BlcnR5IGN1c3RvbURhdGFcbiAgICAgICAgKiBAdHlwZSBPYmplY3RcbiAgICAgICAgIyMjXG4gICAgICAgIEBjdXN0b21EYXRhID0ge31cbiAgICAgICAgXG4gICAgICAgIEB0YWtlRm9ybWF0KGZvbnQpIGlmIGZvbnQ/XG4gICAgICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBUYWtlcyB0aGUgc3R5bGUgZnJvbSB0aGUgc3BlY2lmaWVkIGZvbnQgYW5kIHN0b3JlcyBpdCBpbnRvIHRoZSBmb3JtYXQtcHJvcGVydHkuIFRoZSB0b2tlbiB3aWxsXG4gICAgKiB3aWxsIGJlIHJlbmRlcmVkIHdpdGggdGhhdCBzdHlsZSB0aGVuLlxuICAgICogXG4gICAgKiBAbWV0aG9kIHRha2VGb3JtYXRcbiAgICAqIEBwYXJhbSB7Z3MuRm9udH0gZm9udCAtIFRoZSBmb250IHRvIHRha2UgdGhlIHN0eWxlIGZyb20uXG4gICAgIyMjXG4gICAgdGFrZUZvcm1hdDogKGZvbnQpIC0+XG4gICAgICAgIEBmb3JtYXQgPSBmb250LnRvRGF0YUJ1bmRsZSgpXG4gICAgXG4gICAgIyMjKlxuICAgICogQXBwbGllcyB0aGUgZm9ybWF0LXN0eWxlIG9mIHRoZSB0b2tlbiBvbiB0aGUgc3BlY2lmaWVkIGZvbnQuIFRoZSBmb250IHdpbGwgaGF2ZSB0aGUgc3R5bGUgZnJvbVxuICAgICogdGhlbiB0b2tlbiB0aGVuLlxuICAgICogXG4gICAgKiBAbWV0aG9kIGFwcGx5Rm9ybWF0XG4gICAgKiBAcGFyYW0ge2dzLkZvbnR9IGZvbnQgLSBUaGUgZm9udCB0byBhcHBseSB0aGUgZm9ybWF0LXN0eWxlIG9uLlxuICAgICMjIyAgICBcbiAgICBhcHBseUZvcm1hdDogKGZvbnQpIC0+XG4gICAgICAgIGZvbnQuc2V0KEBmb3JtYXQpXG4gICAgICAgIFxuZ3MuUmVuZGVyZXJUb2tlbiA9IFJlbmRlcmVyVG9rZW5cblxuY2xhc3MgQ29tcG9uZW50X1RleHRSZW5kZXJlciBleHRlbmRzIGdzLkNvbXBvbmVudFxuICAgICMjIypcbiAgICAqIEEgdGV4dC1yZW5kZXJlciBjb21wb25lbnQgYWxsb3cgdG8gZHJhdyBwbGFpbiBvciBmb3JtYXR0ZWQgdGV4dCBvbiBhXG4gICAgKiBnYW1lIG9iamVjdCdzIGJpdG1hcC4gRm9yIGZvcm1hdHRlZCB0ZXh0LCBkaWZmZXJlbnQgdGV4dC1jb2RlcyBjYW4gYmVcbiAgICAqIHVzZWQgdG8gYWRkIGZvcm1hdHRpbmcgb3IgZGVmaW5lIGEgcGxhY2Vob2xkZXIuPGJyPjxicj5cbiAgICAqIFxuICAgICogQSB0ZXh0LWNvZGUgdXNlcyB0aGUgZm9sbG93aW5nIHN5bnRheDo8YnI+PGJyPlxuICAgICogXG4gICAgKiB7Y29kZTp2YWx1ZX0gPC0gU2luZ2xlIFZhbHVlPGJyIC8+XG4gICAgKiB7Y29kZTp2YWx1ZTEsdmFsdWUyLC4uLn0gPC0gTXVsdGlwbGUgVmFsdWVzPGJyPjxicj5cbiAgICAqIFxuICAgICogRXhhbXBsZTo8YnI+PGJyPlxuICAgICogXG4gICAgKiBcIlRoaXMgaXMge1k6SX1hIFRleHR7WTpOfVwiIDwtIFwiYSBUZXh0XCIgd2lsbCBiZSBpdGFsaWMgaGVyZS48YnI+XG4gICAgKiBcIlRoZSB2YWx1ZSBpcyB7R046MX1cIiA8LSBcIntHTjoxfVwiIHdpbGwgYmUgcmVwbGFjZWQgZm9yIHRoZSB2YWx1ZSBvZiB0aGUgZ2xvYmFsIG51bWJlciB2YXJpYWJsZSAwMDAxLjxicj48YnI+XG4gICAgKiBcbiAgICAqIEZvciBhIGxpc3Qgb2YgYWxsIGF2YWlsYWJsZSB0ZXh0LWNvZGVzIHdpdGggZXhhbXBsZXMsIGp1c3QgdGFrZSBhIGxvb2sgaW50byB0aGUgb2ZmaWNhbCBoZWxwLWZpbGUuXG4gICAgKiBcbiAgICAqIEBtb2R1bGUgZ3NcbiAgICAqIEBjbGFzcyBDb21wb25lbnRfVGV4dFJlbmRlcmVyXG4gICAgKiBAZXh0ZW5kcyBncy5Db21wb25lbnRcbiAgICAqIEBtZW1iZXJvZiBnc1xuICAgICogQGNvbnN0cnVjdG9yXG4gICAgIyMjXG4gICAgY29uc3RydWN0b3I6IC0+XG4gICAgICAgIHN1cGVyXG4gICAgICAgIFxuICAgICAgICAjIyMqXG4gICAgICAgICogQHByb3BlcnR5IGN1cnJlbnRYXG4gICAgICAgICogQHR5cGUgbnVtYmVyXG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQGN1cnJlbnRYID0gMFxuICAgICAgICBcbiAgICAgICAgIyMjKlxuICAgICAgICAqIEBwcm9wZXJ0eSBjdXJyZW50WVxuICAgICAgICAqIEB0eXBlIG51bWJlclxuICAgICAgICAqIEBwcm90ZWN0ZWRcbiAgICAgICAgIyMjXG4gICAgICAgIEBjdXJyZW50WSA9IDBcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBAcHJvcGVydHkgY3VycmVudExpbmVIZWlnaHRcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAY3VycmVudExpbmVIZWlnaHQgPSAwXG4gICAgICAgIFxuICAgICAgICAjIyMqXG4gICAgICAgICogQHByb3BlcnR5IGZvbnRcbiAgICAgICAgKiBAdHlwZSBncy5Gb250XG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQGZvbnQgPSBuZXcgRm9udChcIlRpbWVzIE5ldyBSb21hblwiLCAyMilcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBAcHJvcGVydHkgc3BhY2VTaXplXG4gICAgICAgICogQHR5cGUgbnVtYmVyXG4gICAgICAgICogQHByb3RlY3RlZFxuICAgICAgICAjIyNcbiAgICAgICAgQHNwYWNlU2l6ZSA9IDBcbiAgICAgICAgXG4gICAgICAgICMjIypcbiAgICAgICAgKiBAcHJvcGVydHkgZm9udFNpemVcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgKiBAcHJvdGVjdGVkXG4gICAgICAgICMjI1xuICAgICAgICBAZm9udFNpemUgPSAwXG4gICAgICAgIFxuICAgICAgICAjIyMqXG4gICAgICAgICogVGhlIGxlZnQgYW5kIHJpZ2h0IHBhZGRpbmcgcGVyIGxpbmUuXG4gICAgICAgICogQHByb3BlcnR5IHBhZGRpbmdcbiAgICAgICAgKiBAdHlwZSBudW1iZXJcbiAgICAgICAgIyMjXG4gICAgICAgIEBwYWRkaW5nID0gMFxuICAgICAgICBcbiAgICAgICAgIyMjKlxuICAgICAgICAqIFRoZSBzcGFjaW5nIGJldHdlZW4gdGV4dCBsaW5lcyBpbiBwaXhlbHMuXG4gICAgICAgICogQHByb3BlcnR5IGxpbmVTcGFjaW5nXG4gICAgICAgICogQHR5cGUgbnVtYmVyXG4gICAgICAgICMjI1xuICAgICAgICBAbGluZVNwYWNpbmcgPSAwXG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIENyZWF0ZXMgdGhlIHRva2VuLW9iamVjdCBmb3IgYSBsaXN0LXBsYWNlaG9sZGVyLiBBIGxpc3QtcGxhY2Vob2xkZXJcbiAgICAqIGFsbG93cyB0byBpbnNlcnQgYSB2YWx1ZSBmcm9tIGEgbGlzdC12YXJpYWJsZS5cbiAgICAqIFxuICAgICogQG1ldGhvZCBjcmVhdGVMaXN0VG9rZW5cbiAgICAqIEBwYXJhbSB7QXJyYXl9IGxpc3QgLSBUaGUgbGlzdC5cbiAgICAqIEBwYXJhbSB7QXJyYXl9IHZhbHVlcyAtIFRoZSB2YWx1ZXMgb2YgdGhlIGxpc3QtcGxhY2Vob2xkZXIgdGV4dC1jb2RlLlxuICAgICogQHJldHVybiB7c3RyaW5nfSBUaGUgdG9rZW4tb2JqZWN0LlxuICAgICMjI1xuICAgIGNyZWF0ZUxpc3RUb2tlbjogKGxpc3QsIHZhbHVlcykgLT5cbiAgICAgICAgaW5kZXggPSAwXG4gICAgICAgIGlmIHZhbHVlc1sxXT9cbiAgICAgICAgICAgIHZhbHVlcyA9IHZhbHVlc1sxXS5zcGxpdChcIjpcIilcbiAgICAgICAgICAgIGluZGV4ID0gdmFsdWVzWzBdXG4gICAgICAgICAgICBpZiB2YWx1ZXNbMF0gPT0gXCJHXCJcbiAgICAgICAgICAgICAgICBpbmRleCA9IEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubnVtYmVyc1twYXJzZUludCh2YWx1ZXNbMV0pLTFdXG4gICAgICAgICAgICBlbHNlIGlmIHZhbHVlc1swXSA9PSBcIlBcIlxuICAgICAgICAgICAgICAgIGluZGV4ID0gR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5wZXJzaXN0ZW50TnVtYmVyc1twYXJzZUludCh2YWx1ZXNbMV0pLTFdXG4gICAgICAgICAgICBlbHNlIGlmIHZhbHVlc1swXSA9PSBcIkxcIlxuICAgICAgICAgICAgICAgIGluZGV4ID0gR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5udW1iZXJWYWx1ZU9mKHsgc2NvcGU6IDAsIGluZGV4OiBwYXJzZUludCh2YWx1ZXNbMV0pLTF9KVxuICAgICAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gXCJcIiArIGxpc3RbaW5kZXhdXG4gICAgICAgXG4gICAgICBcbiAgICAjIyMqXG4gICAgKiBQYXJzZXMgYW5kIHJldHVybnMgdGhlIHZhcmlhYmxlIGlkZW50aWZpZXIgd2hpY2ggaXMgYW4gYXJyYXkgY29udGFpbmluZ1xuICAgICogdGhlIG9wdGlvbmFsIGRvbWFpbiBuYW1lIGFuZCB0aGUgdmFyaWFibGUgaW5kZXggYXM6IFtkb21haW4sIGluZGV4XS5cbiAgICAqIFxuICAgICogQG1ldGhvZCBwYXJzZVZhcmlhYmxlSWRlbnRpZmllclxuICAgICogQHBhcmFtIHtzdHJpbmd9IGlkZW50aWZpZXIgLSBUaGUgdmFyaWFibGUgaWRlbnRpZmllciBlLmcuIGNvbS5kZWdpY2Eudm5tLmRlZmF1bHQuMSBvciBjb20uZGVnaWNhLnZubS5kZWZhdWx0LlZhck5hbWVcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIHZhcmlhYmxlIHR5cGUgdG8gcGFyc2U6IG51bWJlciwgc3RyaW5nLCBib29sZWFuIG9yIGxpc3RcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0eXBlIC0gVGhlIHNjb3BlIG9mIHRoZSB2YXJpYWJsZSB0byBwYXJzZTogMCA9IGxvY2FsLCAxID0gZ2xvYmFsLCAyID0gcGVyc2lzdGVudC5cbiAgICAqIEByZXR1cm4ge0FycmF5fSBBbiBhcnJheSBjb250YWluaW5nIHR3byB2YWx1ZXMgYXM6IFtkb21haW4sIGluZGV4XS4gSWYgdGhlIGlkZW50aWZpZXIgZG9lc24ndCBjb250YWluIGEgZG9tYWluLXN0cmluZywgdGhlIGRvbWFpbiB3aWxsIGJlIDAgKGRlZmF1bHQpLlxuICAgICMjIyBcbiAgICBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcjogKGlkZW50aWZpZXIsIHR5cGUsIHNjb3BlKSAtPlxuICAgICAgICByZXN1bHQgPSBbMCwgaWRlbnRpZmllcl1cbiAgICAgICAgXG4gICAgICAgIGlmIGlzTmFOKGlkZW50aWZpZXIpXG4gICAgICAgICAgICBpbmRleCA9IGlkZW50aWZpZXIubGFzdEluZGV4T2YoXCIuXCIpXG4gICAgICAgICAgICBpZiBpbmRleCAhPSAtMVxuICAgICAgICAgICAgICAgIHJlc3VsdFswXSA9IGlkZW50aWZpZXIuc3Vic3RyaW5nKDAsIGluZGV4KVxuICAgICAgICAgICAgICAgIHJlc3VsdFsxXSA9IGlkZW50aWZpZXIuc3Vic3RyaW5nKGluZGV4KzEpXG4gICAgICAgICAgICAgICAgaWYgaXNOYU4ocmVzdWx0WzFdKVxuICAgICAgICAgICAgICAgICAgICByZXN1bHRbMV0gPSBHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLmluZGV4T2ZWYXJpYWJsZShyZXN1bHRbMV0sIHR5cGUsIHNjb3BlLCByZXN1bHRbMF0pICsgMVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0WzFdID0gcGFyc2VJbnQocmVzdWx0WzFdKVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHJlc3VsdFsxXSA9IEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUuaW5kZXhPZlZhcmlhYmxlKHJlc3VsdFsxXSwgdHlwZSwgc2NvcGUsIHJlc3VsdFswXSkgKyAxXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHJlc3VsdFsxXSA9IHBhcnNlSW50KHJlc3VsdFsxXSlcbiAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gcmVzdWx0XG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIENyZWF0ZXMgYSB0b2tlbi1vYmplY3QgZm9yIGEgc3BlY2lmaWVkIHRleHQtY29kZS5cbiAgICAqIFxuICAgICogQG1ldGhvZCBjcmVhdGVUb2tlblxuICAgICogQHBhcmFtIHtzdHJpbmd9IGNvZGUgLSBUaGUgY29kZS90eXBlIG9mIHRoZSB0ZXh0LWNvZGUuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gdmFsdWUgLSBUaGUgdmFsdWUgb2YgdGhlIHRleHQtY29kZS5cbiAgICAqIEByZXR1cm4ge09iamVjdH0gVGhlIHRva2VuLW9iamVjdC5cbiAgICAjIyNcbiAgICBjcmVhdGVUb2tlbjogKGNvZGUsIHZhbHVlKSAtPlxuICAgICAgICB0b2tlbk9iamVjdCA9IG51bGxcbiAgICAgICAgdmFsdWUgPSBpZiBpc05hTih2YWx1ZSkgdGhlbiB2YWx1ZSBlbHNlIHBhcnNlSW50KHZhbHVlKVxuICAgICAgICBzd2l0Y2ggY29kZVxuICAgICAgICAgICAgd2hlbiBcIlNaXCIgXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBuZXcgZ3MuUmVuZGVyZXJUb2tlbihjb2RlLCB2YWx1ZSlcbiAgICAgICAgICAgICAgICBAZm9udC5zaXplID0gdG9rZW5PYmplY3QudmFsdWUgfHwgQGZvbnRTaXplXG4gICAgICAgICAgICAgICAgQHNwYWNlU2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4oXCIgXCIpXG4gICAgICAgICAgICB3aGVuIFwiWVwiXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB7IGNvZGU6IGNvZGUsIHZhbHVlOiB2YWx1ZSB9XG4gICAgICAgICAgICAgICAgc3dpdGNoIHZhbHVlXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJVXCIgdGhlbiBAZm9udC51bmRlcmxpbmUgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIlNcIiB0aGVuIEBmb250LnN0cmlrZVRocm91Z2ggPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIklcIiB0aGVuIEBmb250Lml0YWxpYyA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiQlwiIHRoZW4gQGZvbnQuYm9sZCA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiQ1wiIHRoZW4gQGZvbnQuc21hbGxDYXBzID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOVVwiIHRoZW4gQGZvbnQudW5kZXJsaW5lID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5TXCIgdGhlbiBAZm9udC5zdHJpa2VUaHJvdWdoID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5JXCIgdGhlbiBAZm9udC5pdGFsaWMgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTkJcIiB0aGVuIEBmb250LmJvbGQgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTkNcIiB0aGVuIEBmb250LnNtYWxsQ2FwcyA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOXCJcbiAgICAgICAgICAgICAgICAgICAgICAgIEBmb250LnVuZGVybGluZSA9IG5vXG4gICAgICAgICAgICAgICAgICAgICAgICBAZm9udC5zdHJpa2VUaHJvdWdoID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBmb250Lml0YWxpYyA9IG5vXG4gICAgICAgICAgICAgICAgICAgICAgICBAZm9udC5ib2xkID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBmb250LnNtYWxsQ2FwcyA9IG5vXG4gICAgICAgICAgICAgICAgQHNwYWNlU2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4oXCIgXCIpXG4gICAgICAgICAgICB3aGVuIFwiQ1wiXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBuZXcgZ3MuUmVuZGVyZXJUb2tlbihjb2RlLCB2YWx1ZSlcbiAgICAgICAgICAgICAgICBpZiB2YWx1ZSA8PSAwXG4gICAgICAgICAgICAgICAgICAgIEBmb250LmNvbG9yID0gRm9udC5kZWZhdWx0Q29sb3JcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIEBmb250LmNvbG9yID0gZ3MuQ29sb3IuZnJvbU9iamVjdChSZWNvcmRNYW5hZ2VyLnN5c3RlbS5jb2xvcnNbdmFsdWUtMV0gfHwgRm9udC5kZWZhdWx0Q29sb3IpXG4gICAgICAgICAgICB3aGVuIFwiR05cIlxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IGlmIGlzTmFOKHZhbHVlKSB0aGVuIHZhbHVlLnNwbGl0KFwiLFwiKSBlbHNlIFt2YWx1ZV1cbiAgICAgICAgICAgICAgICBpZiB2YWx1ZXNbMV1cbiAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gdmFsdWVzWzFdXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibnVtYmVyXCIsIDEpXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gc3ByaW50ZihcIiVcIitmb3JtYXQrXCJkXCIsIChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLm51bWJlcnNCeURvbWFpblt2YWx1ZXNbMF18fDBdW3ZhbHVlc1sxXS0xXSB8fCAwKSlcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibnVtYmVyXCIsIDEpXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubnVtYmVyc0J5RG9tYWluW3ZhbHVlc1swXXx8MF1bdmFsdWVzWzFdLTFdIHx8IDApLnRvU3RyaW5nKClcbiAgICAgICAgICAgIHdoZW4gXCJHVFwiIFxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZSwgXCJzdHJpbmdcIiwgMSlcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnN0cmluZ3NCeURvbWFpblt2YWx1ZXNbMF18fDBdW3ZhbHVlc1sxXS0xXSB8fCBcIlwiKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gdG9rZW5PYmplY3Quc3BsaXQoL1xceyhbQS16XSspOihbXlxce1xcfV0rKVxcfXwoXFxuKS9nbSlcbiAgICAgICAgICAgICAgICBpZiB0b2tlbk9iamVjdC5sZW5ndGggPiAxXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0LnBvcCgpXG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHRva2VuT2JqZWN0WzBdID8gXCJcIlxuICAgICAgICAgICAgd2hlbiBcIkdTXCJcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWUsIFwiYm9vbGVhblwiLCAxKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUuYm9vbGVhbnNCeURvbWFpblt2YWx1ZXNbMF18fDBdW3ZhbHVlc1sxXS0xXSB8fCBmYWxzZSkudG9TdHJpbmcoKVxuICAgICAgICAgICAgd2hlbiBcIkdMXCJcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSB2YWx1ZS5zcGxpdChcIixcIilcbiAgICAgICAgICAgICAgICBsaXN0SWRlbnRpZmllciA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibGlzdFwiLCAxKVxuICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gQGNyZWF0ZUxpc3RUb2tlbihHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLmxpc3RzQnlEb21haW5bbGlzdElkZW50aWZpZXJbMF1dW2xpc3RJZGVudGlmaWVyWzFdLTFdIHx8IFtdLCB2YWx1ZXMpXG4gICAgICAgICAgICB3aGVuIFwiUE5cIlxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IGlmIGlzTmFOKHZhbHVlKSB0aGVuIHZhbHVlLnNwbGl0KFwiLFwiKSBlbHNlIFt2YWx1ZV1cbiAgICAgICAgICAgICAgICBpZiB2YWx1ZXNbMV1cbiAgICAgICAgICAgICAgICAgICAgZm9ybWF0ID0gdmFsdWVzWzFdXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibnVtYmVyXCIsIDIpXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gc3ByaW50ZihcIiVcIitmb3JtYXQrXCJkXCIsIChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnROdW1iZXJzW3ZhbHVlc1swXV0/W3ZhbHVlc1sxXS0xXSB8fCAwKSlcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibnVtYmVyXCIsIDIpXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUucGVyc2lzdGVudE51bWJlcnNCeURvbWFpblt2YWx1ZXNbMF18fDBdP1t2YWx1ZXNbMV0tMV0gfHwgMCkudG9TdHJpbmcoKVxuICAgICAgICAgICAgd2hlbiBcIlBUXCIgIFxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZSwgXCJzdHJpbmdcIiwgMilcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLnBlcnNpc3RlbnRTdHJpbmdzQnlEb21haW5bdmFsdWVzWzBdXT9bdmFsdWVzWzFdLTFdIHx8IFwiXCIpXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB0b2tlbk9iamVjdC5zcGxpdCgvXFx7KFtBLXpdKyk6KFteXFx7XFx9XSspXFx9fChcXG4pL2dtKVxuICAgICAgICAgICAgICAgIGlmIHRva2VuT2JqZWN0Lmxlbmd0aCA+IDFcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QucG9wKClcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gdG9rZW5PYmplY3RbMF0gPyBcIlwiXG4gICAgICAgICAgICB3aGVuIFwiUFNcIlxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZSwgXCJib29sZWFuXCIsIDIpXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5wZXJzaXN0ZW50Qm9vbGVhbnNCeURvbWFpblt2YWx1ZXNbMF1dP1t2YWx1ZXNbMV0tMV0gfHwgZmFsc2UpLnRvU3RyaW5nKClcbiAgICAgICAgICAgIHdoZW4gXCJQTFwiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gdmFsdWUuc3BsaXQoXCIsXCIpXG4gICAgICAgICAgICAgICAgbGlzdElkZW50aWZpZXIgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWVzWzBdLCBcImxpc3RcIiwgMilcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IEBjcmVhdGVMaXN0VG9rZW4oR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5wZXJzaXN0ZW50TGlzdHNCeURvbWFpbltsaXN0SWRlbnRpZmllclswXV0/W2xpc3RJZGVudGlmaWVyWzFdLTFdIHx8IFtdLCB2YWx1ZXMpXG4gICAgICAgICAgICB3aGVuIFwiTE5cIiBcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSBpZiBpc05hTih2YWx1ZSkgdGhlbiB2YWx1ZS5zcGxpdChcIixcIikgZWxzZSBbdmFsdWVdXG4gICAgICAgICAgICAgICAgaWYgdmFsdWVzWzFdIFxuICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSB2YWx1ZXNbMV1cbiAgICAgICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJudW1iZXJcIiwgMClcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBzcHJpbnRmKFwiJVwiK2Zvcm1hdCtcImRcIiwgKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubnVtYmVyVmFsdWVPZih7IHNjb3BlOiAwLCBpbmRleDogdmFsdWVzWzFdLTF9KSB8fCAwKSlcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHZhbHVlcyA9IEBwYXJzZVZhcmlhYmxlSWRlbnRpZmllcih2YWx1ZXNbMF0sIFwibnVtYmVyXCIsIDApXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubnVtYmVyVmFsdWVPZih7IHNjb3BlOiAwLCBpbmRleDogdmFsdWVzWzFdLTF9KSB8fCAwKS50b1N0cmluZygpXG4gICAgICAgICAgICB3aGVuIFwiTFRcIiBcbiAgICAgICAgICAgICAgICB2YWx1ZXMgPSBAcGFyc2VWYXJpYWJsZUlkZW50aWZpZXIodmFsdWUsIFwic3RyaW5nXCIsIDApXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoR2FtZU1hbmFnZXIudmFyaWFibGVTdG9yZS5zdHJpbmdWYWx1ZU9mKHsgc2NvcGU6IDAsIGluZGV4OiB2YWx1ZXNbMV0tMX0pIHx8IFwiXCIpLnRvU3RyaW5nKClcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHRva2VuT2JqZWN0LnNwbGl0KC9cXHsoW0Etel0rKTooW15cXHtcXH1dKylcXH18KFxcbikvZ20pXG4gICAgICAgICAgICAgICAgaWYgdG9rZW5PYmplY3QubGVuZ3RoID4gMVxuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdC5wb3AoKVxuICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB0b2tlbk9iamVjdFswXSA/IFwiXCJcbiAgICAgICAgICAgIHdoZW4gXCJMU1wiXG4gICAgICAgICAgICAgICAgdmFsdWVzID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlLCBcImJvb2xlYW5cIiwgMClcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IChHYW1lTWFuYWdlci52YXJpYWJsZVN0b3JlLmJvb2xlYW5WYWx1ZU9mKHsgc2NvcGU6IDAsIGluZGV4OiB2YWx1ZXNbMV0tMX0pIHx8IGZhbHNlKS50b1N0cmluZygpXG4gICAgICAgICAgICB3aGVuIFwiTExcIlxuICAgICAgICAgICAgICAgIHZhbHVlcyA9IHZhbHVlLnNwbGl0KFwiLFwiKVxuICAgICAgICAgICAgICAgIGxpc3RJZGVudGlmaWVyID0gQHBhcnNlVmFyaWFibGVJZGVudGlmaWVyKHZhbHVlc1swXSwgXCJsaXN0XCIsIDApXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBAY3JlYXRlTGlzdFRva2VuKEdhbWVNYW5hZ2VyLnZhcmlhYmxlU3RvcmUubGlzdE9iamVjdE9mKHsgc2NvcGU6IDAsIGluZGV4OiBsaXN0SWRlbnRpZmllclsxXS0xfSkgfHwgW10sIHZhbHVlcylcbiAgICAgICAgICAgIHdoZW4gXCJOXCIgXG4gICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSAoaWYgUmVjb3JkTWFuYWdlci5jaGFyYWN0ZXJzW3ZhbHVlXT8gdGhlbiBsY3MoUmVjb3JkTWFuYWdlci5jaGFyYWN0ZXJzW3ZhbHVlXS5uYW1lKSBlbHNlIFwiXCIpXG4gICAgICAgICAgICB3aGVuIFwiUlRcIlxuICAgICAgICAgICAgICAgIHBhaXIgPSB2YWx1ZS5zcGxpdChcIi9cIilcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IHsgY29kZTogY29kZSwgcnRTdHlsZUlkOiBwYWlyWzJdID8gMCwgcmI6IHBhaXJbMF0sIHJ0OiBwYWlyWzFdLCByYlNpemU6IHsgd2lkdGg6IDAsIGhlaWdodDogMCB9LCBydFNpemU6IHsgd2lkdGg6IDAsIGhlaWdodDogMCB9IH1cbiAgICAgICAgICAgIHdoZW4gXCJNXCJcbiAgICAgICAgICAgICAgICBtYWNybyA9IFJlY29yZE1hbmFnZXIuc3lzdGVtLnRleHRNYWNyb3MuZmlyc3QgKG0pIC0+IG0ubmFtZSA9PSB2YWx1ZVxuICAgICAgICAgICAgICAgIGlmIG1hY3JvXG4gICAgICAgICAgICAgICAgICAgIGlmIG1hY3JvLnR5cGUgPT0gMCAjIFRleHQgKyBDb2Rlc1xuICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSBtYWNyby5jb250ZW50LnNwbGl0KC9cXHsoW0Etel0rKTooW15cXHtcXH1dKylcXH18KFxcbikvZ20pXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdC5wb3AoKVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIG1hY3JvLnR5cGUgPT0gMSAjIFBsYWNlaG9sZGVyIFNjcmlwdCBNYWNyb1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgIW1hY3JvLmNvbnRlbnRGdW5jXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbWFjcm8uY29udGVudEZ1bmMgPSBldmFsKFwiKGZ1bmN0aW9uKG9iamVjdCwgdmFsdWUpeyAje21hY3JvLmNvbnRlbnR9IH0pXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG1hY3JvLmNvbnRlbnRGdW5jKEBvYmplY3QsIHZhbHVlKVxuICAgICAgICAgICAgICAgICAgICAgICAgdG9rZW5PYmplY3QgPSB0b2tlbk9iamVjdC5zcGxpdCgvXFx7KFtBLXpdKyk6KFteXFx7XFx9XSspXFx9fChcXG4pL2dtKVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgdG9rZW5PYmplY3QubGVuZ3RoID4gMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0LnBvcCgpXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgIyBTY3JpcHQgTWFjcm9cbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICFtYWNyby5jb250ZW50RnVuY1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1hY3JvLmNvbnRlbnRGdW5jID0gZXZhbChcIihmdW5jdGlvbihvYmplY3QpeyAje21hY3JvLmNvbnRlbnR9IH0pXCIpXG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG5ldyBncy5SZW5kZXJlclRva2VuKFwiWFwiLCBtYWNyby5jb250ZW50RnVuYylcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIHRva2VuT2JqZWN0ID0gXCJcIlxuICAgICAgICAgICAgZWxzZSAgICBcbiAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IG5ldyBncy5SZW5kZXJlclRva2VuKGNvZGUsIHZhbHVlKVxuICAgICAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gdG9rZW5PYmplY3RcbiAgICBcbiAgICBcbiAgICAjIyMqXG4gICAgKiA8cD5HZXRzIHRoZSBjb3JyZWN0IGZvbnQgZm9yIHRoZSBzcGVjaWZpZWQgcnVieS10ZXh0IHRva2VuLjwvcD4gXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gQSBydWJ5LXRleHQgdG9rZW4uXG4gICAgKiBAcmV0dXJuIHtncy5Gb250fSBUaGUgZm9udCBmb3IgdGhlIHJ1YnktdGV4dCB3aGljaCBpcyBzaG93biBhYm92ZSB0aGUgb3JpZ2luYWwgdGV4dC5cbiAgICAqIEBtZXRob2QgZ2V0UnVieVRleHRGb250XG4gICAgIyMjICAgXG4gICAgZ2V0UnVieVRleHRGb250OiAodG9rZW4pIC0+XG4gICAgICAgIHN0eWxlID0gbnVsbFxuICAgICAgICBmb250ID0gbnVsbFxuICAgICAgICAgICAgICAgIFxuICAgICAgICBpZiB0b2tlbi5ydFN0eWxlSWRcbiAgICAgICAgICAgIHN0eWxlID0gdWkuVUlNYW5hZ2VyLnN0eWxlc1tcInJ1YnlUZXh0LVwiK3Rva2VuLnJ0U3R5bGVJZF1cbiAgICAgICAgXG4gICAgICAgIGlmICFzdHlsZVxuICAgICAgICAgICAgc3R5bGUgPSB1aS5VSU1hbmFnZXIuc3R5bGVzW1wicnVieVRleHRcIl1cbiAgICAgICAgICAgIFxuICAgICAgICBmb250ID0gc3R5bGU/LmZvbnQgPyBAZm9udFxuICAgICAgICBmb250LnNpemUgPSBmb250LnNpemUgfHwgQGZvbnQuc2l6ZSAvIDJcbiAgICAgICAgXG4gICAgICAgIHJldHVybiBmb250XG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIDxwPk1lYXN1cmVzIGEgY29udHJvbC10b2tlbi4gSWYgYSB0b2tlbiBwcm9kdWNlcyBhIHZpc3VhbCByZXN1bHQgbGlrZSBkaXNwbGF5aW5nIGFuIGljb24gdGhlbiBpdCBtdXN0IHJldHVybiB0aGUgc2l6ZSB0YWtlbiBieVxuICAgICogdGhlIHZpc3VhbCByZXN1bHQuIElmIHRoZSB0b2tlbiBoYXMgbm8gdmlzdWFsIHJlc3VsdCwgPGI+bnVsbDwvYj4gbXVzdCBiZSByZXR1cm5lZC4gVGhpcyBtZXRob2QgaXMgY2FsbGVkIGZvciBldmVyeSB0b2tlbiB3aGVuIHRoZSBtZXNzYWdlIGlzIGluaXRpYWxpemVkLjwvcD4gXG4gICAgKlxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gQSBjb250cm9sLXRva2VuLlxuICAgICogQHJldHVybiB7Z3MuU2l6ZX0gVGhlIHNpemUgb2YgdGhlIGFyZWEgdGFrZW4gYnkgdGhlIHZpc3VhbCByZXN1bHQgb2YgdGhlIHRva2VuIG9yIDxiPm51bGw8L2I+IGlmIHRoZSB0b2tlbiBoYXMgbm8gdmlzdWFsIHJlc3VsdC5cbiAgICAqIEBtZXRob2QgbWVhc3VyZUNvbnRyb2xUb2tlblxuICAgICogQHByb3RlY3RlZFxuICAgICMjIyAgIFxuICAgIG1lYXN1cmVDb250cm9sVG9rZW46ICh0b2tlbikgLT4gIyBDYW4gYmUgaW1wbGVtZW50ZWQgYnkgZGVyaXZlZCBjbGFzc2VzXG4gICAgICAgIHNpemUgPSBudWxsXG4gICAgICAgIFxuICAgICAgICBzd2l0Y2ggdG9rZW4uY29kZVxuICAgICAgICAgICAgd2hlbiBcIkFcIiAjIEFuaW1hdGlvblxuICAgICAgICAgICAgICAgIGFuaW1hdGlvbiA9IFJlY29yZE1hbmFnZXIuYW5pbWF0aW9uc1tNYXRoLm1heCh0b2tlbi52YWx1ZS0xLCAwKV1cbiAgICAgICAgICAgICAgICBpZiBhbmltYXRpb24/LmdyYXBoaWMubmFtZT9cbiAgICAgICAgICAgICAgICAgICAgaW1hZ2VCaXRtYXAgPSBSZXNvdXJjZU1hbmFnZXIuZ2V0Qml0bWFwKFwiR3JhcGhpY3MvUGljdHVyZXMvI3thbmltYXRpb24uZ3JhcGhpYy5uYW1lfVwiKVxuICAgICAgICAgICAgICAgICAgICBpZiBpbWFnZUJpdG1hcD9cbiAgICAgICAgICAgICAgICAgICAgICAgIHNpemUgPSB3aWR0aDogTWF0aC5yb3VuZChpbWFnZUJpdG1hcC53aWR0aCAvIGFuaW1hdGlvbi5mcmFtZXNYKSwgaGVpZ2h0OiBNYXRoLnJvdW5kKGltYWdlQml0bWFwLmhlaWdodCAvIGFuaW1hdGlvbi5mcmFtZXNZKVxuICAgICAgICAgICAgd2hlbiBcIlJUXCIgIyBSdWJ5IFRleHRcbiAgICAgICAgICAgICAgICBmb250ID0gQGdldFJ1YnlUZXh0Rm9udCh0b2tlbilcbiAgICAgICAgICAgICAgICBmcyA9IGZvbnQuc2l6ZVxuICAgICAgICAgICAgICAgIGZvbnQuc2l6ZSA9IGZvbnQuc2l6ZSB8fCBAZm9udC5zaXplIC8gMlxuICAgICAgICAgICAgICAgIHRva2VuLnJiU2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4odG9rZW4ucmIpXG4gICAgICAgICAgICAgICAgdG9rZW4ucnRTaXplID0gZm9udC5tZWFzdXJlVGV4dFBsYWluKHRva2VuLnJ0KVxuICAgICAgICAgICAgICAgIGZvbnQuc2l6ZSA9IGZzXG4gICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgc2l6ZSA9IHdpZHRoOiBNYXRoLm1heCh0b2tlbi5yYlNpemUud2lkdGgsIHRva2VuLnJ0U2l6ZS53aWR0aCksIGhlaWdodDogdG9rZW4ucmJTaXplLmhlaWdodCArIHRva2VuLnJ0U2l6ZS5oZWlnaHRcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIHNpemVcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogPHA+RHJhd3MgdGhlIHZpc3VhbCByZXN1bHQgb2YgYSB0b2tlbiwgbGlrZSBhbiBpY29uIGZvciBleGFtcGxlLCB0byB0aGUgc3BlY2lmaWVkIGJpdG1hcC4gVGhpcyBtZXRob2QgaXMgY2FsbGVkIGZvciBldmVyeSB0b2tlbiB3aGlsZSB0aGUgdGV4dCBpcyByZW5kZXJlZC48L3A+IFxuICAgICpcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSB0b2tlbiAtIEEgY29udHJvbC10b2tlbi5cbiAgICAqIEBwYXJhbSB7Z3MuQml0bWFwfSBiaXRtYXAgLSBUaGUgYml0bWFwIHVzZWQgZm9yIHRoZSBjdXJyZW50IHRleHQtbGluZS4gQ2FuIGJlIHVzZWQgdG8gZHJhdyBzb21ldGhpbmcgb24gaXQgbGlrZSBhbiBpY29uLCBldGMuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gb2Zmc2V0IC0gQW4geC1vZmZzZXQgZm9yIHRoZSBkcmF3LXJvdXRpbmUuXG4gICAgKiBAbWV0aG9kIGRyYXdDb250cm9sVG9rZW5cbiAgICAqIEBwcm90ZWN0ZWRcbiAgICAjIyNcbiAgICBkcmF3Q29udHJvbFRva2VuOiAodG9rZW4sIGJpdG1hcCwgb2Zmc2V0KSAtPlxuICAgICAgICBzd2l0Y2ggdG9rZW4uY29kZVxuICAgICAgICAgICAgd2hlbiBcIkFcIiAjIEFuaW1hdGlvblxuICAgICAgICAgICAgICAgIGFuaW1hdGlvbiA9IFJlY29yZE1hbmFnZXIuYW5pbWF0aW9uc1tNYXRoLm1heCh0b2tlbi52YWx1ZS0xLCAwKV1cbiAgICAgICAgICAgICAgICBpZiBhbmltYXRpb24/LmdyYXBoaWMubmFtZT9cbiAgICAgICAgICAgICAgICAgICAgaW1hZ2VCaXRtYXAgPSBSZXNvdXJjZU1hbmFnZXIuZ2V0Qml0bWFwKFwiR3JhcGhpY3MvUGljdHVyZXMvI3thbmltYXRpb24uZ3JhcGhpYy5uYW1lfVwiKVxuICAgICAgICAgICAgICAgICAgICBpZiBpbWFnZUJpdG1hcD9cbiAgICAgICAgICAgICAgICAgICAgICAgIHJlY3QgPSBuZXcgZ3MuUmVjdCgwLCAwLCBNYXRoLnJvdW5kKGltYWdlQml0bWFwLndpZHRoIC8gYW5pbWF0aW9uLmZyYW1lc1gpLCBNYXRoLnJvdW5kKGltYWdlQml0bWFwLmhlaWdodCAvIGFuaW1hdGlvbi5mcmFtZXNZKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGJpdG1hcC5ibHQob2Zmc2V0LCBAY3VycmVudFksIGltYWdlQml0bWFwLCByZWN0KVxuICAgICAgICAgICAgd2hlbiBcIlJUXCIgXG4gICAgICAgICAgICAgICAgc3R5bGUgPSBudWxsXG4gICAgICAgICAgICAgICAgaWYgdG9rZW4ucnRTdHlsZUlkXG4gICAgICAgICAgICAgICAgICAgIHN0eWxlID0gdWkuVUlNYW5hZ2VyLnN0eWxlc1tcInJ1YnlUZXh0LVwiK3Rva2VuLnJ0U3R5bGVJZF1cbiAgICAgICAgICAgICAgICBpZiAhc3R5bGVcbiAgICAgICAgICAgICAgICAgICAgc3R5bGUgPSB1aS5VSU1hbmFnZXIuc3R5bGVzW1wicnVieVRleHRcIl1cbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgZm9udCA9IHN0eWxlPy5mb250ID8gQGZvbnRcbiAgICAgICAgICAgICAgICBmcyA9IGZvbnQuc2l6ZVxuICAgICAgICAgICAgICAgIGZvbnQuc2l6ZSA9IGZvbnQuc2l6ZSB8fCBAZm9udC5zaXplIC8gMlxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgIGlmIHN0eWxlIGFuZCAhc3R5bGUuZGVzY3JpcHRvci5mb250Py5jb2xvclxuICAgICAgICAgICAgICAgICAgICBmb250LmNvbG9yLnNldChAZm9udC5jb2xvcilcbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgYml0bWFwLmZvbnQgPSBmb250XG4gICAgICAgICAgICAgICAgYml0bWFwLmRyYXdUZXh0KG9mZnNldCwgYml0bWFwLmZvbnQuZGVzY2VudCwgTWF0aC5tYXgodG9rZW4ucmJTaXplLndpZHRoLCB0b2tlbi5ydFNpemUud2lkdGgpLCBiaXRtYXAuaGVpZ2h0LCB0b2tlbi5ydCwgMSwgMClcbiAgICAgICAgICAgICAgICBiaXRtYXAuZm9udCA9IEBmb250XG4gICAgICAgICAgICAgICAgZm9udC5zaXplID0gZnNcbiAgICAgICAgICAgICAgICBiaXRtYXAuZHJhd1RleHQob2Zmc2V0LCB0b2tlbi5ydFNpemUuaGVpZ2h0LCBNYXRoLm1heCh0b2tlbi5yYlNpemUud2lkdGgsIHRva2VuLnJ0U2l6ZS53aWR0aCksIGJpdG1hcC5oZWlnaHQsIHRva2VuLnJiLCAxLCAwKVxuICAgIFxuICAgIFxuICAgICMjIypcbiAgICAqIFNwbGl0cyB1cCB0aGUgc3BlY2lmaWVkIHRva2VuIHVzaW5nIGEgamFwYW5lc2Ugd29yZC13cmFwIHRlY2huaXF1ZS5cbiAgICAqIFxuICAgICogQG1ldGhvZCB3b3JkV3JhcEphcGFuZXNlXG4gICAgKiBAcGFyYW0ge09iamVjdH0gdG9rZW4gLSBUaGUgdG9rZW4gdG8gc3BsaXQgdXAuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmV9IGxpbmUgLSBUaGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gVGhlIHdpZHRoIG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gVGhlIGhlaWdodCBvZiB0aGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lW119IC0gQW4gYXJyYXkgb2YgbGluZXMuIElmIHRoZSB0b2tlbiBpcyBzcGxpdCB1cCBpbnRvIG11bHRpcGxlIGxpbmVzLCBhbGwgbmV3XG4gICAgKiBsaW5lcyBhcmUgYWRkZWQgdG8gdGhpcyByZXN1bHQgYXJyYXkuXG4gICAgKiBAcmV0dXJuIHtncy5SZW5kZXJlclRleHRMaW5lfSBUaGUgY3VycmVudCBsaW5lLCB0aGF0IG1heSBiZSB0aGUgc2FtZSBhcyB0aGUgPGI+bGluZTwvYj4gcGFyYW1ldGVycyBidXQgaWYgbmV3IGxpbmVzXG4gICAgKiBhcmUgY3JlYXRlZCBpdCBoYXMgdG8gYmUgdGhlIGxhc3QgbmV3IGNyZWF0ZWQgbGluZS5cbiAgICAjIyMgICAgIFxuICAgIHdvcmRXcmFwSmFwYW5lc2U6ICh0b2tlbiwgbGluZSwgd2lkdGgsIGhlaWdodCwgcmVzdWx0KSAtPlxuICAgICAgICBzdGFydE9mTGluZSA9ICfigJTigKbigKXjgLPjgLTjgLXjgIIu44O744CBOjssID8h4oC84oGH4oGI4oGJ4oCQ44Kg4oCT44CcKV3vvZ3jgJXjgInjgIvjgI3jgI/jgJHjgJnjgJfjgJ/igJlcIu+9oMK744O944O+44O844Kh44Kj44Kl44Kn44Kp44OD44Oj44Ol44On44Ou44O144O244GB44GD44GF44GH44GJ44Gj44KD44KF44KH44KO44KV44KW44ew44ex44ey44ez44e044e144e244e344e444e544e644e744e844e944e+44e/44CF44C7J1xuICAgICAgICBlbmRPZkxpbmUgPSAnKFvvvZvjgJTjgIjjgIrjgIzjgI7jgJDjgJjjgJbjgJ3igJhcIu+9n8KrJ1xuICAgICAgICBub1NwbGl0ID0gJ0FCQ0RFRkdISUpLTE1OT1BRUlNUVVZXWFlaYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg577yQ77yR77yS77yT77yU77yV77yW77yX77yY77yZ4oCU4oCm4oCl44Cz44C044C1J1xuICAgICAgICBkZXNjZW50ID0gQGZvbnQuZGVzY2VudFxuICAgICAgICBzaXplID0gQGZvbnQubWVhc3VyZVRleHRQbGFpbih0b2tlbilcbiAgICAgICAgZGVwdGggPSA4XG4gICAgICAgIGRlcHRoTGV2ZWwgPSAwXG4gICAgICAgIGkgPSAwXG4gICAgICAgIGogPSAwXG4gICAgICAgIGxhc3RDaGFyYWN0ZXJJbmRleCA9IDBcbiAgICAgICAgXG4gICAgICAgIGlmIHNpemUud2lkdGggPiBAb2JqZWN0LmRzdFJlY3Qud2lkdGgtQHNwYWNlU2l6ZS53aWR0aCozLUBwYWRkaW5nKjJcbiAgICAgICAgICAgIHdoaWxlIGkgPCB0b2tlbi5sZW5ndGhcbiAgICAgICAgICAgICAgICBjaCA9IHRva2VuW2ldXG4gICAgICAgICAgICAgICAgc2l6ZSA9IEBmb250Lm1lYXN1cmVUZXh0UGxhaW4oY2gpXG4gICAgICAgICAgICAgICAgd2lkdGggKz0gc2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgIG1vdmVkID0gbm9cbiAgICAgICAgICAgICAgICBpZiB3aWR0aCA+IEBvYmplY3QuZHN0UmVjdC53aWR0aCAtIEBwYWRkaW5nKjJcbiAgICAgICAgICAgICAgICAgICAgZGVwdGhMZXZlbCA9IDBcbiAgICAgICAgICAgICAgICAgICAgaiA9IGlcbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgIGxvb3BcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vdmVkID0gbm9cbiAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIGogPiAwIGFuZCBzdGFydE9mTGluZS5pbmRleE9mKHRva2VuW2pdKSAhPSAtMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGotLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vdmVkID0geWVzXG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlIGogPiAwIGFuZCBlbmRPZkxpbmUuaW5kZXhPZih0b2tlbltqLTFdKSAhPSAtMVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGotLVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vdmVkID0geWVzXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgICAgICB3aGlsZSBqID4gMCBhbmQgbm9TcGxpdC5pbmRleE9mKHRva2VuW2otMV0pICE9IC0xXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgai0tXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbW92ZWQgPSB5ZXNcbiAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiBqID09IDAgYW5kIG1vdmVkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpID0galxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgZGVwdGhMZXZlbCsrXG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhayBpZiBkZXB0aExldmVsID49IGRlcHRoIG9yICFtb3ZlZFxuICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgIGxpbmUuY29udGVudC5wdXNoKG5ldyBncy5SZW5kZXJlclRva2VuKG51bGwsIHRva2VuLnN1YnN0cmluZyhsYXN0Q2hhcmFjdGVySW5kZXgsIGkpLCBAZm9udCkpXG4gICAgICAgICAgICAgICAgICAgIGxhc3RDaGFyYWN0ZXJJbmRleCA9IGlcbiAgICAgICAgICAgICAgICAgICAgbGluZS5oZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIEBmb250LmxpbmVIZWlnaHQpXG4gICAgICAgICAgICAgICAgICAgIGxpbmUud2lkdGggPSB3aWR0aCAtIHNpemUud2lkdGhcbiAgICAgICAgICAgICAgICAgICAgbGluZS5kZXNjZW50ID0gZGVzY2VudFxuICAgICAgICAgICAgICAgICAgICBkZXNjZW50ID0gQGZvbnQuZGVzY2VudFxuICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSBzaXplLmhlaWdodFxuICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChsaW5lKVxuICAgICAgICAgICAgICAgICAgICBsaW5lID0gbmV3IGdzLlJlbmRlcmVyVGV4dExpbmUoKVxuICAgICAgICAgICAgICAgICAgICB3aWR0aCA9IHdpZHRoIC0gKHdpZHRoIC0gc2l6ZS53aWR0aClcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICBpKytcbiAgICAgICAgZWxzZVxuICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2gobmV3IGdzLlJlbmRlcmVyVG9rZW4obnVsbCwgdG9rZW4sIEBmb250KSlcbiAgICAgICAgICAgIGxpbmUuaGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBAZm9udC5saW5lSGVpZ2h0KVxuICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoICsgc2l6ZS53aWR0aFxuICAgICAgICAgICAgbGluZS5kZXNjZW50ID0gZGVzY2VudFxuICAgICAgICAgICAgXG4gICAgICAgIGhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgQGZvbnQubGluZUhlaWdodCkgICBcbiAgICAgICAgICAgIFxuICAgICAgICBpZiBsYXN0Q2hhcmFjdGVySW5kZXggIT0gaVxuICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2gobmV3IGdzLlJlbmRlcmVyVG9rZW4obnVsbCwgdG9rZW4uc3Vic3RyaW5nKGxhc3RDaGFyYWN0ZXJJbmRleCwgaSksIEBmb250KSlcbiAgICAgICAgICAgIGxpbmUud2lkdGggPSB3aWR0aFxuICAgICAgICAgICAgbGluZS5oZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIGxpbmUuaGVpZ2h0KVxuICAgICAgICAgICAgbGluZS5kZXNjZW50ID0gZGVzY2VudFxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBsaW5lXG4gICAgICAgIFxuICAgIFxuICAgICMjIypcbiAgICAqIERvZXMgbm90IHdvcmQtd3JhcHBpbmcgYXQgYWxsLiBJdCBqdXN0IGFkZHMgdGhlIHRleHQgdG9rZW4gdG8gdGhlIGxpbmUgYXMgaXMuXG4gICAgKiBcbiAgICAqIEBtZXRob2Qgd29yZFdyYXBOb25lXG4gICAgKiBAcGFyYW0ge09iamVjdH0gdG9rZW4gLSBUaGUgdG9rZW4gdG8gc3BsaXQgdXAuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmV9IGxpbmUgLSBUaGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gVGhlIHdpZHRoIG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gVGhlIGhlaWdodCBvZiB0aGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lW119IC0gQW4gYXJyYXkgb2YgbGluZXMuIElmIHRoZSB0b2tlbiBpcyBzcGxpdCB1cCBpbnRvIG11bHRpcGxlIGxpbmVzLCBhbGwgbmV3XG4gICAgKiBsaW5lcyBhcmUgYWRkZWQgdG8gdGhpcyByZXN1bHQgYXJyYXkuXG4gICAgKiBAcmV0dXJuIHtncy5SZW5kZXJlclRleHRMaW5lfSBUaGUgY3VycmVudCBsaW5lLCB0aGF0IG1heSBiZSB0aGUgc2FtZSBhcyB0aGUgPGI+bGluZTwvYj4gcGFyYW1ldGVycyBidXQgaWYgbmV3IGxpbmVzXG4gICAgKiBhcmUgY3JlYXRlZCBpdCBoYXMgdG8gYmUgdGhlIGxhc3QgbmV3IGNyZWF0ZWQgbGluZS5cbiAgICAjIyMgIFxuICAgIHdvcmRXcmFwTm9uZTogKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQpIC0+XG4gICAgICAgIHNpemUgPSBAZm9udC5tZWFzdXJlVGV4dFBsYWluKHRva2VuKVxuICAgICAgICBoZWlnaHQgPSBNYXRoLm1heChzaXplLmhlaWdodCwgaGVpZ2h0IHx8IEBmb250LmxpbmVIZWlnaHQpICAgXG4gICAgICAgIFxuICAgICAgICBpZiB0b2tlbi5sZW5ndGggPiAwICAgIFxuICAgICAgICAgICAgbGluZS53aWR0aCArPSBzaXplLndpZHRoXG4gICAgICAgICAgICBsaW5lLmhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgbGluZS5oZWlnaHQpXG4gICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBAZm9udC5kZXNjZW50XG4gICAgICAgICAgICBsaW5lLmNvbnRlbnQucHVzaChuZXcgZ3MuUmVuZGVyZXJUb2tlbihudWxsLCB0b2tlbikpXG4gICAgICAgICAgICBcbiAgICAgICAgcmV0dXJuIGxpbmVcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogU3BsaXRzIHVwIHRoZSBzcGVjaWZpZWQgdG9rZW4gdXNpbmcgYSBzcGFjZS1iYXNlZCB3b3JkLXdyYXAgdGVjaG5pcXVlLlxuICAgICogXG4gICAgKiBAbWV0aG9kIHdvcmRXcmFwU3BhY2VCYXNlZFxuICAgICogQHBhcmFtIHtPYmplY3R9IHRva2VuIC0gVGhlIHRva2VuIHRvIHNwbGl0IHVwLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lfSBsaW5lIC0gVGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB3aWR0aCAtIFRoZSB3aWR0aCBvZiB0aGUgY3VycmVudCBsaW5lLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IGhlaWdodCAtIFRoZSBoZWlnaHQgb2YgdGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7Z3MuUmVuZGVyZXJUZXh0TGluZVtdfSAtIEFuIGFycmF5IG9mIGxpbmVzLiBJZiB0aGUgdG9rZW4gaXMgc3BsaXQgdXAgaW50byBtdWx0aXBsZSBsaW5lcywgYWxsIG5ld1xuICAgICogbGluZXMgYXJlIGFkZGVkIHRvIHRoaXMgcmVzdWx0IGFycmF5LlxuICAgICogQHJldHVybiB7Z3MuUmVuZGVyZXJUZXh0TGluZX0gVGhlIGN1cnJlbnQgbGluZSwgdGhhdCBtYXkgYmUgdGhlIHNhbWUgYXMgdGhlIDxiPmxpbmU8L2I+IHBhcmFtZXRlcnMgYnV0IGlmIG5ldyBsaW5lc1xuICAgICogYXJlIGNyZWF0ZWQgaXQgaGFzIHRvIGJlIHRoZSBsYXN0IG5ldyBjcmVhdGVkIGxpbmUuXG4gICAgIyMjICAgIFxuICAgIHdvcmRXcmFwU3BhY2VCYXNlZDogKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQpIC0+XG4gICAgICAgIGN1cnJlbnRXb3JkcyA9IFtdXG4gICAgICAgIHdvcmRzID0gdG9rZW4uc3BsaXQoXCIgXCIpXG4gICAgICAgIGRlc2NlbnQgPSBAZm9udC5kZXNjZW50XG4gICAgICAgIEBzcGFjZVNpemUgPSBAZm9udC5tZWFzdXJlVGV4dFBsYWluKFwiIFwiKVxuICAgICAgICBcbiAgICAgICAgZm9yIHdvcmQsIGkgaW4gd29yZHNcbiAgICAgICAgICAgIHNpemUgPSBAZm9udC5tZWFzdXJlVGV4dFBsYWluKHdvcmQpXG4gICAgICAgICAgICB3aWR0aCArPSBzaXplLndpZHRoICsgQHNwYWNlU2l6ZS53aWR0aFxuICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgIGlmIHdpZHRoID4gQG9iamVjdC5kc3RSZWN0LndpZHRoIC0gQHBhZGRpbmcqMlxuICAgICAgICAgICAgICAgIHRva2VuID0gbmV3IGdzLlJlbmRlcmVyVG9rZW4obnVsbCwgY3VycmVudFdvcmRzLmpvaW4oXCIgXCIpKVxuICAgICAgICAgICAgICAgIHRva2VuLnRha2VGb3JtYXQoQGZvbnQpXG4gICAgICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2godG9rZW4pXG4gICAgICAgICAgICAgICAgbGluZS5oZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIGxpbmUuaGVpZ2h0KVxuICAgICAgICAgICAgICAgIGxpbmUud2lkdGggPSB3aWR0aCAtIHNpemUud2lkdGhcbiAgICAgICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBNYXRoLm1heChsaW5lLmRlc2NlbnQsIGRlc2NlbnQpXG4gICAgICAgICAgICAgICAgZGVzY2VudCA9IE1hdGgubWF4KGRlc2NlbnQsIEBmb250LmRlc2NlbnQpXG4gICAgICAgICAgICAgICAgaGVpZ2h0ID0gc2l6ZS5oZWlnaHRcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaChsaW5lKVxuICAgICAgICAgICAgICAgIGxpbmUgPSBuZXcgZ3MuUmVuZGVyZXJUZXh0TGluZSgpXG4gICAgICAgICAgICAgICAgY3VycmVudFdvcmRzID0gW3dvcmRdXG4gICAgICAgICAgICAgICAgd2lkdGggPSB3aWR0aCAtICh3aWR0aCAtIHNpemUud2lkdGgpXG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgY3VycmVudFdvcmRzLnB1c2god29yZClcbiAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgIGhlaWdodCA9IE1hdGgubWF4KGhlaWdodCwgQGZvbnQubGluZUhlaWdodCkgICBcbiAgICAgICAgICAgIFxuICAgICAgICBpZiBjdXJyZW50V29yZHMubGVuZ3RoID4gMFxuICAgICAgICAgICAgdG9rZW4gPSBuZXcgZ3MuUmVuZGVyZXJUb2tlbihudWxsLCBjdXJyZW50V29yZHMuam9pbihcIiBcIikpXG4gICAgICAgICAgICB0b2tlbi50YWtlRm9ybWF0KEBmb250KVxuICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2godG9rZW4pXG4gICAgICAgICAgICBsaW5lLndpZHRoID0gd2lkdGhcbiAgICAgICAgICAgIGxpbmUuaGVpZ2h0ID0gTWF0aC5tYXgoaGVpZ2h0LCBsaW5lLmhlaWdodClcbiAgICAgICAgICAgIGxpbmUuZGVzY2VudCA9IE1hdGgubWF4KGRlc2NlbnQsIGxpbmUuZGVzY2VudClcbiAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gbGluZVxuICAgIFxuICAgICMjIypcbiAgICAqIFNwbGl0cyB1cCB0aGUgc3BlY2lmaWVkIHRva2VuIHVzaW5nIGEgd29yZC13cmFwIHRlY2huaXF1ZS4gVGhlIGtpbmQgb2Ygd29yZC13cmFwIHRlY2huaXF1ZVxuICAgICogZGVwZW5kcyBvbiB0aGUgc2VsZWN0ZWQgbGFuZ3VhZ2UuIFlvdSBjYW4gb3ZlcndyaXRlIHRoaXMgbWV0aG9kIGluIGRlcml2ZWQgY2xhc3NlcyB0byBpbXBsZW1lbnQgeW91clxuICAgICogb3duIGN1c3RvbSB3b3JkLXdyYXAgdGVjaG5pcXVlcy5cbiAgICAqIFxuICAgICogQG1ldGhvZCBleGVjdXRlV29yZFdyYXBcbiAgICAqIEBwYXJhbSB7T2JqZWN0fSB0b2tlbiAtIFRoZSB0b2tlbiB0byBzcGxpdCB1cC5cbiAgICAqIEBwYXJhbSB7Z3MuUmVuZGVyZXJUZXh0TGluZX0gbGluZSAtIFRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBUaGUgd2lkdGggb2YgdGhlIGN1cnJlbnQgbGluZS5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBUaGUgaGVpZ2h0IG9mIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgKiBAcGFyYW0ge2dzLlJlbmRlcmVyVGV4dExpbmVbXX0gLSBBbiBhcnJheSBvZiBsaW5lcy4gSWYgdGhlIHRva2VuIGlzIHNwbGl0IHVwIGludG8gbXVsdGlwbGUgbGluZXMsIGFsbCBuZXdcbiAgICAqIGxpbmVzIGFyZSBhZGRlZCB0byB0aGlzIHJlc3VsdCBhcnJheS5cbiAgICAqIEByZXR1cm4ge2dzLlJlbmRlcmVyVGV4dExpbmV9IFRoZSBjdXJyZW50IGxpbmUsIHRoYXQgbWF5IGJlIHRoZSBzYW1lIGFzIHRoZSA8Yj5saW5lPC9iPiBwYXJhbWV0ZXJzIGJ1dCBpZiBuZXcgbGluZXNcbiAgICAqIGFyZSBjcmVhdGVkIGl0IGhhcyB0byBiZSB0aGUgbGFzdCBuZXcgY3JlYXRlZCBsaW5lLlxuICAgICMjI1xuICAgIGV4ZWN1dGVXb3JkV3JhcDogKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQsIHdvcmRXcmFwKSAtPlxuICAgICAgICBpZiB3b3JkV3JhcFxuICAgICAgICAgICAgc3dpdGNoIExhbmd1YWdlTWFuYWdlci5sYW5ndWFnZS53b3JkV3JhcFxuICAgICAgICAgICAgICAgIHdoZW4gXCJzcGFjZUJhc2VkXCJcbiAgICAgICAgICAgICAgICAgICAgQHdvcmRXcmFwU3BhY2VCYXNlZCh0b2tlbiwgbGluZSwgd2lkdGgsIGhlaWdodCwgcmVzdWx0KVxuICAgICAgICAgICAgICAgIHdoZW4gXCJqYXBhbmVzZVwiXG4gICAgICAgICAgICAgICAgICAgIEB3b3JkV3JhcEphcGFuZXNlKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQpXG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIEB3b3JkV3JhcE5vbmUodG9rZW4sIGxpbmUsIHdpZHRoLCBoZWlnaHQsIHJlc3VsdClcbiAgICAgICAgICAgIFxuICBcbiAgICAjIyMqXG4gICAgKiBDcmVhdGVzIGFuIGEgb2YgbGluZS1vYmplY3RzLiBFYWNoIGxpbmUtb2JqZWN0IGlzIGEgbGlzdCBvZiB0b2tlbi1vYmplY3RzLiBcbiAgICAqIEEgdG9rZW4tb2JqZWN0IGNhbiBiZSBqdXN0IGEgc3RyaW5nIG9yIGFuIG9iamVjdCBjb250YWluaW5nIG1vcmUgaW5mb3JtYXRpb25cbiAgICAqIGFib3V0IGhvdyB0byBwcm9jZXNzIHRoZSB0b2tlbiBhdCBydW50aW1lLlxuICAgICogXG4gICAgKiBBIGxpbmUtb2JqZWN0IGFsc28gY29udGFpbnMgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBsaWtlIHRoZSB3aWR0aCBhbmQgaGVpZ2h0XG4gICAgKiBvZiB0aGUgbGluZShpbiBwaXhlbHMpLlxuICAgICogXG4gICAgKiBJZiB0aGUgd29yZFdyYXAgcGFyYW0gaXMgc2V0LCBsaW5lLWJyZWFrcyBhcmUgYXV0b21hdGljYWxseSBjcmVhdGVkIGlmIGEgbGluZVxuICAgICogZG9lc24ndCBmaXQgaW50byB0aGUgd2lkdGggb2YgdGhlIGdhbWUgb2JqZWN0J3MgYml0bWFwLlxuICAgICogXG4gICAgKiBAbWV0aG9kIGNhbGN1bGF0ZUxpbmVzXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gbWVzc2FnZSAtIEEgbWVzc2FnZSBjcmVhdGluZyB0aGUgbGluZS1vYmplY3RzIGZvci5cbiAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gd29yZFdyYXAgLSBJZiB3b3JkV3JhcCBpcyBzZXQgdG8gdHJ1ZSwgbGluZS1icmVha3MgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZC5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBbZmlyc3RMaW5lV2lkdGg9MF0gLSBUaGUgY3VycmVudCB3aWR0aCBvZiB0aGUgZmlyc3QgbGluZS5cbiAgICAqIEByZXR1cm4ge0FycmF5fSBBbiBhcnJheSBvZiBsaW5lLW9iamVjdHMuXG4gICAgIyMjXG4gICAgY2FsY3VsYXRlTGluZXM6IChtZXNzYWdlLCB3b3JkV3JhcCwgZmlyc3RMaW5lV2lkdGgpIC0+XG4gICAgICAgIHJlc3VsdCA9IFtdXG4gICAgICAgIGxpbmUgPSBuZXcgZ3MuUmVuZGVyZXJUZXh0TGluZSgpXG4gICAgICAgIHdpZHRoID0gZmlyc3RMaW5lV2lkdGggfHwgMFxuICAgICAgICBoZWlnaHQgPSAwXG4gICAgICAgIGRlc2NlbnQgPSBAZm9udC5kZXNjZW50XG4gICAgICAgIGN1cnJlbnRXb3JkcyA9IFtdXG4gICAgICAgIHNpemUgPSBudWxsXG4gICAgICAgIEBzcGFjZVNpemUgPSBAZm9udC5tZWFzdXJlQ2hhcihcIiBcIilcbiAgICAgICAgQGZvbnRTaXplID0gQGZvbnQuc2l6ZVxuICAgICAgICBcbiAgICAgICAgdG9rZW5zID0gbWVzc2FnZS5zcGxpdCgvXFx7KFtBLXpdKyk6KFteXFx7XFx9XSspXFx9fChcXG4pL2dtKVxuICAgICAgICB0b2tlbiA9IG51bGxcbiAgICAgICAgdCA9IDBcbiAgICAgICAgXG4gICAgICAgIHVuZGVybGluZSA9IEBmb250LnVuZGVybGluZVxuICAgICAgICBzdHJpa2VUaHJvdWdoID0gQGZvbnQuc3RyaWtlVGhyb3VnaFxuICAgICAgICBpdGFsaWMgPSBAZm9udC5pdGFsaWNcbiAgICAgICAgYm9sZCA9IEBmb250LmJvbGRcbiAgICAgICAgc21hbGxDYXBzID0gQGZvbnQuc21hbGxDYXBzXG4gICAgICAgIFxuICAgICAgICB3aGlsZSB0IDwgdG9rZW5zLmxlbmd0aFxuICAgICAgICAgICAgdG9rZW4gPSB0b2tlbnNbdF1cbiAgICAgICAgICAgIFxuICAgICAgICAgICAgaWYgdCAlIDQgIT0gMFxuICAgICAgICAgICAgICAgIGlmIHRva2VuP1xuICAgICAgICAgICAgICAgICAgICB0b2tlbk9iamVjdCA9IEBjcmVhdGVUb2tlbih0b2tlbiwgdG9rZW5zW3QrMV0pXG4gICAgICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgICAgICAgICBpZiB0b2tlbk9iamVjdC5wdXNoP1xuICAgICAgICAgICAgICAgICAgICAgICAgQXJyYXkucHJvdG90eXBlLnNwbGljZS5hcHBseSh0b2tlbnMsIFt0KzMsIDBdLmNvbmNhdCh0b2tlbk9iamVjdCkpXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgbm90IHRva2VuT2JqZWN0LmNvZGU/XG4gICAgICAgICAgICAgICAgICAgICAgICB0b2tlbnNbdCszXSA9IHRva2VuT2JqZWN0ICsgdG9rZW5zW3QrM11cbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgc2l6ZSA9IEBtZWFzdXJlQ29udHJvbFRva2VuKHRva2VuT2JqZWN0KVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgc2l6ZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpZHRoICs9IHNpemUud2lkdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSBNYXRoLm1heChoZWlnaHQsIHNpemUuaGVpZ2h0KVxuICAgICAgICAgICAgICAgICAgICAgICAgI2Rlc2NlbnQgPSBNYXRoLm1heChAZm9udC5kZXNjZW50LCBkZXNjZW50KVxuICAgICAgICAgICAgICAgICAgICAgICAgbGluZS5jb250ZW50LnB1c2godG9rZW5PYmplY3QpXG4gICAgICAgICAgICAgICAgZWxzZSAjIE11c3QgYmUgYSBuZXctbGluZVxuICAgICAgICAgICAgICAgICAgICBsaW5lLmhlaWdodCA9IGhlaWdodCB8fCBAZm9udC5saW5lSGVpZ2h0XG4gICAgICAgICAgICAgICAgICAgIGxpbmUud2lkdGggPSB3aWR0aFxuICAgICAgICAgICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBkZXNjZW50XG4gICAgICAgICAgICAgICAgICAgIHJlc3VsdC5wdXNoKGxpbmUpXG4gICAgICAgICAgICAgICAgICAgIGxpbmUgPSBuZXcgZ3MuUmVuZGVyZXJUZXh0TGluZSgpXG4gICAgICAgICAgICAgICAgICAgIGxpbmUuY29udGVudC5wdXNoKG5ldyBncy5SZW5kZXJlclRva2VuKG51bGwsIFwiXFxuXCIsIEBmb250KSlcbiAgICAgICAgICAgICAgICAgICAgd2lkdGggPSAwXG4gICAgICAgICAgICAgICAgICAgIGhlaWdodCA9IDBcbiAgICAgICAgICAgICAgICAgICAgZGVzY2VudCA9IEBmb250LmRlc2NlbnRcbiAgICAgICAgICAgICAgICB0ICs9IDJcbiAgICAgICAgICAgIGVsc2UgaWYgdG9rZW4ubGVuZ3RoID4gMFxuICAgICAgICAgICAgICAgIGxpbmUgPSBAZXhlY3V0ZVdvcmRXcmFwKHRva2VuLCBsaW5lLCB3aWR0aCwgaGVpZ2h0LCByZXN1bHQsIHdvcmRXcmFwKVxuICAgICAgICAgICAgICAgIHdpZHRoID0gbGluZS53aWR0aFxuICAgICAgICAgICAgICAgIGhlaWdodCA9IGxpbmUuaGVpZ2h0XG4gICAgICAgICAgICAgICAgZGVzY2VudCA9IGxpbmUuZGVzY2VudFxuICAgICAgICAgICAgICAgIFxuICAgICAgICAgICAgdCsrXG4gICAgICAgICAgICBcbiAgICAgICAgaWYgbGluZS5jb250ZW50Lmxlbmd0aCA+IDAgb3IgcmVzdWx0Lmxlbmd0aCA9PSAwXG4gICAgICAgICAgICBsaW5lLmhlaWdodCA9IGhlaWdodFxuICAgICAgICAgICAgbGluZS53aWR0aCA9IHdpZHRoXG4gICAgICAgICAgICBsaW5lLmRlc2NlbnQgPSBkZXNjZW50XG4gICAgICAgICAgICByZXN1bHQucHVzaChsaW5lKVxuICAgICAgIFxuICAgICAgICAgXG4gICAgICAgIEBmb250LnNpemUgPSBAZm9udFNpemUgIFxuICAgICAgICBAZm9udC51bmRlcmxpbmUgPSB1bmRlcmxpbmVcbiAgICAgICAgQGZvbnQuc3RyaWtlVGhyb3VnaCA9IHN0cmlrZVRocm91Z2hcbiAgICAgICAgQGZvbnQuaXRhbGljID0gaXRhbGljXG4gICAgICAgIEBmb250LmJvbGQgPSBib2xkXG4gICAgICAgIEBmb250LnNtYWxsQ2FwcyA9IHNtYWxsQ2Fwc1xuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHJlc3VsdFxuICAgIFxuICAgIFxuICAgICMjIypcbiAgICAqIE1lYXN1cmVzIHRoZSBkaW1lbnNpb25zIG9mIGZvcm1hdHRlZCBsaW5lcyBpbiBwaXhlbHMuIFRoZSByZXN1bHQgaXMgbm90XG4gICAgKiBwaXhlbC1wZXJmZWN0LlxuICAgICogXG4gICAgKiBAbWV0aG9kIG1lYXN1cmVGb3JtYXR0ZWRMaW5lc1xuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lW119IGxpbmVzIC0gQW4gYXJyYXkgb2YgdGV4dCBsaW5lcyB0byBtZWFzdXJlLlxuICAgICogQHBhcmFtIHtib29sZWFufSB3b3JkV3JhcCAtIElmIHdvcmRXcmFwIGlzIHNldCB0byB0cnVlLCBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgbGluZS1icmVha3Mgd2lsbCBiZSBjYWxjdWxhdGVkLlxuICAgICogQHJlc3VsdCB7T2JqZWN0fSBBbiBvYmplY3QgY29udGFpbmluZyB0aGUgd2lkdGggYW5kIGhlaWdodCBvZiB0aGUgdGV4dC5cbiAgICAjIyNcbiAgICBtZWFzdXJlRm9ybWF0dGVkTGluZXM6IChsaW5lcywgd29yZFdyYXApIC0+XG4gICAgICAgIHNpemUgPSB3aWR0aDogMCwgaGVpZ2h0OiAwXG4gICAgICAgIFxuICAgICAgICBmb3IgbGluZSBpbiBsaW5lc1xuICAgICAgICAgICAgc2l6ZS53aWR0aCA9IE1hdGgubWF4KGxpbmUud2lkdGgrMiwgc2l6ZS53aWR0aClcbiAgICAgICAgICAgIHNpemUuaGVpZ2h0ICs9IGxpbmUuaGVpZ2h0ICsgQGxpbmVTcGFjaW5nXG5cbiAgICAgICAgc2l6ZS5oZWlnaHQgLT0gQGxpbmVTcGFjaW5nXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gc2l6ZVxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBNZWFzdXJlcyB0aGUgZGltZW5zaW9ucyBvZiBhIGZvcm1hdHRlZCB0ZXh0IGluIHBpeGVscy4gVGhlIHJlc3VsdCBpcyBub3RcbiAgICAqIHBpeGVsLXBlcmZlY3QuXG4gICAgKiBcbiAgICAqIEBtZXRob2QgbWVhc3VyZUZvcm1hdHRlZFRleHRcbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIHRleHQgdG8gbWVhc3VyZS5cbiAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gd29yZFdyYXAgLSBJZiB3b3JkV3JhcCBpcyBzZXQgdG8gdHJ1ZSwgYXV0b21hdGljYWxseSBjcmVhdGVkIGxpbmUtYnJlYWtzIHdpbGwgYmUgY2FsY3VsYXRlZC5cbiAgICAqIEByZXN1bHQge09iamVjdH0gQW4gb2JqZWN0IGNvbnRhaW5pbmcgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIHRleHQuXG4gICAgIyMjXG4gICAgbWVhc3VyZUZvcm1hdHRlZFRleHQ6ICh0ZXh0LCB3b3JkV3JhcCkgLT5cbiAgICAgICAgQGZvbnQuc2V0KEBvYmplY3QuZm9udClcbiAgICAgICAgc2l6ZSA9IG51bGxcbiAgICAgICAgbGluZXMgPSBAY2FsY3VsYXRlTGluZXModGV4dCwgd29yZFdyYXApXG4gICAgICAgIFxuICAgICAgICBzaXplID0gQG1lYXN1cmVGb3JtYXR0ZWRMaW5lcyhsaW5lcywgd29yZFdyYXApXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gc2l6ZVxuICAgICAgICBcbiAgICAjIyMqXG4gICAgKiBNZWFzdXJlcyB0aGUgZGltZW5zaW9ucyBvZiBhIHBsYWluIHRleHQgaW4gcGl4ZWxzLiBGb3JtYXR0aW5nIGFuZFxuICAgICogd29yZC13cmFwcGluZyBhcmUgbm90IHN1cHBvcnRlZC5cbiAgICAqXG4gICAgKiBAbWV0aG9kIG1lYXN1cmVUZXh0XG4gICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSB0ZXh0IHRvIG1lYXN1cmUuXG4gICAgKiBAcmVzdWx0IHtPYmplY3R9IEFuIG9iamVjdCBjb250YWluaW5nIHRoZSB3aWR0aCBhbmQgaGVpZ2h0IG9mIHRoZSB0ZXh0LlxuICAgICMjI1xuICAgIG1lYXN1cmVUZXh0OiAodGV4dCkgLT5cbiAgICAgICAgc2l6ZSA9IHdpZHRoOiAwLCBoZWlnaHQ6IDBcbiAgICAgICAgbGluZXMgPSB0ZXh0LnRvU3RyaW5nKCkuc3BsaXQoXCJcXG5cIilcblxuICAgICAgICBmb3IgbGluZSBpbiBsaW5lc1xuICAgICAgICAgICAgbGluZVNpemUgPSBAb2JqZWN0LmZvbnQubWVhc3VyZVRleHQodGV4dClcbiAgICAgICAgICAgIHNpemUud2lkdGggPSBNYXRoLm1heChzaXplLndpZHRoLCBsaW5lU2l6ZS53aWR0aClcbiAgICAgICAgICAgIHNpemUuaGVpZ2h0ICs9IEBvYmplY3QuZm9udC5saW5lSGVpZ2h0ICsgQGxpbmVTcGFjaW5nXG4gICAgICAgICAgICBcbiAgICAgICAgc2l6ZS5oZWlnaHQgLT0gQGxpbmVTcGFjaW5nXG4gICAgICAgIFxuICAgICAgICByZXR1cm4gc2l6ZVxuICAgIFxuICAgICMjIypcbiAgICAqIFNlYXJjaGVzIGZvciBhIHRva2VuIGluIGEgbGlzdCBvZiB0b2tlbnMgYW5kIHJldHVybnMgdGhlIGZpcnN0IG1hdGNoLlxuICAgICpcbiAgICAqIEBtZXRob2QgZmluZFRva2VuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gc3RhcnRJbmRleCAtIFRoZSBpbmRleCBpbiB0aGUgbGlzdCBvZiB0b2tlbnMgd2hlcmUgdGhlIHNlYXJjaCB3aWxsIHN0YXJ0LlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGNvZGUgLSBUaGUgY29kZSBvZiB0aGUgdG9rZW4gdG8gc2VhcmNoIGZvci5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBkaXJlY3Rpb24gLSBUaGUgc2VhcmNoIGRpcmVjdGlvbiwgY2FuIGJlIGZvcndhcmQoMSkgb3IgYmFja3dhcmQoLTEpLlxuICAgICogQHBhcmFtIHtPYmplY3RbXX0gdG9rZW5zIC0gVGhlIGxpc3Qgb2YgdG9rZW5zIHRvIHNlYXJjaC5cbiAgICAqIEByZXN1bHQge09iamVjdH0gVGhlIGZpcnN0IHRva2VuIHdoaWNoIG1hdGNoZXMgdGhlIHNwZWNpZmllZCBjb2RlIG9yIDxiPm51bGw8L2I+IGlmIHRoZSB0b2tlbiBjYW5ub3QgYmUgZm91bmQuXG4gICAgIyMjICBcbiAgICBmaW5kVG9rZW46IChzdGFydEluZGV4LCBjb2RlLCBkaXJlY3Rpb24sIHRva2VucykgLT5cbiAgICAgICAgdG9rZW4gPSBudWxsXG4gICAgICAgIGkgPSBzdGFydEluZGV4XG4gICAgICAgIGlmIGRpcmVjdGlvbiA9PSAtMVxuICAgICAgICAgICAgd2hpbGUgaSA+PSAwXG4gICAgICAgICAgICAgICAgdCA9IHRva2Vuc1tpXVxuICAgICAgICAgICAgICAgIGlmIHQuY29kZSA9PSBjb2RlXG4gICAgICAgICAgICAgICAgICAgIHRva2VuID0gdFxuICAgICAgICAgICAgICAgICAgICBicmVha1xuICAgICAgICAgICAgICAgIGktLVxuICAgICAgICBcbiAgICAgICAgcmV0dXJuIHRva2VuXG4gICAgIFxuICAgICMjIypcbiAgICAqIFNlYXJjaGVzIGZvciBhIHNwZWNpZmljIGtpbmQgb2YgdG9rZW5zIGJldHdlZW4gYSBzdGFydCBhbmQgYW4gZW5kIHRva2VuLlxuICAgICpcbiAgICAqIEBtZXRob2QgZmluZFRva2Vuc0JldHdlZW5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBzdGFydEluZGV4IC0gVGhlIGluZGV4IHdoZXJlIHRoZSBzZWFyY2ggd2lsbCBzdGFydC5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBlbmRJbmRleCAtIFRoZSBpbmRleCB3aGVyZSB0aGUgc2VhcmNoIHdpbGwgZW5kLlxuICAgICogQHBhcmFtIHtzdHJpbmd9IGNvZGUgLSBUaGUgY29kZSBvZiB0aGUgdG9rZW4tdHlwZSB0byBzZWFyY2ggZm9yLlxuICAgICogQHBhcmFtIHtPYmplY3RbXX0gdG9rZW5zIC0gVGhlIGxpc3Qgb2YgdG9rZW5zIHRvIHNlYXJjaC5cbiAgICAqIEByZXN1bHQge09iamVjdFtdfSBMaXN0IG9mIHRva2VucyBtYXRjaGluZyB0aGUgc3BlY2lmaWVkIGNvZGUuIEl0cyBhbiBlbXB0eSBsaXN0IGlmIG5vIHRva2VucyB3ZXJlIGZvdW5kLlxuICAgICMjIyAgICAgXG4gICAgZmluZFRva2Vuc0JldHdlZW46IChzdGFydEluZGV4LCBlbmRJbmRleCwgY29kZSwgdG9rZW5zKSAtPlxuICAgICAgICByZXN1bHQgPSBbXVxuICAgICAgICBzID0gc3RhcnRJbmRleFxuICAgICAgICBlID0gZW5kSW5kZXhcbiAgICAgICAgXG4gICAgICAgIHdoaWxlIHMgPCBlXG4gICAgICAgICAgICB0b2tlbiA9IHRva2Vuc1tzXVxuICAgICAgICAgICAgaWYgYHRva2VuLmNvZGUgPT0gY29kZWBcbiAgICAgICAgICAgICAgICByZXN1bHQucHVzaCh0b2tlbilcbiAgICAgICAgICAgIHMrK1xuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogUHJvY2Vzc2VzIGEgY29udHJvbC10b2tlbi4gQSBjb250cm9sLXRva2VuIGlzIGEgdG9rZW4gd2hpY2ggaW5mbHVlbmNlc1xuICAgICogdGhlIHRleHQtcmVuZGVyaW5nIGxpa2UgY2hhbmdpbmcgdGhlIGZvbnRzIGNvbG9yLCBzaXplIG9yIHN0eWxlLlxuICAgICpcbiAgICAqIENoYW5nZXMgd2lsbCBiZSBhdXRvbWF0aWNhbGx5IGFwcGxpZWQgdG8gdGhlIGdhbWUgb2JqZWN0J3MgZm9udC5cbiAgICAqXG4gICAgKiBAbWV0aG9kIHByb2Nlc3NDb250cm9sVG9rZW5cbiAgICAqIEBwYXJhbSB7T2JqZWN0fSB0b2tlbiAtIEEgY29udHJvbC10b2tlbi5cbiAgICAqIEByZXR1cm4ge09iamVjdH0gQW4gb2JqZWN0IHdoaWNoIGNhbiBjb250YWluIGFkZGl0aW9uYWwgaW5mbyBuZWVkZWQgZm9yIHByb2Nlc3NpbmcuXG4gICAgIyMjXG4gICAgcHJvY2Vzc0NvbnRyb2xUb2tlbjogKHRva2VuKSAtPlxuICAgICAgICByZXN1bHQgPSBudWxsXG4gICAgICAgIFxuICAgICAgICBzd2l0Y2ggdG9rZW4uY29kZVxuICAgICAgICAgICAgd2hlbiBcIlNaXCJcbiAgICAgICAgICAgICAgICBAb2JqZWN0LmZvbnQuc2l6ZSA9IHRva2VuLnZhbHVlIHx8IEBmb250U2l6ZVxuICAgICAgICAgICAgd2hlbiBcIkNcIlxuICAgICAgICAgICAgICAgIGlmIHRva2VuLnZhbHVlIDw9IDBcbiAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5mb250LmNvbG9yID0gRm9udC5kZWZhdWx0Q29sb3JcbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5jb2xvciA9IFJlY29yZE1hbmFnZXIuc3lzdGVtLmNvbG9yc1t0b2tlbi52YWx1ZS0xXSB8fCBGb250LmRlZmF1bHRDb2xvclxuICAgICAgICAgICAgd2hlbiBcIllcIlxuICAgICAgICAgICAgICAgIHN3aXRjaCB0b2tlbi52YWx1ZVxuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiVVwiIHRoZW4gQG9iamVjdC5mb250LnVuZGVybGluZSA9IHllc1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiU1wiIHRoZW4gQG9iamVjdC5mb250LnN0cmlrZVRocm91Z2ggPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIklcIiB0aGVuIEBvYmplY3QuZm9udC5pdGFsaWMgPSB5ZXNcbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIkJcIiB0aGVuIEBvYmplY3QuZm9udC5ib2xkID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJDXCIgdGhlbiBAb2JqZWN0LmZvbnQuc21hbGxDYXBzID0geWVzXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOVVwiIHRoZW4gQG9iamVjdC5mb250LnVuZGVybGluZSA9IG5vXG4gICAgICAgICAgICAgICAgICAgIHdoZW4gXCJOU1wiIHRoZW4gQG9iamVjdC5mb250LnN0cmlrZVRocm91Z2ggPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTklcIiB0aGVuIEBvYmplY3QuZm9udC51bmRlcmxpbmUgPSBub1xuICAgICAgICAgICAgICAgICAgICB3aGVuIFwiTkJcIiB0aGVuIEBvYmplY3QuZm9udC5ib2xkID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5DXCIgdGhlbiBAb2JqZWN0LmZvbnQuc21hbGxDYXBzID0gbm9cbiAgICAgICAgICAgICAgICAgICAgd2hlbiBcIk5cIlxuICAgICAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5mb250LnVuZGVybGluZSA9IG5vXG4gICAgICAgICAgICAgICAgICAgICAgICBAb2JqZWN0LmZvbnQuc3RyaWtlVGhyb3VnaCA9IG5vXG4gICAgICAgICAgICAgICAgICAgICAgICBAb2JqZWN0LmZvbnQuaXRhbGljID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5ib2xkID0gbm9cbiAgICAgICAgICAgICAgICAgICAgICAgIEBvYmplY3QuZm9udC5zbWFsbENhcHMgPSBub1xuICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiByZXN1bHRcbiAgICAgICAgXG4gICAgIyMjKlxuICAgICogRHJhd3MgYSBwbGFpbiB0ZXh0LiBGb3JtYXR0aW5nIGFuZCB3b3JkLXdyYXBwaW5nIGFyZSBub3Qgc3VwcG9ydGVkLlxuICAgICpcbiAgICAqIEBtZXRob2QgZHJhd1RleHRcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB4IC0gVGhlIHgtY29vcmRpbmF0ZSBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHkgLSBUaGUgeS1jb29yZGluYXRlIG9mIHRoZSB0ZXh0J3MgcG9zaXRpb24uXG4gICAgKiBAcGFyYW0ge251bWJlcn0gd2lkdGggLSBEZXByZWNhdGVkLiBDYW4gYmUgbnVsbC5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBoZWlnaHQgLSBEZXByZWNhdGVkLiBDYW4gYmUgbnVsbC5cbiAgICAqIEBwYXJhbSB7c3RyaW5nfSB0ZXh0IC0gVGhlIHRleHQgdG8gZHJhdy5cbiAgICAjIyNcbiAgICBkcmF3VGV4dDogKHBsLCBwdCwgcHIsIHBiLCB0ZXh0KSAtPlxuICAgICAgICBsaW5lcyA9IHRleHQudG9TdHJpbmcoKS5zcGxpdChcIlxcblwiKVxuICAgICAgICBmb250ID0gQG9iamVjdC5mb250XG4gICAgICAgIGhlaWdodCA9IGZvbnQubGluZUhlaWdodFxuICAgICAgICBcbiAgICAgICAgZm9yIGxpbmUsIGkgaW4gbGluZXNcbiAgICAgICAgICAgIHNpemUgPSBmb250Lm1lYXN1cmVUZXh0KGxpbmUpXG4gICAgICAgICAgICBAb2JqZWN0LmJpdG1hcC5kcmF3VGV4dChwbCwgaSAqIGhlaWdodCArIHB0LCBzaXplLndpZHRoICsgcHIrcGwsIGhlaWdodCtwdCtwYiwgbGluZSwgMCwgMClcbiAgICAgICAgICAgIFxuICAgICAgICByZXR1cm4gbnVsbFxuICAgIFxuICAgICMjIypcbiAgICAqIERyYXdzIGFuIGFycmF5IG9mIGZvcm1hdHRlZCB0ZXh0IGxpbmVzLiBcbiAgICAqIElmIHRoZSB3b3JkV3JhcCBwYXJhbSBpcyBzZXQsIGxpbmUtYnJlYWtzIGFyZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQgaWYgYSBsaW5lXG4gICAgKiBkb2Vzbid0IGZpdCBpbnRvIHRoZSB3aWR0aCBvZiB0aGUgZ2FtZSBvYmplY3QncyBiaXRtYXAuXG4gICAgKlxuICAgICogQG1ldGhvZCBkcmF3Rm9ybWF0dGVkTGluZXNcbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBwbCAtIFRoZSBsZWZ0LXBhZGRpbmcgb2YgdGhlIHRleHQncyBwb3NpdGlvbi5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBwdCAtIFRoZSB0b3AtcGFkZGluZyBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHByIC0gVGhlIHJpZ2h0LXBhZGRpbmcgb2YgdGhlIHRleHQncyBwb3NpdGlvbi5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSBwYiAtIFRoZSBib3R0b20tcGFkZGluZyBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtncy5SZW5kZXJlclRleHRMaW5lW119IGxpbmVzIC0gQW4gYXJyYXkgb2YgbGluZXMgdG8gZHJhdy5cbiAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gd29yZFdyYXAgLSBJZiB3b3JkV3JhcCBpcyBzZXQgdG8gdHJ1ZSwgbGluZS1icmVha3MgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZC5cbiAgICAjIyMgXG4gICAgZHJhd0Zvcm1hdHRlZExpbmVzOiAocGwsIHB0LCBwciwgcGIsIGxpbmVzLCB3b3JkV3JhcCkgLT5cbiAgICAgICAgQGN1cnJlbnRYID0gcGxcbiAgICAgICAgQGN1cnJlbnRZID0gcHRcbiAgICAgICAgQGN1cnJlbnRMaW5lSGVpZ2h0ID0gMFxuICAgIFxuICAgICAgICBmb3IgbGluZSBpbiBsaW5lc1xuICAgICAgICAgICAgZm9yIHRva2VuIGluIGxpbmUuY29udGVudFxuICAgICAgICAgICAgICAgIGlmIHRva2VuLmNvZGU/XG4gICAgICAgICAgICAgICAgICAgIEBwcm9jZXNzQ29udHJvbFRva2VuKHRva2VuKVxuICAgICAgICAgICAgICAgICAgICBzaXplID0gQG1lYXN1cmVDb250cm9sVG9rZW4odG9rZW4pXG4gICAgICAgICAgICAgICAgICAgIGlmIHNpemVcbiAgICAgICAgICAgICAgICAgICAgICAgIEBkcmF3Q29udHJvbFRva2VuKHRva2VuLCBAb2JqZWN0LmJpdG1hcCwgQGN1cnJlbnRYKVxuICAgICAgICAgICAgICAgICAgICAgICAgQGN1cnJlbnRYICs9IHNpemUud2lkdGhcbiAgICAgICAgICAgICAgICBlbHNlIGlmIHRva2VuLnZhbHVlLmxlbmd0aCA+IDBcbiAgICAgICAgICAgICAgICAgICAgZm9udCA9IEBvYmplY3QuZm9udFxuICAgICAgICAgICAgICAgICAgICBoZWlnaHQgPSBsaW5lLmhlaWdodFxuICAgICAgICAgICAgICAgICAgICBpZiB0b2tlbi52YWx1ZSAhPSBcIlxcblwiXG4gICAgICAgICAgICAgICAgICAgICAgICBzaXplID0gZm9udC5tZWFzdXJlVGV4dFBsYWluKHRva2VuLnZhbHVlKVxuICAgICAgICAgICAgICAgICAgICAgICAgQG9iamVjdC5iaXRtYXAuZHJhd1RleHQoQGN1cnJlbnRYLCBAY3VycmVudFkgKyBoZWlnaHQgLSBzaXplLmhlaWdodCArIGZvbnQuZGVzY2VudCAtIGxpbmUuZGVzY2VudCwgc2l6ZS53aWR0aCtwbCtwciwgaGVpZ2h0K3B0K3BiLCB0b2tlbi52YWx1ZSwgMCwgMClcbiAgICAgICAgICAgICAgICAgICAgICAgIEBjdXJyZW50WCArPSBzaXplLndpZHRoXG4gICAgICAgICAgICAgICAgICAgIEBjdXJyZW50TGluZUhlaWdodCA9IE1hdGgubWF4KEBjdXJyZW50TGluZUhlaWdodCwgaGVpZ2h0KVxuICAgICAgICAgICAgQGN1cnJlbnRZICs9IChAY3VycmVudExpbmVIZWlnaHQgfHwgQG9iamVjdC5mb250LmxpbmVIZWlnaHQpICsgQGxpbmVTcGFjaW5nXG4gICAgICAgICAgICBAY3VycmVudFggPSBwbFxuICAgICAgICAgICAgQGN1cnJlbnRMaW5lSGVpZ2h0ID0gMFxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBudWxsXG4gICAgICAgIFxuICAgICMjIypcbiAgICAqIERyYXdzIGEgZm9ybWF0dGVkIHRleHQuIFxuICAgICogSWYgdGhlIHdvcmRXcmFwIHBhcmFtIGlzIHNldCwgbGluZS1icmVha3MgYXJlIGF1dG9tYXRpY2FsbHkgY3JlYXRlZCBpZiBhIGxpbmVcbiAgICAqIGRvZXNuJ3QgZml0IGludG8gdGhlIHdpZHRoIG9mIHRoZSBnYW1lIG9iamVjdCdzIGJpdG1hcC5cbiAgICAqXG4gICAgKiBAbWV0aG9kIGRyYXdGb3JtYXR0ZWRUZXh0XG4gICAgKiBAcGFyYW0ge251bWJlcn0geCAtIFRoZSB4LWNvb3JkaW5hdGUgb2YgdGhlIHRleHQncyBwb3NpdGlvbi5cbiAgICAqIEBwYXJhbSB7bnVtYmVyfSB5IC0gVGhlIHktY29vcmRpbmF0ZSBvZiB0aGUgdGV4dCdzIHBvc2l0aW9uLlxuICAgICogQHBhcmFtIHtudW1iZXJ9IHdpZHRoIC0gRGVwcmVjYXRlZC4gQ2FuIGJlIG51bGwuXG4gICAgKiBAcGFyYW0ge251bWJlcn0gaGVpZ2h0IC0gRGVwcmVjYXRlZC4gQ2FuIGJlIG51bGwuXG4gICAgKiBAcGFyYW0ge3N0cmluZ30gdGV4dCAtIFRoZSB0ZXh0IHRvIGRyYXcuXG4gICAgKiBAcGFyYW0ge2Jvb2xlYW59IHdvcmRXcmFwIC0gSWYgd29yZFdyYXAgaXMgc2V0IHRvIHRydWUsIGxpbmUtYnJlYWtzIGFyZSBhdXRvbWF0aWNhbGx5IGNyZWF0ZWQuXG4gICAgKiBAcmV0dXJuIHtncy5SZW5kZXJlclRleHRMaW5lW119IFRoZSBkcmF3biB0ZXh0IGxpbmVzLlxuICAgICMjI1xuICAgIGRyYXdGb3JtYXR0ZWRUZXh0OiAocGwsIHB0LCBwciwgcGIsIHRleHQsIHdvcmRXcmFwKSAtPlxuICAgICAgICBsaW5lcyA9IEBjYWxjdWxhdGVMaW5lcyh0ZXh0LnRvU3RyaW5nKCksIHdvcmRXcmFwKVxuICAgICAgICBcbiAgICAgICAgQGRyYXdGb3JtYXR0ZWRMaW5lcyhwbCwgcHQsIHByLCBwYiwgbGluZXMsIHdvcmRXcmFwKVxuICAgICAgICAgICAgXG4gICAgICAgIHJldHVybiBsaW5lc1xuICAgICAgICBcbmdzLkNvbXBvbmVudF9UZXh0UmVuZGVyZXIgPSBDb21wb25lbnRfVGV4dFJlbmRlcmVyIl19\n//# sourceURL=Component_TextRenderer_120.js"
13 13 },
14 14 "summary": [
15 15 "name",