@xmcl/text-component
Version:
Parse Minecraft text component and render it to css.
8 lines (7 loc) • 20.1 kB
Source Map (JSON)
{
"version": 3,
"sources": ["../index.ts"],
"sourcesContent": ["/**\n * @module @xmcl/text-component\n */\n/**\n * @see https://minecraft.gamepedia.com/Raw_JSON_text_format\n */\nexport interface TextComponent {\n /**\n * A string representing raw text to display directly in chat. Note that selectors such as \"@a\" and \"@p\" are not translated into player names; use selector instead. Can use escape characters, such as \\n for newline (enter), \\t for tab, etc.\n */\n text: string\n /**\n * The translation identifier of text to be displayed using the player's selected language. This identifier is the same as the identifiers found in lang files from assets or resource packs. Ignored when text exist in the root object.\n */\n translate?: string\n /**\n * A list of chat component arguments and/or string arguments to be used by translate. Useless otherwise.\n *\n * The arguments are text corresponding to the arguments used by the translation string in the current language, in order (for example, the first list element corresponds to \"%1$s\" in a translation string). Argument structure repeats this raw JSON text structure.\n */\n with?: string[]\n /**\n * A player's score in an objective. Displays nothing if the player is not tracked in the given objective.\n * Ignored when any of the previous fields exist in the root object.\n */\n score?: {\n name: string\n objective: string\n value: string\n }\n /**\n * A string containing a selector (@p,@a,@r,@e or @s) and, optionally, selector arguments.\n *\n * Unlike text, the selector is translated into the correct player/entity names.\n * If more than one player/entity is detected by the selector, it is displayed in a form such as 'Name1 and Name2' or 'Name1, Name2, Name3, and Name4'.\n * Ignored when any of the previous fields exist in the root object.\n *\n * - Clicking a player's name inserted into a /tellraw command this way suggests a command to whisper to that player.\n * - Shift-clicking a player's name inserts that name into chat.\n * - Shift-clicking a non-player entity's name inserts its UUID into chat.\n */\n selector?: string\n /**\n * A string that can be used to display the key needed to preform a certain action.\n * An example is `key.inventory` which always displays \"E\" unless the player has set a different key for opening their inventory.\n *\n * Ignored when any of the previous fields exist in the root object.\n */\n keybind?: string\n /**\n * A string indicating the NBT path used for looking up NBT values from an entity or a block entity. Ignored when any of the previous fields exist in the root object.\n */\n nbt?: string\n /**\n * A string specifying the coordinates of the block entity from which the NBT value is obtained. The coordinates can be absolute or relative. Useless if nbt is absent.\n */\n block?: string\n /**\n * A string specifying the target selector for the entity from which the NBT value is obtained. Useless if nbt is absent.\n */\n entity?: string\n /**\n * A list element whose structure repeats this raw JSON text structure. Note that all properties of this object are inherited by children except for text, extra, translate, with, and score.\n *\n * This means that children retain the same formatting and events as this object unless they explicitly override them.\n */\n extra?: TextComponent[]\n /**\n * The color to render this text in. Valid values are \"black\", \"dark_blue\", \"dark_green\", \"dark_aqua\", \"dark_red\", \"dark_purple\", \"gold\", \"gray\", \"dark_gray\", \"blue\", \"green\", \"aqua\", \"red\", \"light_purple\", \"yellow\", \"white\", and \"reset\" (cancels out the effects of colors used by parent objects). Technically, \"bold\", \"italic\", \"underlined\", \"strikethrough\", and \"obfuscated\" are also accepted, but it may be better practice to use the tags below for such formats.\n */\n color?: string\n bold?: boolean\n italic?: boolean\n underlined?: boolean\n strikethrough?: boolean\n obfuscated?: boolean\n /**\n * When the text is shift-clicked by a player, this string is inserted in their chat input. It does not overwrite any existing text the player was writing.\n */\n insertion?: string\n /**\n * Allows for events to occur when the player clicks on text.\n */\n clickEvent?: {\n /**\n * The action to perform when clicked.\n * Valid values are\n * - \"open_url\" (opens value as a URL in the player's default web browser),\n * - \"open_file\" (opens the value file on the user's computer),\n * - \"run_command\" (has value entered in chat as though the player typed it themselves. This can be used to run commands, provided the player has the required permissions),\n * - \"change_page\" (can be used only in written books) changes to page value if that page exists,\n * - \"suggest_command\" (similar to \"run_command\" but it cannot be used in a written book, the text appears only in the player's chat input and it is not automatically entered. Unlike insertion, this replaces the existing contents of the chat input),\n * - \"copy_to_clipboard\"\u200C[upcoming: 1.15] (copy the value to the clipboard). \"open_file\" is used in messages automatically generated by the game (e.g. on taking a screenshot) and cannot be used in commands or signs.\n */\n action: ClickEventAction\n /**\n * The URL, file, chat, command or book page used by the specified action. Note that commands must be prefixed with the usual \"/\" slash.\n */\n value: string\n }\n hoverEvent?: {\n /**\n * The type of tooltip to show. Valid values are\n * - \"show_text\" (shows raw JSON text),\n * - \"show_item\" (shows the tooltip of an item that can have NBT tags),\n * - \"show_entity\" (shows an entity's name, possibly its type, and its UUID).\n */\n action: HoverEventAction\n /**\n * The formatting of this tag varies depending on the action. Note that \"show_text\" is the only action to support an Object as the value; all other action values are Strings and should thus be wrapped in quotes.\n *\n * - \"show_text\" can be either a raw string of text or an object with the same formatting as this base object. Note that clickEvent and hoverEvent do not function within the tooltip, but the formatting and extra tags still work.\n * - \"show_item\" can be a string formatted like item NBT data. Contains the \"id\" tag, and optionally the \"Damage\" tag and \"tag\" tag (which is the same compound used as \"dataTag\" in the /give command).\n * - \"show_entity\" can be string formatted like a compound with the string values \"type\" (such as \"Zombie\"), \"name\", and \"id\" (should be an entity UUID, but can actually be any string).\n */\n value: string | TextComponent\n }\n}\n\nexport type ClickEventAction = 'open_file' | 'open_url' | 'run_command' | 'suggest_command'\nexport type HoverEventAction = 'show_text' | 'show_item' | 'show_entity'\n\nexport interface Style {\n /**\n * The friendly name of the color, like `light_purple` or `red`\n */\n color?: string\n bold?: boolean\n italic?: boolean\n underlined?: boolean\n strikethrough?: boolean\n obfuscated?: boolean\n}\n\n/**\n * Get Minecraft style code for the style\n */\nexport function getStyleCode(style: TextComponent): string {\n let code = ''\n for (const l of TextFormat.list) {\n if (l.matchStyle(style)) {\n code += l\n }\n }\n return code\n}\n\n/**\n * The renderable node\n */\nexport type RenderNode = {\n /**\n * The css style string\n */\n style: object\n /**\n * The text component backed by\n */\n component: TextComponent\n /**\n * Children\n */\n children: RenderNode[]\n}\n\n/**\n * Get suggest css style object for input style\n */\nexport function getSuggestedStyle(style: TextComponent | Style): object {\n const styledObject: object = {}\n for (const l of TextFormat.list) {\n if (l.matchStyle(style)) {\n Object.assign(styledObject, l.cssForeground)\n }\n }\n return styledObject\n}\n\n/**\n * Render a text component into html style object\n * @returns the render node hint for html/css info\n */\nexport function render(src: TextComponent): RenderNode {\n const children = [] as RenderNode[]\n for (const component of src.extra || []) {\n children.push(render(component))\n }\n return { children, component: src, style: getSuggestedStyle(src) }\n}\n\n/**\n * Flat all components (this component and its children) in this component by DFS into a list.\n * @param component The root component\n */\nexport function flat(component: TextComponent): TextComponent[] {\n const arr: TextComponent[] = [component]\n if (component.extra && component.extra.length !== 0) {\n for (const s of component.extra) {\n arr.push(...flat(s))\n }\n }\n return arr\n}\n\n/**\n * Convert a text component to Minecraft specific formatted string like `\u00A71colored\u00A7r`\n */\nexport function toFormattedString(comp: TextComponent): string {\n let v = ''\n for (const component of flat(comp)) {\n const text = component.text\n if (text.length !== 0) {\n v += `${getStyleCode(component)}${text}${TextFormat.RESET}`\n }\n }\n return v\n}\n\n/**\n * Convert a formatted string to text component json\n * @param formatted The formatted string\n */\nexport function fromFormattedString(formatted: string): TextComponent {\n const firstCode = formatted.indexOf('\u00A7')\n if (firstCode === -1) {\n return { text: formatted }\n }\n\n const textComponent: TextComponent = {\n text: formatted.substring(0, firstCode),\n }\n\n let builder = ''\n const style: Style = {\n bold: false,\n obfuscated: false,\n strikethrough: false,\n underlined: false,\n italic: false,\n color: undefined,\n }\n\n for (let i = firstCode; i < formatted.length; i++) {\n const word = formatted.charCodeAt(i)\n if (word === 167 && i + 1 < formatted.length) {\n if (builder.length !== 0) {\n if (!textComponent.extra) { textComponent.extra = [] }\n textComponent.extra.push({ text: builder, ...style })\n builder = ''\n }\n // apply style\n const format = TextFormat.fromCode(formatted.charAt(i + 1).toLowerCase())\n if (format) { format.applyToStyle(style) }\n ++i // ignore the next char\n } else {\n builder += formatted[i]\n }\n }\n if (builder.length !== 0) {\n if (!textComponent.extra) { textComponent.extra = [] }\n textComponent.extra.push({ text: builder, ...style })\n }\n return textComponent\n}\n\nclass TextFormat<T extends keyof Style> {\n static readonly CONTROL_STRING = '\u00A7'\n constructor(readonly key: T, readonly value: Style[T], readonly name: string, readonly code: string, readonly cssForeground: object, readonly cssBackground?: object) { }\n applyToStyle(style: Style) { style[this.key] = this.value }\n matchStyle(style: Style) { return style[this.key] === this.value }\n\n static readonly BLACK = new TextFormat('color', 'black', 'BLACK', '0', { color: '#000000' }, { color: '#000000' })\n static readonly DARK_BLUE = new TextFormat('color', 'dark_blue', 'DARK_BLUE', '1', { color: '#0000AA' }, { color: '#00002A' })\n static readonly DARK_GREEN = new TextFormat('color', 'dark_green', 'DARK_GREEN', '2', { color: '#00AA00' }, { color: '#002A00' })\n static readonly DARK_AQUA = new TextFormat('color', 'dark_aqua', 'DARK_AQUA', '3', { color: '#00AAAA' }, { color: '#002A2A' })\n static readonly DARK_RED = new TextFormat('color', 'dark_red', 'DARK_RED', '4', { color: '#AA0000' }, { color: '#2A0000' })\n static readonly DARK_PURPLE = new TextFormat('color', 'dark_purple', 'DARK_PURPLE', '5', { color: '#AA00AA' }, { color: '#2A002A' })\n static readonly GOLD = new TextFormat('color', 'gold', 'GOLD', '6', { color: '#FFAA00' }, { color: '#2A2A00' })\n static readonly GRAY = new TextFormat('color', 'gray', 'GRAY', '7', { color: '#AAAAAA' }, { color: '#2A2A2A' })\n static readonly DARK_GRAY = new TextFormat('color', 'dark_gray', 'DARK_GRAY', '8', { color: '#555555' }, { color: '#151515' })\n static readonly BLUE = new TextFormat('color', 'blue', 'BLUE', '9', { color: '#5555FF' }, { color: '#15153F' })\n static readonly GREEN = new TextFormat('color', 'green', 'GREEN', 'a', { color: '#55FF55' }, { color: '#153F15' })\n static readonly AQUA = new TextFormat('color', 'aqua', 'AQUA', 'b', { color: '#55FFFF' }, { color: '#153F3F' })\n static readonly RED = new TextFormat('color', 'red', 'RED', 'c', { color: '#FF5555' }, { color: '#3F1515' })\n static readonly LIGHT_PURPLE = new TextFormat('color', 'light_purple', 'LIGHT_PURPLE', 'd', { color: '#FF55FF' }, { color: '#3F153F' })\n static readonly YELLOW = new TextFormat('color', 'yellow', 'YELLOW', 'e', { color: '#FFFF55' }, { color: '#3F3F15' })\n static readonly WHITE = new TextFormat('color', 'white', 'WHITE', 'f', { color: '#FFFFFF' }, { color: '#3F3F3F' })\n static readonly OBFUSCATED = new TextFormat('obfuscated', true, 'OBFUSCATED', 'k', {})\n static readonly BOLD = new TextFormat('bold', true, 'BOLD', 'l', { 'font-weight': 'bold' })\n static readonly STRIKETHROUGH = new TextFormat('strikethrough', true, 'STRIKETHROUGH', 'm', { 'text-decoration': 'line-through' })\n static readonly UNDERLINE = new TextFormat('underlined', true, 'UNDERLINE', 'n', { 'text-decoration': 'underline' })\n static readonly ITALIC = new TextFormat('italic', true, 'ITALIC', 'o', { 'font-style': 'italic' })\n static readonly RESET = {\n name: 'RESET',\n code: 'r',\n applyToStyle(style: Style) {\n style.bold = false\n style.strikethrough = false\n style.underlined = false\n style.italic = false\n style.obfuscated = false\n style.color = undefined\n },\n matchStyle(style: Style) { return false },\n cssBackground: {},\n cssForeground: {},\n toString() { return `${TextFormat.CONTROL_STRING}r` },\n }\n\n static readonly list = [\n TextFormat.BLACK,\n TextFormat.DARK_BLUE,\n TextFormat.DARK_GREEN,\n TextFormat.DARK_AQUA,\n TextFormat.DARK_RED,\n TextFormat.DARK_PURPLE,\n TextFormat.GOLD,\n TextFormat.GRAY,\n TextFormat.DARK_GRAY,\n TextFormat.BLUE,\n TextFormat.GREEN,\n TextFormat.AQUA,\n TextFormat.RED,\n TextFormat.LIGHT_PURPLE,\n TextFormat.YELLOW,\n TextFormat.WHITE,\n TextFormat.OBFUSCATED,\n TextFormat.BOLD,\n TextFormat.STRIKETHROUGH,\n TextFormat.UNDERLINE,\n TextFormat.ITALIC,\n TextFormat.RESET,\n ]\n\n /**\n * Get the text format from text code\n * @param code The text code character like 0, 1, 2\n * @returns The TextFormat instance\n */\n static fromCode(code: string) {\n const seq = '0123456789abcdefklmnor'\n const index = seq.indexOf(code)\n if (!index) { return undefined }\n return this.list[index]\n }\n\n toString() {\n return `${TextFormat.CONTROL_STRING}${this.code}`\n }\n}\n"],
"mappings": ";;;;;;;;AAyIO,SAAS,aAAa,OAA8B;AACzD,MAAI,OAAO;AACX,aAAW,KAAK,WAAW,MAAM;AAC/B,QAAI,EAAE,WAAW,KAAK,GAAG;AACvB,cAAQ;AAAA,IACV;AAAA,EACF;AACA,SAAO;AACT;AAuBO,SAAS,kBAAkB,OAAsC;AACtE,QAAM,eAAuB,CAAC;AAC9B,aAAW,KAAK,WAAW,MAAM;AAC/B,QAAI,EAAE,WAAW,KAAK,GAAG;AACvB,aAAO,OAAO,cAAc,EAAE,aAAa;AAAA,IAC7C;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,OAAO,KAAgC;AACrD,QAAM,WAAW,CAAC;AAClB,aAAW,aAAa,IAAI,SAAS,CAAC,GAAG;AACvC,aAAS,KAAK,OAAO,SAAS,CAAC;AAAA,EACjC;AACA,SAAO,EAAE,UAAU,WAAW,KAAK,OAAO,kBAAkB,GAAG,EAAE;AACnE;AAMO,SAAS,KAAK,WAA2C;AAC9D,QAAM,MAAuB,CAAC,SAAS;AACvC,MAAI,UAAU,SAAS,UAAU,MAAM,WAAW,GAAG;AACnD,eAAW,KAAK,UAAU,OAAO;AAC/B,UAAI,KAAK,GAAG,KAAK,CAAC,CAAC;AAAA,IACrB;AAAA,EACF;AACA,SAAO;AACT;AAKO,SAAS,kBAAkB,MAA6B;AAC7D,MAAI,IAAI;AACR,aAAW,aAAa,KAAK,IAAI,GAAG;AAClC,UAAM,OAAO,UAAU;AACvB,QAAI,KAAK,WAAW,GAAG;AACrB,WAAK,GAAG,aAAa,SAAS,IAAI,OAAO,WAAW;AAAA,IACtD;AAAA,EACF;AACA,SAAO;AACT;AAMO,SAAS,oBAAoB,WAAkC;AACpE,QAAM,YAAY,UAAU,QAAQ,MAAG;AACvC,MAAI,cAAc,IAAI;AACpB,WAAO,EAAE,MAAM,UAAU;AAAA,EAC3B;AAEA,QAAM,gBAA+B;AAAA,IACnC,MAAM,UAAU,UAAU,GAAG,SAAS;AAAA,EACxC;AAEA,MAAI,UAAU;AACd,QAAM,QAAe;AAAA,IACnB,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,eAAe;AAAA,IACf,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,OAAO;AAAA,EACT;AAEA,WAAS,IAAI,WAAW,IAAI,UAAU,QAAQ,KAAK;AACjD,UAAM,OAAO,UAAU,WAAW,CAAC;AACnC,QAAI,SAAS,OAAO,IAAI,IAAI,UAAU,QAAQ;AAC5C,UAAI,QAAQ,WAAW,GAAG;AACxB,YAAI,CAAC,cAAc,OAAO;AAAE,wBAAc,QAAQ,CAAC;AAAA,QAAE;AACrD,sBAAc,MAAM,KAAK,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC;AACpD,kBAAU;AAAA,MACZ;AAEA,YAAM,SAAS,WAAW,SAAS,UAAU,OAAO,IAAI,CAAC,EAAE,YAAY,CAAC;AACxE,UAAI,QAAQ;AAAE,eAAO,aAAa,KAAK;AAAA,MAAE;AACzC,QAAE;AAAA,IACJ,OAAO;AACL,iBAAW,UAAU,CAAC;AAAA,IACxB;AAAA,EACF;AACA,MAAI,QAAQ,WAAW,GAAG;AACxB,QAAI,CAAC,cAAc,OAAO;AAAE,oBAAc,QAAQ,CAAC;AAAA,IAAE;AACrD,kBAAc,MAAM,KAAK,EAAE,MAAM,SAAS,GAAG,MAAM,CAAC;AAAA,EACtD;AACA,SAAO;AACT;AAEA,IAAM,cAAN,MAAwC;AAAA,EAEtC,YAAqB,KAAiB,OAA0B,MAAuB,MAAuB,eAAgC,eAAwB;AAAjJ;AAAiB;AAA0B;AAAuB;AAAuB;AAAgC;AAAA,EAA0B;AAAA,EACxK,aAAa,OAAc;AAAE,UAAM,KAAK,GAAG,IAAI,KAAK;AAAA,EAAM;AAAA,EAC1D,WAAW,OAAc;AAAE,WAAO,MAAM,KAAK,GAAG,MAAM,KAAK;AAAA,EAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAsEjE,OAAO,SAAS,MAAc;AAC5B,UAAM,MAAM;AACZ,UAAM,QAAQ,IAAI,QAAQ,IAAI;AAC9B,QAAI,CAAC,OAAO;AAAE,aAAO;AAAA,IAAU;AAC/B,WAAO,KAAK,KAAK,KAAK;AAAA,EACxB;AAAA,EAEA,WAAW;AACT,WAAO,GAAG,YAAW,iBAAiB,KAAK;AAAA,EAC7C;AACF;AApFA,IAAM,aAAN;AACE,cADI,YACY,kBAAiB;AAKjC,cANI,YAMY,SAAQ,IAAI,YAAW,SAAS,SAAS,SAAS,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACjH,cAPI,YAOY,aAAY,IAAI,YAAW,SAAS,aAAa,aAAa,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC7H,cARI,YAQY,cAAa,IAAI,YAAW,SAAS,cAAc,cAAc,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAChI,cATI,YASY,aAAY,IAAI,YAAW,SAAS,aAAa,aAAa,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC7H,cAVI,YAUY,YAAW,IAAI,YAAW,SAAS,YAAY,YAAY,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC1H,cAXI,YAWY,eAAc,IAAI,YAAW,SAAS,eAAe,eAAe,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACnI,cAZI,YAYY,QAAO,IAAI,YAAW,SAAS,QAAQ,QAAQ,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC9G,cAbI,YAaY,QAAO,IAAI,YAAW,SAAS,QAAQ,QAAQ,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC9G,cAdI,YAcY,aAAY,IAAI,YAAW,SAAS,aAAa,aAAa,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC7H,cAfI,YAeY,QAAO,IAAI,YAAW,SAAS,QAAQ,QAAQ,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC9G,cAhBI,YAgBY,SAAQ,IAAI,YAAW,SAAS,SAAS,SAAS,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACjH,cAjBI,YAiBY,QAAO,IAAI,YAAW,SAAS,QAAQ,QAAQ,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC9G,cAlBI,YAkBY,OAAM,IAAI,YAAW,SAAS,OAAO,OAAO,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AAC3G,cAnBI,YAmBY,gBAAe,IAAI,YAAW,SAAS,gBAAgB,gBAAgB,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACtI,cApBI,YAoBY,UAAS,IAAI,YAAW,SAAS,UAAU,UAAU,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACpH,cArBI,YAqBY,SAAQ,IAAI,YAAW,SAAS,SAAS,SAAS,KAAK,EAAE,OAAO,UAAU,GAAG,EAAE,OAAO,UAAU,CAAC;AACjH,cAtBI,YAsBY,cAAa,IAAI,YAAW,cAAc,MAAM,cAAc,KAAK,CAAC,CAAC;AACrF,cAvBI,YAuBY,QAAO,IAAI,YAAW,QAAQ,MAAM,QAAQ,KAAK,EAAE,eAAe,OAAO,CAAC;AAC1F,cAxBI,YAwBY,iBAAgB,IAAI,YAAW,iBAAiB,MAAM,iBAAiB,KAAK,EAAE,mBAAmB,eAAe,CAAC;AACjI,cAzBI,YAyBY,aAAY,IAAI,YAAW,cAAc,MAAM,aAAa,KAAK,EAAE,mBAAmB,YAAY,CAAC;AACnH,cA1BI,YA0BY,UAAS,IAAI,YAAW,UAAU,MAAM,UAAU,KAAK,EAAE,cAAc,SAAS,CAAC;AACjG,cA3BI,YA2BY,SAAQ;AAAA,EACtB,MAAM;AAAA,EACN,MAAM;AAAA,EACN,aAAa,OAAc;AACzB,UAAM,OAAO;AACb,UAAM,gBAAgB;AACtB,UAAM,aAAa;AACnB,UAAM,SAAS;AACf,UAAM,aAAa;AACnB,UAAM,QAAQ;AAAA,EAChB;AAAA,EACA,WAAW,OAAc;AAAE,WAAO;AAAA,EAAM;AAAA,EACxC,eAAe,CAAC;AAAA,EAChB,eAAe,CAAC;AAAA,EAChB,WAAW;AAAE,WAAO,GAAG,YAAW;AAAA,EAAkB;AACtD;AAEA,cA5CI,YA4CY,QAAO;AAAA,EACrB,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AAAA,EACX,YAAW;AACb;",
"names": []
}