Spaces:
Running
Running
{ | |
"version": 3, | |
"sources": ["../../../server/chat-plugins/hangman.ts"], | |
"sourcesContent": ["/*\n* Hangman chat plugin\n* By bumbadadabum and Zarel. Art by crobat.\n*/\nimport { FS, Utils } from '../../lib';\n\nconst HANGMAN_FILE = 'config/chat-plugins/hangman.json';\n\nconst DIACRITICS_AFTER_UNDERSCORE = /_[\\u0300-\\u036f\\u0483-\\u0489\\u0610-\\u0615\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06ED\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E]+/g;\nconst MAX_HANGMAN_LENGTH = 30;\nconst MAX_INDIVIDUAL_WORD_LENGTH = 20;\nconst MAX_HINT_LENGTH = 150;\n\ninterface HangmanEntry {\n\thints: string[];\n\ttags?: string[];\n}\n\n// futureproofing this into one single object so that new params can be added\n// more easily\ninterface HangmanOptions {\n\tallowCreator?: boolean;\n}\n\nexport let hangmanData: { [roomid: string]: { [phrase: string]: HangmanEntry } } = {};\n\ntry {\n\thangmanData = JSON.parse(FS(HANGMAN_FILE).readSync());\n\tlet save = false;\n\tfor (const roomid in hangmanData) {\n\t\tconst roomData = hangmanData[roomid] || {};\n\t\tconst roomKeys = Object.keys(roomData);\n\t\tif (roomKeys.length && !roomData[roomKeys[0]].hints) {\n\t\t\tsave = true;\n\t\t\tfor (const key of roomKeys) {\n\t\t\t\troomData[key] = { hints: roomData[key] as any };\n\t\t\t}\n\t\t}\n\t}\n\tif (save) {\n\t\tFS(HANGMAN_FILE).writeUpdate(() => JSON.stringify(hangmanData));\n\t}\n} catch {}\n\nconst maxMistakes = 6;\n\nexport class Hangman extends Rooms.SimpleRoomGame {\n\toverride readonly gameid = 'hangman' as ID;\n\tgameNumber: number;\n\tcreator: ID;\n\tword: string;\n\thint: string;\n\tincorrectGuesses: number;\n\toptions: HangmanOptions;\n\n\tguesses: string[];\n\tletterGuesses: string[];\n\tlastGuesser: string;\n\twordSoFar: string[];\n\treadonly checkChat = true;\n\n\tconstructor(\n\t\troom: Room,\n\t\tuser: User,\n\t\tword: string,\n\t\thint = '',\n\t\tgameOptions: HangmanOptions = {}\n\t) {\n\t\tsuper(room);\n\n\t\tthis.gameNumber = room.nextGameNumber();\n\n\t\tthis.title = 'Hangman';\n\t\tthis.creator = user.id;\n\t\tthis.word = word;\n\t\tthis.hint = hint;\n\t\tthis.incorrectGuesses = 0;\n\t\tthis.options = gameOptions;\n\n\t\tthis.guesses = [];\n\t\tthis.letterGuesses = [];\n\t\tthis.lastGuesser = '';\n\t\tthis.wordSoFar = [];\n\n\t\tfor (const letter of word) {\n\t\t\tif (/[a-zA-Z]/.test(letter)) {\n\t\t\t\tthis.wordSoFar.push('_');\n\t\t\t} else {\n\t\t\t\tthis.wordSoFar.push(letter);\n\t\t\t}\n\t\t}\n\t}\n\n\tchoose(user: User, word: string) {\n\t\tif (user.id === this.creator && !this.options.allowCreator) {\n\t\t\tthrow new Chat.ErrorMessage(\"You can't guess in your own hangman game.\");\n\t\t}\n\n\t\tconst sanitized = word.replace(/[^A-Za-z ]/g, '');\n\t\tconst normalized = toID(sanitized);\n\t\tif (normalized.length < 1) {\n\t\t\tthrow new Chat.ErrorMessage(`Use \"/guess [letter]\" to guess a letter, or \"/guess [phrase]\" to guess the entire Hangman phrase.`);\n\t\t}\n\t\tif (sanitized.length > MAX_HANGMAN_LENGTH) {\n\t\t\tthrow new Chat.ErrorMessage(`Guesses must be ${MAX_HANGMAN_LENGTH} or fewer letters \u2013 \"${word}\" is too long.`);\n\t\t}\n\n\t\tfor (const guessid of this.guesses) {\n\t\t\tif (normalized === toID(guessid)) throw new Chat.ErrorMessage(`Your guess \"${word}\" has already been guessed.`);\n\t\t}\n\n\t\tif (sanitized.length > 1) {\n\t\t\tif (!this.guessWord(sanitized, user.name)) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Your guess \"${sanitized}\" is invalid.`);\n\t\t\t} else {\n\t\t\t\tthis.room.addByUser(user, `${user.name} guessed \"${sanitized}\"!`);\n\t\t\t}\n\t\t} else {\n\t\t\tif (!this.guessLetter(sanitized, user.name)) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Your guess \"${sanitized}\" is not a valid letter.`);\n\t\t\t}\n\t\t}\n\t}\n\n\tguessLetter(letter: string, guesser: string) {\n\t\tletter = letter.toUpperCase();\n\t\tif (this.guesses.includes(letter)) return false;\n\t\tif (this.word.toUpperCase().includes(letter)) {\n\t\t\tfor (let i = 0; i < this.word.length; i++) {\n\t\t\t\tif (this.word[i].toUpperCase() === letter) {\n\t\t\t\t\tthis.wordSoFar[i] = this.word[i];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!this.wordSoFar.includes('_')) {\n\t\t\t\tthis.incorrectGuesses = -1;\n\t\t\t\tthis.guesses.push(letter);\n\t\t\t\tthis.letterGuesses.push(`${letter}1`);\n\t\t\t\tthis.lastGuesser = guesser;\n\t\t\t\tthis.finish();\n\t\t\t\treturn true;\n\t\t\t}\n\t\t\tthis.letterGuesses.push(`${letter}1`);\n\t\t} else {\n\t\t\tthis.incorrectGuesses++;\n\t\t\tthis.letterGuesses.push(`${letter}0`);\n\t\t}\n\n\t\tthis.guesses.push(letter);\n\t\tthis.lastGuesser = guesser;\n\t\tthis.update();\n\t\treturn true;\n\t}\n\n\tguessWord(word: string, guesser: string) {\n\t\tconst ourWord = toID(this.word.replace(/[0-9]+/g, ''));\n\t\tconst guessedWord = toID(word.replace(/[0-9]+/g, ''));\n\t\tconst wordSoFar = this.wordSoFar.filter(letter => /[a-zA-Z_]/.test(letter)).join('').toLowerCase();\n\n\t\t// Can't be a correct guess if the lengths don't match\n\t\tif (ourWord.length !== guessedWord.length) return false;\n\n\t\tfor (let i = 0; i < ourWord.length; i++) {\n\t\t\tif (wordSoFar.charAt(i) === '_') {\n\t\t\t\t// Can't be a correct guess if it contains letters already guessed\n\t\t\t\tif (this.letterGuesses.some(guess => guess.toLowerCase().startsWith(guessedWord.charAt(i)))) return false;\n\t\t\t} else if (wordSoFar.charAt(i) !== guessedWord.charAt(i)) {\n\t\t\t\t// Can't be a correct guess if the guess has incorrect letters in already guessed indexes\n\t\t\t\treturn false;\n\t\t\t}\n\t\t}\n\n\t\tif (ourWord === guessedWord) {\n\t\t\tfor (const [i, letter] of this.wordSoFar.entries()) {\n\t\t\t\tif (letter === '_') {\n\t\t\t\t\tthis.wordSoFar[i] = this.word[i];\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.incorrectGuesses = -1;\n\t\t\tthis.guesses.push(word);\n\t\t\tthis.lastGuesser = guesser;\n\t\t\tthis.finish();\n\t\t} else {\n\t\t\tthis.incorrectGuesses++;\n\t\t\tthis.guesses.push(word);\n\t\t\tthis.lastGuesser = guesser;\n\t\t\tthis.update();\n\t\t}\n\t\treturn true;\n\t}\n\n\thangingMan() {\n\t\treturn `<img width=\"120\" height=\"120\" src=\"//${Config.routes.client}/fx/hangman${this.incorrectGuesses === -1 ? 7 : this.incorrectGuesses}.png\" />`;\n\t}\n\n\tgenerateWindow() {\n\t\tlet result = 0;\n\n\t\tif (this.incorrectGuesses === maxMistakes) {\n\t\t\tresult = 1;\n\t\t} else if (!this.wordSoFar.includes('_')) {\n\t\t\tresult = 2;\n\t\t}\n\n\t\tconst color = result === 1 ? 'red' : (result === 2 ? 'green' : 'blue');\n\t\tconst message = `${result === 1 ? 'Too bad! The mon has been hanged.' : (result === 2 ? 'The word has been guessed. Congratulations!' : 'Hangman')}`;\n\t\tlet output = `<div class=\"broadcast-${color}\">`;\n\t\toutput += `<p style=\"text-align:left;font-weight:bold;font-size:10pt;margin:5px 0 0 15px\">${message}</p>`;\n\t\toutput += `<table><tr><td style=\"text-align:center;\">${this.hangingMan()}</td><td style=\"text-align:center;width:100%;word-wrap:break-word\">`;\n\n\t\tlet escapedWord = this.wordSoFar.map(Utils.escapeHTML);\n\t\tif (result === 1) {\n\t\t\tconst word = this.word;\n\t\t\tescapedWord = escapedWord.map((letter, index) =>\n\t\t\t\tletter === '_' ? `<font color=\"#7af87a\">${word.charAt(index)}</font>` : letter);\n\t\t}\n\t\tconst wordString = escapedWord.join('').replace(DIACRITICS_AFTER_UNDERSCORE, '_');\n\n\t\tif (this.hint) output += Utils.html`<div>(Hint: ${this.hint})</div>`;\n\t\toutput += `<p style=\"font-weight:bold;font-size:12pt;letter-spacing:3pt\">${wordString}</p>`;\n\t\tif (this.guesses.length) {\n\t\t\tif (this.letterGuesses.length) {\n\t\t\t\toutput += 'Letters: ' + this.letterGuesses.map(\n\t\t\t\t\tg => `<strong${g[1] === '1' ? '' : ' style=\"color: #DBA\"'}>${g[0]}</strong>`\n\t\t\t\t).join(', ');\n\t\t\t}\n\t\t\tif (result === 2) {\n\t\t\t\toutput += Utils.html`<br />Winner: ${this.lastGuesser}`;\n\t\t\t} else if (this.guesses[this.guesses.length - 1].length === 1) {\n\t\t\t\t// last guess was a letter\n\t\t\t\toutput += Utils.html` <small>– ${this.lastGuesser}</small>`;\n\t\t\t} else {\n\t\t\t\toutput += Utils.html`<br />Guessed: ${this.guesses[this.guesses.length - 1]} ` +\n\t\t\t\t\t`<small>– ${this.lastGuesser}</small>`;\n\t\t\t}\n\t\t}\n\n\t\toutput += '</td></tr></table></div>';\n\n\t\treturn output;\n\t}\n\n\tdisplay(user: User, broadcast = false) {\n\t\tif (broadcast) {\n\t\t\tthis.room.add(`|uhtml|hangman${this.gameNumber}|${this.generateWindow()}`);\n\t\t} else {\n\t\t\tuser.sendTo(this.room, `|uhtml|hangman${this.gameNumber}|${this.generateWindow()}`);\n\t\t}\n\t}\n\n\tupdate() {\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, this.generateWindow());\n\n\t\tif (this.incorrectGuesses === maxMistakes) {\n\t\t\tthis.finish();\n\t\t}\n\t}\n\n\tend() {\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, '<div class=\"infobox\">(The game of hangman was ended.)</div>');\n\t\tthis.room.add(\"The game of hangman was ended.\");\n\t\tthis.room.game = null;\n\t}\n\n\tfinish() {\n\t\tthis.room.uhtmlchange(`hangman${this.gameNumber}`, '<div class=\"infobox\">(The game of hangman has ended – scroll down to see the results)</div>');\n\t\tthis.room.add(`|html|${this.generateWindow()}`);\n\t\tthis.room.game = null;\n\t}\n\tstatic save() {\n\t\tFS(HANGMAN_FILE).writeUpdate(() => JSON.stringify(hangmanData));\n\t}\n\tstatic getRandom(room: RoomID, tag?: string) {\n\t\tif (!hangmanData[room]) {\n\t\t\thangmanData[room] = {};\n\t\t\tthis.save();\n\t\t}\n\t\tlet phrases = Object.keys(hangmanData[room]);\n\t\tif (!phrases.length) throw new Chat.ErrorMessage(`The room ${room} has no saved hangman words.`);\n\t\tif (tag) {\n\t\t\ttag = toID(tag);\n\t\t\tphrases = phrases.filter(key => hangmanData[room][key].tags?.map(toID).includes(tag as ID));\n\t\t\tif (!phrases.length) {\n\t\t\t\tthrow new Chat.ErrorMessage(`No terms found with tag ${tag}`);\n\t\t\t}\n\t\t}\n\n\t\tconst shuffled = Utils.randomElement(phrases);\n\t\tconst entry = hangmanData[room][shuffled];\n\t\treturn {\n\t\t\tquestion: shuffled,\n\t\t\thint: Utils.randomElement(entry.hints),\n\t\t};\n\t}\n\tstatic validateParams(params: string[]) {\n\t\t// NFD splits diacritics apart from letters, allowing the letters to be guessed\n\t\t// underscore is used to signal \"letter hasn't been guessed yet\", so replace it with Japanese underscore as a workaround\n\t\tconst phrase = params[0].normalize('NFD').trim().replace(/_/g, '\\uFF3F');\n\n\t\tif (!phrase.length) throw new Chat.ErrorMessage(\"Enter a valid word\");\n\t\tif (phrase.length > MAX_HANGMAN_LENGTH) {\n\t\t\tthrow new Chat.ErrorMessage(`Phrase must be less than ${MAX_HANGMAN_LENGTH} characters long.`);\n\t\t}\n\t\tif (phrase.split(' ').some(w => w.length > MAX_INDIVIDUAL_WORD_LENGTH)) {\n\t\t\tthrow new Chat.ErrorMessage(`Each word in the phrase must be less than ${MAX_INDIVIDUAL_WORD_LENGTH} characters long.`);\n\t\t}\n\t\tif (!/[a-zA-Z]/.test(phrase)) throw new Chat.ErrorMessage(\"Word must contain at least one letter.\");\n\t\tlet hint;\n\t\tif (params.length > 1) {\n\t\t\thint = params.slice(1).join(',').trim();\n\t\t\tif (hint.length > MAX_HINT_LENGTH) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Hint must be less than ${MAX_HINT_LENGTH} characters long.`);\n\t\t\t}\n\t\t}\n\t\treturn { phrase, hint };\n\t}\n}\n\nexport const commands: Chat.ChatCommands = {\n\thangman: {\n\t\tcreate: 'new',\n\t\tnew(target, room, user, connection) {\n\t\t\troom = this.requireRoom();\n\t\t\ttarget = target.trim();\n\t\t\tconst text = this.filter(target);\n\t\t\tif (target !== text) return this.errorReply(\"You are not allowed to use filtered words in hangmans.\");\n\t\t\tconst params = text.split(',');\n\n\t\t\tthis.checkCan('minigame', null, room);\n\t\t\tif (room.settings.hangmanDisabled) return this.errorReply(\"Hangman is disabled for this room.\");\n\t\t\tthis.checkChat();\n\t\t\tif (room.game) return this.errorReply(`There is already a game of ${room.game.title} in progress in this room.`);\n\n\t\t\tif (!params) return this.errorReply(\"No word entered.\");\n\t\t\tconst { phrase, hint } = Hangman.validateParams(params);\n\n\t\t\tconst game = new Hangman(room, user, phrase, hint);\n\t\t\troom.game = game;\n\t\t\tgame.display(user, true);\n\n\t\t\tthis.modlog('HANGMAN');\n\t\t\treturn this.addModAction(`A game of hangman was started by ${user.name} \u2013 use /guess to play!`);\n\t\t},\n\t\tcreatehelp: [\"/hangman create [word], [hint] - Makes a new hangman game. Requires: % @ # ~\"],\n\n\t\tguess(target, room, user) {\n\t\t\tconst word = this.filter(target);\n\t\t\tif (word !== target) return this.errorReply(`You may not use filtered words in guesses.`);\n\t\t\tthis.parse(`/choose ${target}`);\n\t\t},\n\t\tguesshelp: [\n\t\t\t`/guess [letter] - Makes a guess for the letter entered.`,\n\t\t\t`/guess [word] - Same as a letter, but guesses an entire word.`,\n\t\t],\n\n\t\tstop: 'end',\n\t\tend(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('minigame', null, room);\n\t\t\tthis.checkChat();\n\t\t\tconst game = this.requireGame(Hangman);\n\t\t\tgame.end();\n\t\t\tthis.modlog('ENDHANGMAN');\n\t\t\treturn this.privateModAction(`The game of hangman was ended by ${user.name}.`);\n\t\t},\n\t\tendhelp: [\"/hangman end - Ends the game of hangman before the man is hanged or word is guessed. Requires: % @ # ~\"],\n\n\t\tdisable(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('gamemanagement', null, room);\n\t\t\tif (room.settings.hangmanDisabled) {\n\t\t\t\treturn this.errorReply(\"Hangman is already disabled.\");\n\t\t\t}\n\t\t\troom.settings.hangmanDisabled = true;\n\t\t\troom.saveSettings();\n\t\t\treturn this.sendReply(\"Hangman has been disabled for this room.\");\n\t\t},\n\n\t\tenable(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('gamemanagement', null, room);\n\t\t\tif (!room.settings.hangmanDisabled) {\n\t\t\t\treturn this.errorReply(\"Hangman is already enabled.\");\n\t\t\t}\n\t\t\tdelete room.settings.hangmanDisabled;\n\t\t\troom.saveSettings();\n\t\t\treturn this.sendReply(\"Hangman has been enabled for this room.\");\n\t\t},\n\n\t\tdisplay(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tconst game = this.requireGame(Hangman);\n\t\t\tif (!this.runBroadcast()) return;\n\t\t\troom.update();\n\n\t\t\tgame.display(user, this.broadcasting);\n\t\t},\n\n\t\t''(target, room, user) {\n\t\t\treturn this.parse('/help hangman');\n\t\t},\n\n\t\trandom(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('mute', null, room);\n\t\t\tif (room.game) {\n\t\t\t\tthrow new Chat.ErrorMessage(`There is already a game of ${room.game.title} running.`);\n\t\t\t}\n\t\t\ttarget = toID(target);\n\t\t\tconst { question, hint } = Hangman.getRandom(room.roomid, target);\n\t\t\tconst game = new Hangman(room, user, question, hint, { allowCreator: true });\n\t\t\troom.game = game;\n\t\t\tthis.addModAction(`${user.name} started a random game of hangman - use /guess to play!`);\n\t\t\tgame.display(user, true);\n\t\t\tthis.modlog(`HANGMAN RANDOM`, null, target ? `tag: ${target}` : '');\n\t\t},\n\t\taddrandom(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('mute', null, room);\n\t\t\tif (!hangmanData[room.roomid]) hangmanData[room.roomid] = {};\n\t\t\tif (!target) return this.parse('/help hangman');\n\t\t\t// validation\n\t\t\tconst args = target.split(target.includes('|') ? '|' : ',');\n\t\t\tconst { phrase } = Hangman.validateParams(args);\n\t\t\tif (!hangmanData[room.roomid][phrase]) hangmanData[room.roomid][phrase] = { hints: [] };\n\t\t\targs.shift();\n\t\t\thangmanData[room.roomid][phrase].hints.push(...args);\n\t\t\tHangman.save();\n\t\t\tthis.privateModAction(`${user.name} added a random hangman with ${Chat.count(args.length, 'hints')}.`);\n\t\t\tthis.modlog(`HANGMAN ADDRANDOM`, null, `${phrase}: ${args.join(', ')}`);\n\t\t},\n\t\trr: 'removerandom',\n\t\tremoverandom(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('mute', null, room);\n\t\t\tlet [word, ...hints] = target.split(',');\n\t\t\tif (!toID(target) || !word) return this.parse('/help hangman');\n\t\t\tfor (const [i, hint] of hints.entries()) {\n\t\t\t\tif (hint.startsWith('room:')) {\n\t\t\t\t\tconst newID = hint.slice(5);\n\t\t\t\t\tconst targetRoom = Rooms.search(newID);\n\t\t\t\t\tif (!targetRoom) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid room: ${newID}`);\n\t\t\t\t\t}\n\t\t\t\t\tthis.room = targetRoom;\n\t\t\t\t\troom = targetRoom;\n\t\t\t\t\thints.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid]) {\n\t\t\t\treturn this.errorReply(\"There are no hangman words for this room.\");\n\t\t\t}\n\t\t\tconst roomKeys = Object.keys(hangmanData[room.roomid]);\n\t\t\tconst roomKeyIDs = roomKeys.map(toID);\n\t\t\tconst index = roomKeyIDs.indexOf(toID(word));\n\t\t\tif (index < 0) {\n\t\t\t\treturn this.errorReply(`That word is not a saved hangman.`);\n\t\t\t}\n\t\t\tword = roomKeys[index];\n\t\t\thints = hints.map(toID);\n\n\t\t\tif (!hints.length) {\n\t\t\t\tdelete hangmanData[room.roomid][word];\n\t\t\t\tthis.privateModAction(`${user.name} deleted the hangman entry for '${word}'`);\n\t\t\t\tthis.modlog(`HANGMAN REMOVERANDOM`, null, word);\n\t\t\t} else {\n\t\t\t\thangmanData[room.roomid][word].hints = hangmanData[room.roomid][word].hints.filter(item => !hints.includes(toID(item)));\n\t\t\t\tif (!hangmanData[room.roomid][word].hints.length) {\n\t\t\t\t\tdelete hangmanData[room.roomid][word];\n\t\t\t\t}\n\t\t\t\tthis.privateModAction(`${user.name} deleted ${Chat.count(hints, 'hints')} for the hangman term '${word}'`);\n\t\t\t\tthis.modlog(`HANGMAN REMOVERANDOM`, null, `${word}: ${hints.join(', ')}`);\n\t\t\t}\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\n\t\t\tHangman.save();\n\t\t},\n\t\taddtag(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('mute', null, room);\n\t\t\tlet [term, ...tags] = target.split(',');\n\t\t\t// only a .trim() because toID will make it unable to find the term if it has caps\n\t\t\tterm = term.trim();\n\t\t\ttags = tags.map(i => toID(i)).filter(Boolean);\n\t\t\tif (!term || !tags?.length) {\n\t\t\t\treturn this.parse('/help hangman');\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid]) {\n\t\t\t\thangmanData[room.roomid] = {};\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid][term]) {\n\t\t\t\treturn this.errorReply(`Term ${term} not found.`);\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid][term].tags) hangmanData[room.roomid][term].tags = [];\n\t\t\tfor (const [i, tag] of tags.entries()) {\n\t\t\t\tif (hangmanData[room.roomid][term].tags!.includes(tag)) {\n\t\t\t\t\tthis.errorReply(`The tag ${tag} is already on the term ${term} and has been skipped.`);\n\t\t\t\t\ttags.splice(i, 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!tags.length) {\n\t\t\t\tthis.errorReply(`Specify at least one valid tag.`);\n\t\t\t\treturn this.parse(`/help hangman`);\n\t\t\t}\n\t\t\thangmanData[room.roomid][term].tags!.push(...tags);\n\t\t\tHangman.save();\n\t\t\tthis.privateModAction(`${user.name} added ${Chat.count(tags, \"tags\")} to the hangman term ${term}`);\n\t\t\tthis.modlog(`HANGMAN ADDTAG`, null, `${term}: ${tags.map(Utils.escapeHTML).join(', ')}`);\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\n\t\t},\n\t\tuntag(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\tthis.checkCan('mute', null, room);\n\t\t\tif (!toID(target)) {\n\t\t\t\treturn this.parse(`/help hangman`);\n\t\t\t}\n\t\t\tlet [term, ...tags] = target.split(',');\n\t\t\ttags = tags.map(i => toID(i)).filter(Boolean);\n\t\t\tif (!term || !tags) {\n\t\t\t\treturn this.parse('/help hangman');\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid]) {\n\t\t\t\treturn this.errorReply(`This room has no hangman terms.`);\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid][term]) {\n\t\t\t\treturn this.errorReply(`That term was not found.`);\n\t\t\t}\n\t\t\tif (!hangmanData[room.roomid][term].tags) {\n\t\t\t\treturn this.errorReply(`That term has no tags.`);\n\t\t\t}\n\t\t\tif (tags.length) {\n\t\t\t\tthis.privateModAction(`${user.name} removed ${Chat.count(tags, \"tags\")} from the hangman term ${term}`);\n\t\t\t\tthis.modlog(`HANGMAN UNTAG`, null, `${term}: ${tags.map(Utils.escapeHTML).join(', ')}`);\n\t\t\t\thangmanData[room.roomid][term].tags = hangmanData[room.roomid][term].tags?.filter(t => !tags.includes(t));\n\t\t\t} else {\n\t\t\t\tthis.privateModAction(`${user.name} removed all tags from the hangman term ${term}`);\n\t\t\t\tthis.modlog(`HANGMAN UNTAG`, null, `${term}`);\n\t\t\t\thangmanData[room.roomid][term].tags = [];\n\t\t\t}\n\n\t\t\tif (!hangmanData[room.roomid][term].tags!.length) {\n\t\t\t\tdelete hangmanData[room.roomid][term].tags;\n\t\t\t}\n\t\t\tHangman.save();\n\t\t\tthis.refreshPage(`hangman-${room.roomid}`);\n\t\t},\n\t\tview: 'terms',\n\t\tterms(target, room, user) {\n\t\t\troom = this.requireRoom();\n\t\t\treturn this.parse(`/j view-hangman-${target || room.roomid}`);\n\t\t},\n\t},\n\n\thangmanhelp: [\n\t\t`/hangman allows users to play the popular game hangman in PS rooms.`,\n\t\t`Accepts the following commands:`,\n\t\t`/hangman create [word], [hint] - Makes a new hangman game. Requires: % @ # ~`,\n\t\t`/hangman guess [letter] - Makes a guess for the letter entered.`,\n\t\t`/hangman guess [word] - Same as a letter, but guesses an entire word.`,\n\t\t`/hangman display - Displays the game.`,\n\t\t`/hangman end - Ends the game of hangman before the man is hanged or word is guessed. Requires: % @ # ~`,\n\t\t`/hangman [enable/disable] - Enables or disables hangman from being started in a room. Requires: # ~`,\n\t\t`/hangman random [tag]- Runs a random hangman, if the room has any added. `,\n\t\t`If a tag is given, randomizes from only terms with those tags. Requires: % @ # ~`,\n\t\t`/hangman addrandom [word], [...hints] - Adds an entry for [word] with the [hints] provided to the room's hangman pool. Requires: % @ # ~`,\n\t\t`/hangman removerandom [word][, hints] - Removes data from the hangman entry for [word]. If hints are given, removes only those hints.` +\n\t\t` Otherwise it removes the entire entry. Requires: % @ ~ #`,\n\t\t`/hangman addtag [word], [...tags] - Adds tags to the hangman term matching [word]. Requires: % @ ~ #`,\n\t\t`/hangman untag [term][, ...tags] - Removes tags from the hangman [term]. If tags are given, removes only those tags. Requires: % @ # * `,\n\t\t`/hangman terms - Displays all random hangman in a room. Requires: % @ # ~`,\n\t],\n};\n\nexport const pages: Chat.PageTable = {\n\thangman(args, user) {\n\t\tconst room = this.requireRoom();\n\t\tthis.title = `[Hangman]`;\n\t\tthis.checkCan('mute', null, room);\n\t\tlet buf = `<div class=\"pad\"><button style=\"float:right;\" class=\"button\" name=\"send\" value=\"/join view-hangman-${room.roomid}\"><i class=\"fa fa-refresh\"></i> Refresh</button>`;\n\t\tbuf += `<div class=\"pad\"><h2>Hangman entries on ${room.title}</h2>`;\n\t\tconst roomTerms = hangmanData[room.roomid];\n\t\tif (!roomTerms) {\n\t\t\treturn this.errorReply(`No hangman terms found for ${room.title}.`);\n\t\t}\n\t\tfor (const t in roomTerms) {\n\t\t\tbuf += `<div class=\"infobox\">`;\n\t\t\tbuf += `<h3>${t}</h3><hr />`;\n\t\t\tif (user.can('mute', null, room, 'hangman addrandom')) {\n\t\t\t\tbuf += `<strong>Hints:</strong> `;\n\t\t\t\tbuf += roomTerms[t].hints.map(\n\t\t\t\t\thint => `${hint} <button class=\"button\" name=\"send\" value=\"/msgroom ${room.roomid}, /hangman rr ${t},${hint}\" aria-label=\"Delete\"><i class=\"fa fa-trash\"></i></button>`\n\t\t\t\t).join(', ');\n\t\t\t\tbuf += `<button style=\"float:right;\" class=\"button\" name=\"send\" value=\"/msgroom ${room.roomid}, /hangman rr ${t}\"><i class=\"fa fa-trash\"></i> Delete all terms</button>`;\n\t\t\t\tif (roomTerms[t].tags) {\n\t\t\t\t\tbuf += `<br /><strong>Tags: </strong> `;\n\t\t\t\t\tbuf += roomTerms[t].tags?.map(\n\t\t\t\t\t\ttag => `${tag} <button class=\"button\" name=\"send\" value=\"/msgroom ${room.roomid}, /hangman untag ${t},${tag}\" aria-label=\"Delete\"><i class=\"fa fa-trash\"></i></button>`\n\t\t\t\t\t).join(', ');\n\t\t\t\t\tbuf += `<button style=\"float:right;\" class=\"button\" name=\"send\" value=\"/msgroom ${room.roomid}, /hangman untag ${t}\"><i class=\"fa fa-trash\"></i> Delete all tags</button>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += `</div><br />`;\n\t\t}\n\t\tbuf += `</div>`;\n\t\treturn buf;\n\t},\n};\n\nexport const roomSettings: Chat.SettingsHandler = room => ({\n\tlabel: \"Hangman\",\n\tpermission: 'editroom',\n\toptions: [\n\t\t[`disabled`, room.settings.hangmanDisabled || 'hangman disable'],\n\t\t[`enabled`, !room.settings.hangmanDisabled || 'hangman enable'],\n\t],\n});\n"], | |
"mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAIA,iBAA0B;AAE1B,MAAM,eAAe;AAErB,MAAM,8BAA8B;AACpC,MAAM,qBAAqB;AAC3B,MAAM,6BAA6B;AACnC,MAAM,kBAAkB;AAajB,IAAI,cAAwE,CAAC;AAEpF,IAAI;AACH,gBAAc,KAAK,UAAM,eAAG,YAAY,EAAE,SAAS,CAAC;AACpD,MAAI,OAAO;AACX,aAAW,UAAU,aAAa;AACjC,UAAM,WAAW,YAAY,MAAM,KAAK,CAAC;AACzC,UAAM,WAAW,OAAO,KAAK,QAAQ;AACrC,QAAI,SAAS,UAAU,CAAC,SAAS,SAAS,CAAC,CAAC,EAAE,OAAO;AACpD,aAAO;AACP,iBAAW,OAAO,UAAU;AAC3B,iBAAS,GAAG,IAAI,EAAE,OAAO,SAAS,GAAG,EAAS;AAAA,MAC/C;AAAA,IACD;AAAA,EACD;AACA,MAAI,MAAM;AACT,uBAAG,YAAY,EAAE,YAAY,MAAM,KAAK,UAAU,WAAW,CAAC;AAAA,EAC/D;AACD,QAAE;AAAO;AAET,MAAM,cAAc;AAEb,MAAM,gBAAgB,MAAM,eAAe;AAAA,EAejD,YACC,MACA,MACA,MACA,OAAO,IACP,cAA8B,CAAC,GAC9B;AACD,UAAM,IAAI;AArBX,SAAkB,SAAS;AAY3B,SAAS,YAAY;AAWpB,SAAK,aAAa,KAAK,eAAe;AAEtC,SAAK,QAAQ;AACb,SAAK,UAAU,KAAK;AACpB,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,mBAAmB;AACxB,SAAK,UAAU;AAEf,SAAK,UAAU,CAAC;AAChB,SAAK,gBAAgB,CAAC;AACtB,SAAK,cAAc;AACnB,SAAK,YAAY,CAAC;AAElB,eAAW,UAAU,MAAM;AAC1B,UAAI,WAAW,KAAK,MAAM,GAAG;AAC5B,aAAK,UAAU,KAAK,GAAG;AAAA,MACxB,OAAO;AACN,aAAK,UAAU,KAAK,MAAM;AAAA,MAC3B;AAAA,IACD;AAAA,EACD;AAAA,EAEA,OAAO,MAAY,MAAc;AAChC,QAAI,KAAK,OAAO,KAAK,WAAW,CAAC,KAAK,QAAQ,cAAc;AAC3D,YAAM,IAAI,KAAK,aAAa,2CAA2C;AAAA,IACxE;AAEA,UAAM,YAAY,KAAK,QAAQ,eAAe,EAAE;AAChD,UAAM,aAAa,KAAK,SAAS;AACjC,QAAI,WAAW,SAAS,GAAG;AAC1B,YAAM,IAAI,KAAK,aAAa,mGAAmG;AAAA,IAChI;AACA,QAAI,UAAU,SAAS,oBAAoB;AAC1C,YAAM,IAAI,KAAK,aAAa,mBAAmB,+CAA0C,oBAAoB;AAAA,IAC9G;AAEA,eAAW,WAAW,KAAK,SAAS;AACnC,UAAI,eAAe,KAAK,OAAO;AAAG,cAAM,IAAI,KAAK,aAAa,eAAe,iCAAiC;AAAA,IAC/G;AAEA,QAAI,UAAU,SAAS,GAAG;AACzB,UAAI,CAAC,KAAK,UAAU,WAAW,KAAK,IAAI,GAAG;AAC1C,cAAM,IAAI,KAAK,aAAa,eAAe,wBAAwB;AAAA,MACpE,OAAO;AACN,aAAK,KAAK,UAAU,MAAM,GAAG,KAAK,iBAAiB,aAAa;AAAA,MACjE;AAAA,IACD,OAAO;AACN,UAAI,CAAC,KAAK,YAAY,WAAW,KAAK,IAAI,GAAG;AAC5C,cAAM,IAAI,KAAK,aAAa,eAAe,mCAAmC;AAAA,MAC/E;AAAA,IACD;AAAA,EACD;AAAA,EAEA,YAAY,QAAgB,SAAiB;AAC5C,aAAS,OAAO,YAAY;AAC5B,QAAI,KAAK,QAAQ,SAAS,MAAM;AAAG,aAAO;AAC1C,QAAI,KAAK,KAAK,YAAY,EAAE,SAAS,MAAM,GAAG;AAC7C,eAAS,IAAI,GAAG,IAAI,KAAK,KAAK,QAAQ,KAAK;AAC1C,YAAI,KAAK,KAAK,CAAC,EAAE,YAAY,MAAM,QAAQ;AAC1C,eAAK,UAAU,CAAC,IAAI,KAAK,KAAK,CAAC;AAAA,QAChC;AAAA,MACD;AAEA,UAAI,CAAC,KAAK,UAAU,SAAS,GAAG,GAAG;AAClC,aAAK,mBAAmB;AACxB,aAAK,QAAQ,KAAK,MAAM;AACxB,aAAK,cAAc,KAAK,GAAG,SAAS;AACpC,aAAK,cAAc;AACnB,aAAK,OAAO;AACZ,eAAO;AAAA,MACR;AACA,WAAK,cAAc,KAAK,GAAG,SAAS;AAAA,IACrC,OAAO;AACN,WAAK;AACL,WAAK,cAAc,KAAK,GAAG,SAAS;AAAA,IACrC;AAEA,SAAK,QAAQ,KAAK,MAAM;AACxB,SAAK,cAAc;AACnB,SAAK,OAAO;AACZ,WAAO;AAAA,EACR;AAAA,EAEA,UAAU,MAAc,SAAiB;AACxC,UAAM,UAAU,KAAK,KAAK,KAAK,QAAQ,WAAW,EAAE,CAAC;AACrD,UAAM,cAAc,KAAK,KAAK,QAAQ,WAAW,EAAE,CAAC;AACpD,UAAM,YAAY,KAAK,UAAU,OAAO,YAAU,YAAY,KAAK,MAAM,CAAC,EAAE,KAAK,EAAE,EAAE,YAAY;AAGjG,QAAI,QAAQ,WAAW,YAAY;AAAQ,aAAO;AAElD,aAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACxC,UAAI,UAAU,OAAO,CAAC,MAAM,KAAK;AAEhC,YAAI,KAAK,cAAc,KAAK,WAAS,MAAM,YAAY,EAAE,WAAW,YAAY,OAAO,CAAC,CAAC,CAAC;AAAG,iBAAO;AAAA,MACrG,WAAW,UAAU,OAAO,CAAC,MAAM,YAAY,OAAO,CAAC,GAAG;AAEzD,eAAO;AAAA,MACR;AAAA,IACD;AAEA,QAAI,YAAY,aAAa;AAC5B,iBAAW,CAAC,GAAG,MAAM,KAAK,KAAK,UAAU,QAAQ,GAAG;AACnD,YAAI,WAAW,KAAK;AACnB,eAAK,UAAU,CAAC,IAAI,KAAK,KAAK,CAAC;AAAA,QAChC;AAAA,MACD;AACA,WAAK,mBAAmB;AACxB,WAAK,QAAQ,KAAK,IAAI;AACtB,WAAK,cAAc;AACnB,WAAK,OAAO;AAAA,IACb,OAAO;AACN,WAAK;AACL,WAAK,QAAQ,KAAK,IAAI;AACtB,WAAK,cAAc;AACnB,WAAK,OAAO;AAAA,IACb;AACA,WAAO;AAAA,EACR;AAAA,EAEA,aAAa;AACZ,WAAO,wCAAwC,OAAO,OAAO,oBAAoB,KAAK,qBAAqB,KAAK,IAAI,KAAK;AAAA,EAC1H;AAAA,EAEA,iBAAiB;AAChB,QAAI,SAAS;AAEb,QAAI,KAAK,qBAAqB,aAAa;AAC1C,eAAS;AAAA,IACV,WAAW,CAAC,KAAK,UAAU,SAAS,GAAG,GAAG;AACzC,eAAS;AAAA,IACV;AAEA,UAAM,QAAQ,WAAW,IAAI,QAAS,WAAW,IAAI,UAAU;AAC/D,UAAM,UAAU,GAAG,WAAW,IAAI,sCAAuC,WAAW,IAAI,gDAAgD;AACxI,QAAI,SAAS,yBAAyB;AACtC,cAAU,kFAAkF;AAC5F,cAAU,6CAA6C,KAAK,WAAW;AAEvE,QAAI,cAAc,KAAK,UAAU,IAAI,iBAAM,UAAU;AACrD,QAAI,WAAW,GAAG;AACjB,YAAM,OAAO,KAAK;AAClB,oBAAc,YAAY,IAAI,CAAC,QAAQ,UACtC,WAAW,MAAM,yBAAyB,KAAK,OAAO,KAAK,aAAa,MAAM;AAAA,IAChF;AACA,UAAM,aAAa,YAAY,KAAK,EAAE,EAAE,QAAQ,6BAA6B,GAAG;AAEhF,QAAI,KAAK;AAAM,gBAAU,iBAAM,mBAAmB,KAAK;AACvD,cAAU,iEAAiE;AAC3E,QAAI,KAAK,QAAQ,QAAQ;AACxB,UAAI,KAAK,cAAc,QAAQ;AAC9B,kBAAU,cAAc,KAAK,cAAc;AAAA,UAC1C,OAAK,UAAU,EAAE,CAAC,MAAM,MAAM,KAAK,0BAA0B,EAAE,CAAC;AAAA,QACjE,EAAE,KAAK,IAAI;AAAA,MACZ;AACA,UAAI,WAAW,GAAG;AACjB,kBAAU,iBAAM,qBAAqB,KAAK;AAAA,MAC3C,WAAW,KAAK,QAAQ,KAAK,QAAQ,SAAS,CAAC,EAAE,WAAW,GAAG;AAE9D,kBAAU,iBAAM,uBAAuB,KAAK;AAAA,MAC7C,OAAO;AACN,kBAAU,iBAAM,sBAAsB,KAAK,QAAQ,KAAK,QAAQ,SAAS,CAAC,OACzE,kBAAkB,KAAK;AAAA,MACzB;AAAA,IACD;AAEA,cAAU;AAEV,WAAO;AAAA,EACR;AAAA,EAEA,QAAQ,MAAY,YAAY,OAAO;AACtC,QAAI,WAAW;AACd,WAAK,KAAK,IAAI,iBAAiB,KAAK,cAAc,KAAK,eAAe,GAAG;AAAA,IAC1E,OAAO;AACN,WAAK,OAAO,KAAK,MAAM,iBAAiB,KAAK,cAAc,KAAK,eAAe,GAAG;AAAA,IACnF;AAAA,EACD;AAAA,EAEA,SAAS;AACR,SAAK,KAAK,YAAY,UAAU,KAAK,cAAc,KAAK,eAAe,CAAC;AAExE,QAAI,KAAK,qBAAqB,aAAa;AAC1C,WAAK,OAAO;AAAA,IACb;AAAA,EACD;AAAA,EAEA,MAAM;AACL,SAAK,KAAK,YAAY,UAAU,KAAK,cAAc,6DAA6D;AAChH,SAAK,KAAK,IAAI,gCAAgC;AAC9C,SAAK,KAAK,OAAO;AAAA,EAClB;AAAA,EAEA,SAAS;AACR,SAAK,KAAK,YAAY,UAAU,KAAK,cAAc,mGAAmG;AACtJ,SAAK,KAAK,IAAI,SAAS,KAAK,eAAe,GAAG;AAC9C,SAAK,KAAK,OAAO;AAAA,EAClB;AAAA,EACA,OAAO,OAAO;AACb,uBAAG,YAAY,EAAE,YAAY,MAAM,KAAK,UAAU,WAAW,CAAC;AAAA,EAC/D;AAAA,EACA,OAAO,UAAU,MAAc,KAAc;AAC5C,QAAI,CAAC,YAAY,IAAI,GAAG;AACvB,kBAAY,IAAI,IAAI,CAAC;AACrB,WAAK,KAAK;AAAA,IACX;AACA,QAAI,UAAU,OAAO,KAAK,YAAY,IAAI,CAAC;AAC3C,QAAI,CAAC,QAAQ;AAAQ,YAAM,IAAI,KAAK,aAAa,YAAY,kCAAkC;AAC/F,QAAI,KAAK;AACR,YAAM,KAAK,GAAG;AACd,gBAAU,QAAQ,OAAO,SAAO,YAAY,IAAI,EAAE,GAAG,EAAE,MAAM,IAAI,IAAI,EAAE,SAAS,GAAS,CAAC;AAC1F,UAAI,CAAC,QAAQ,QAAQ;AACpB,cAAM,IAAI,KAAK,aAAa,2BAA2B,KAAK;AAAA,MAC7D;AAAA,IACD;AAEA,UAAM,WAAW,iBAAM,cAAc,OAAO;AAC5C,UAAM,QAAQ,YAAY,IAAI,EAAE,QAAQ;AACxC,WAAO;AAAA,MACN,UAAU;AAAA,MACV,MAAM,iBAAM,cAAc,MAAM,KAAK;AAAA,IACtC;AAAA,EACD;AAAA,EACA,OAAO,eAAe,QAAkB;AAGvC,UAAM,SAAS,OAAO,CAAC,EAAE,UAAU,KAAK,EAAE,KAAK,EAAE,QAAQ,MAAM,QAAQ;AAEvE,QAAI,CAAC,OAAO;AAAQ,YAAM,IAAI,KAAK,aAAa,oBAAoB;AACpE,QAAI,OAAO,SAAS,oBAAoB;AACvC,YAAM,IAAI,KAAK,aAAa,4BAA4B,qCAAqC;AAAA,IAC9F;AACA,QAAI,OAAO,MAAM,GAAG,EAAE,KAAK,OAAK,EAAE,SAAS,0BAA0B,GAAG;AACvE,YAAM,IAAI,KAAK,aAAa,6CAA6C,6CAA6C;AAAA,IACvH;AACA,QAAI,CAAC,WAAW,KAAK,MAAM;AAAG,YAAM,IAAI,KAAK,aAAa,wCAAwC;AAClG,QAAI;AACJ,QAAI,OAAO,SAAS,GAAG;AACtB,aAAO,OAAO,MAAM,CAAC,EAAE,KAAK,GAAG,EAAE,KAAK;AACtC,UAAI,KAAK,SAAS,iBAAiB;AAClC,cAAM,IAAI,KAAK,aAAa,0BAA0B,kCAAkC;AAAA,MACzF;AAAA,IACD;AACA,WAAO,EAAE,QAAQ,KAAK;AAAA,EACvB;AACD;AAEO,MAAM,WAA8B;AAAA,EAC1C,SAAS;AAAA,IACR,QAAQ;AAAA,IACR,IAAI,QAAQ,MAAM,MAAM,YAAY;AACnC,aAAO,KAAK,YAAY;AACxB,eAAS,OAAO,KAAK;AACrB,YAAM,OAAO,KAAK,OAAO,MAAM;AAC/B,UAAI,WAAW;AAAM,eAAO,KAAK,WAAW,wDAAwD;AACpG,YAAM,SAAS,KAAK,MAAM,GAAG;AAE7B,WAAK,SAAS,YAAY,MAAM,IAAI;AACpC,UAAI,KAAK,SAAS;AAAiB,eAAO,KAAK,WAAW,oCAAoC;AAC9F,WAAK,UAAU;AACf,UAAI,KAAK;AAAM,eAAO,KAAK,WAAW,8BAA8B,KAAK,KAAK,iCAAiC;AAE/G,UAAI,CAAC;AAAQ,eAAO,KAAK,WAAW,kBAAkB;AACtD,YAAM,EAAE,QAAQ,KAAK,IAAI,QAAQ,eAAe,MAAM;AAEtD,YAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,QAAQ,IAAI;AACjD,WAAK,OAAO;AACZ,WAAK,QAAQ,MAAM,IAAI;AAEvB,WAAK,OAAO,SAAS;AACrB,aAAO,KAAK,aAAa,oCAAoC,KAAK,iCAA4B;AAAA,IAC/F;AAAA,IACA,YAAY,CAAC,8EAA8E;AAAA,IAE3F,MAAM,QAAQ,MAAM,MAAM;AACzB,YAAM,OAAO,KAAK,OAAO,MAAM;AAC/B,UAAI,SAAS;AAAQ,eAAO,KAAK,WAAW,4CAA4C;AACxF,WAAK,MAAM,WAAW,QAAQ;AAAA,IAC/B;AAAA,IACA,WAAW;AAAA,MACV;AAAA,MACA;AAAA,IACD;AAAA,IAEA,MAAM;AAAA,IACN,IAAI,QAAQ,MAAM,MAAM;AACvB,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,YAAY,MAAM,IAAI;AACpC,WAAK,UAAU;AACf,YAAM,OAAO,KAAK,YAAY,OAAO;AACrC,WAAK,IAAI;AACT,WAAK,OAAO,YAAY;AACxB,aAAO,KAAK,iBAAiB,oCAAoC,KAAK,OAAO;AAAA,IAC9E;AAAA,IACA,SAAS,CAAC,wGAAwG;AAAA,IAElH,QAAQ,QAAQ,MAAM,MAAM;AAC3B,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,kBAAkB,MAAM,IAAI;AAC1C,UAAI,KAAK,SAAS,iBAAiB;AAClC,eAAO,KAAK,WAAW,8BAA8B;AAAA,MACtD;AACA,WAAK,SAAS,kBAAkB;AAChC,WAAK,aAAa;AAClB,aAAO,KAAK,UAAU,0CAA0C;AAAA,IACjE;AAAA,IAEA,OAAO,QAAQ,MAAM,MAAM;AAC1B,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,kBAAkB,MAAM,IAAI;AAC1C,UAAI,CAAC,KAAK,SAAS,iBAAiB;AACnC,eAAO,KAAK,WAAW,6BAA6B;AAAA,MACrD;AACA,aAAO,KAAK,SAAS;AACrB,WAAK,aAAa;AAClB,aAAO,KAAK,UAAU,yCAAyC;AAAA,IAChE;AAAA,IAEA,QAAQ,QAAQ,MAAM,MAAM;AAC3B,aAAO,KAAK,YAAY;AACxB,YAAM,OAAO,KAAK,YAAY,OAAO;AACrC,UAAI,CAAC,KAAK,aAAa;AAAG;AAC1B,WAAK,OAAO;AAEZ,WAAK,QAAQ,MAAM,KAAK,YAAY;AAAA,IACrC;AAAA,IAEA,GAAG,QAAQ,MAAM,MAAM;AACtB,aAAO,KAAK,MAAM,eAAe;AAAA,IAClC;AAAA,IAEA,OAAO,QAAQ,MAAM,MAAM;AAC1B,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,UAAI,KAAK,MAAM;AACd,cAAM,IAAI,KAAK,aAAa,8BAA8B,KAAK,KAAK,gBAAgB;AAAA,MACrF;AACA,eAAS,KAAK,MAAM;AACpB,YAAM,EAAE,UAAU,KAAK,IAAI,QAAQ,UAAU,KAAK,QAAQ,MAAM;AAChE,YAAM,OAAO,IAAI,QAAQ,MAAM,MAAM,UAAU,MAAM,EAAE,cAAc,KAAK,CAAC;AAC3E,WAAK,OAAO;AACZ,WAAK,aAAa,GAAG,KAAK,6DAA6D;AACvF,WAAK,QAAQ,MAAM,IAAI;AACvB,WAAK,OAAO,kBAAkB,MAAM,SAAS,QAAQ,WAAW,EAAE;AAAA,IACnE;AAAA,IACA,UAAU,QAAQ,MAAM,MAAM;AAC7B,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,UAAI,CAAC,YAAY,KAAK,MAAM;AAAG,oBAAY,KAAK,MAAM,IAAI,CAAC;AAC3D,UAAI,CAAC;AAAQ,eAAO,KAAK,MAAM,eAAe;AAE9C,YAAM,OAAO,OAAO,MAAM,OAAO,SAAS,GAAG,IAAI,MAAM,GAAG;AAC1D,YAAM,EAAE,OAAO,IAAI,QAAQ,eAAe,IAAI;AAC9C,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,MAAM;AAAG,oBAAY,KAAK,MAAM,EAAE,MAAM,IAAI,EAAE,OAAO,CAAC,EAAE;AACtF,WAAK,MAAM;AACX,kBAAY,KAAK,MAAM,EAAE,MAAM,EAAE,MAAM,KAAK,GAAG,IAAI;AACnD,cAAQ,KAAK;AACb,WAAK,iBAAiB,GAAG,KAAK,oCAAoC,KAAK,MAAM,KAAK,QAAQ,OAAO,IAAI;AACrG,WAAK,OAAO,qBAAqB,MAAM,GAAG,WAAW,KAAK,KAAK,IAAI,GAAG;AAAA,IACvE;AAAA,IACA,IAAI;AAAA,IACJ,aAAa,QAAQ,MAAM,MAAM;AAChC,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,UAAI,CAAC,MAAM,GAAG,KAAK,IAAI,OAAO,MAAM,GAAG;AACvC,UAAI,CAAC,KAAK,MAAM,KAAK,CAAC;AAAM,eAAO,KAAK,MAAM,eAAe;AAC7D,iBAAW,CAAC,GAAG,IAAI,KAAK,MAAM,QAAQ,GAAG;AACxC,YAAI,KAAK,WAAW,OAAO,GAAG;AAC7B,gBAAM,QAAQ,KAAK,MAAM,CAAC;AAC1B,gBAAM,aAAa,MAAM,OAAO,KAAK;AACrC,cAAI,CAAC,YAAY;AAChB,mBAAO,KAAK,WAAW,iBAAiB,OAAO;AAAA,UAChD;AACA,eAAK,OAAO;AACZ,iBAAO;AACP,gBAAM,OAAO,GAAG,CAAC;AAAA,QAClB;AAAA,MACD;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,GAAG;AAC9B,eAAO,KAAK,WAAW,2CAA2C;AAAA,MACnE;AACA,YAAM,WAAW,OAAO,KAAK,YAAY,KAAK,MAAM,CAAC;AACrD,YAAM,aAAa,SAAS,IAAI,IAAI;AACpC,YAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,CAAC;AAC3C,UAAI,QAAQ,GAAG;AACd,eAAO,KAAK,WAAW,mCAAmC;AAAA,MAC3D;AACA,aAAO,SAAS,KAAK;AACrB,cAAQ,MAAM,IAAI,IAAI;AAEtB,UAAI,CAAC,MAAM,QAAQ;AAClB,eAAO,YAAY,KAAK,MAAM,EAAE,IAAI;AACpC,aAAK,iBAAiB,GAAG,KAAK,uCAAuC,OAAO;AAC5E,aAAK,OAAO,wBAAwB,MAAM,IAAI;AAAA,MAC/C,OAAO;AACN,oBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,QAAQ,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,UAAQ,CAAC,MAAM,SAAS,KAAK,IAAI,CAAC,CAAC;AACtH,YAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ;AACjD,iBAAO,YAAY,KAAK,MAAM,EAAE,IAAI;AAAA,QACrC;AACA,aAAK,iBAAiB,GAAG,KAAK,gBAAgB,KAAK,MAAM,OAAO,OAAO,2BAA2B,OAAO;AACzG,aAAK,OAAO,wBAAwB,MAAM,GAAG,SAAS,MAAM,KAAK,IAAI,GAAG;AAAA,MACzE;AACA,WAAK,YAAY,WAAW,KAAK,QAAQ;AACzC,cAAQ,KAAK;AAAA,IACd;AAAA,IACA,OAAO,QAAQ,MAAM,MAAM;AAC1B,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,UAAI,CAAC,MAAM,GAAG,IAAI,IAAI,OAAO,MAAM,GAAG;AAEtC,aAAO,KAAK,KAAK;AACjB,aAAO,KAAK,IAAI,OAAK,KAAK,CAAC,CAAC,EAAE,OAAO,OAAO;AAC5C,UAAI,CAAC,QAAQ,CAAC,MAAM,QAAQ;AAC3B,eAAO,KAAK,MAAM,eAAe;AAAA,MAClC;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,GAAG;AAC9B,oBAAY,KAAK,MAAM,IAAI,CAAC;AAAA,MAC7B;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,GAAG;AACpC,eAAO,KAAK,WAAW,QAAQ,iBAAiB;AAAA,MACjD;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE;AAAM,oBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;AACjF,iBAAW,CAAC,GAAG,GAAG,KAAK,KAAK,QAAQ,GAAG;AACtC,YAAI,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,KAAM,SAAS,GAAG,GAAG;AACvD,eAAK,WAAW,WAAW,8BAA8B,4BAA4B;AACrF,eAAK,OAAO,GAAG,CAAC;AAAA,QACjB;AAAA,MACD;AACA,UAAI,CAAC,KAAK,QAAQ;AACjB,aAAK,WAAW,iCAAiC;AACjD,eAAO,KAAK,MAAM,eAAe;AAAA,MAClC;AACA,kBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,KAAM,KAAK,GAAG,IAAI;AACjD,cAAQ,KAAK;AACb,WAAK,iBAAiB,GAAG,KAAK,cAAc,KAAK,MAAM,MAAM,MAAM,yBAAyB,MAAM;AAClG,WAAK,OAAO,kBAAkB,MAAM,GAAG,SAAS,KAAK,IAAI,iBAAM,UAAU,EAAE,KAAK,IAAI,GAAG;AACvF,WAAK,YAAY,WAAW,KAAK,QAAQ;AAAA,IAC1C;AAAA,IACA,MAAM,QAAQ,MAAM,MAAM;AACzB,aAAO,KAAK,YAAY;AACxB,WAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,UAAI,CAAC,KAAK,MAAM,GAAG;AAClB,eAAO,KAAK,MAAM,eAAe;AAAA,MAClC;AACA,UAAI,CAAC,MAAM,GAAG,IAAI,IAAI,OAAO,MAAM,GAAG;AACtC,aAAO,KAAK,IAAI,OAAK,KAAK,CAAC,CAAC,EAAE,OAAO,OAAO;AAC5C,UAAI,CAAC,QAAQ,CAAC,MAAM;AACnB,eAAO,KAAK,MAAM,eAAe;AAAA,MAClC;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,GAAG;AAC9B,eAAO,KAAK,WAAW,iCAAiC;AAAA,MACzD;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,GAAG;AACpC,eAAO,KAAK,WAAW,0BAA0B;AAAA,MAClD;AACA,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM;AACzC,eAAO,KAAK,WAAW,wBAAwB;AAAA,MAChD;AACA,UAAI,KAAK,QAAQ;AAChB,aAAK,iBAAiB,GAAG,KAAK,gBAAgB,KAAK,MAAM,MAAM,MAAM,2BAA2B,MAAM;AACtG,aAAK,OAAO,iBAAiB,MAAM,GAAG,SAAS,KAAK,IAAI,iBAAM,UAAU,EAAE,KAAK,IAAI,GAAG;AACtF,oBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,MAAM,OAAO,OAAK,CAAC,KAAK,SAAS,CAAC,CAAC;AAAA,MACzG,OAAO;AACN,aAAK,iBAAiB,GAAG,KAAK,+CAA+C,MAAM;AACnF,aAAK,OAAO,iBAAiB,MAAM,GAAG,MAAM;AAC5C,oBAAY,KAAK,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC;AAAA,MACxC;AAEA,UAAI,CAAC,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE,KAAM,QAAQ;AACjD,eAAO,YAAY,KAAK,MAAM,EAAE,IAAI,EAAE;AAAA,MACvC;AACA,cAAQ,KAAK;AACb,WAAK,YAAY,WAAW,KAAK,QAAQ;AAAA,IAC1C;AAAA,IACA,MAAM;AAAA,IACN,MAAM,QAAQ,MAAM,MAAM;AACzB,aAAO,KAAK,YAAY;AACxB,aAAO,KAAK,MAAM,mBAAmB,UAAU,KAAK,QAAQ;AAAA,IAC7D;AAAA,EACD;AAAA,EAEA,aAAa;AAAA,IACZ;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IAEA;AAAA,IACA;AAAA,IACA;AAAA,EACD;AACD;AAEO,MAAM,QAAwB;AAAA,EACpC,QAAQ,MAAM,MAAM;AACnB,UAAM,OAAO,KAAK,YAAY;AAC9B,SAAK,QAAQ;AACb,SAAK,SAAS,QAAQ,MAAM,IAAI;AAChC,QAAI,MAAM,sGAAsG,KAAK;AACrH,WAAO,2CAA2C,KAAK;AACvD,UAAM,YAAY,YAAY,KAAK,MAAM;AACzC,QAAI,CAAC,WAAW;AACf,aAAO,KAAK,WAAW,8BAA8B,KAAK,QAAQ;AAAA,IACnE;AACA,eAAW,KAAK,WAAW;AAC1B,aAAO;AACP,aAAO,OAAO;AACd,UAAI,KAAK,IAAI,QAAQ,MAAM,MAAM,mBAAmB,GAAG;AACtD,eAAO;AACP,eAAO,UAAU,CAAC,EAAE,MAAM;AAAA,UACzB,UAAQ,GAAG,2DAA2D,KAAK,uBAAuB,KAAK;AAAA,QACxG,EAAE,KAAK,IAAI;AACX,eAAO,2EAA2E,KAAK,uBAAuB;AAC9G,YAAI,UAAU,CAAC,EAAE,MAAM;AACtB,iBAAO;AACP,iBAAO,UAAU,CAAC,EAAE,MAAM;AAAA,YACzB,SAAO,GAAG,0DAA0D,KAAK,0BAA0B,KAAK;AAAA,UACzG,EAAE,KAAK,IAAI;AACX,iBAAO,2EAA2E,KAAK,0BAA0B;AAAA,QAClH;AAAA,MACD;AACA,aAAO;AAAA,IACR;AACA,WAAO;AACP,WAAO;AAAA,EACR;AACD;AAEO,MAAM,eAAqC,WAAS;AAAA,EAC1D,OAAO;AAAA,EACP,YAAY;AAAA,EACZ,SAAS;AAAA,IACR,CAAC,YAAY,KAAK,SAAS,mBAAmB,iBAAiB;AAAA,IAC/D,CAAC,WAAW,CAAC,KAAK,SAAS,mBAAmB,gBAAgB;AAAA,EAC/D;AACD;", | |
"names": [] | |
} | |