{ "version": 3, "sources": ["../../server/chat.ts"], "sourcesContent": ["/**\n * Chat\n * Pokemon Showdown - http://pokemonshowdown.com/\n *\n * This handles chat and chat commands sent from users to chatrooms\n * and PMs. The main function you're looking for is Chat.parse\n * (scroll down to its definition for details)\n *\n * Individual commands are put in:\n * chat-commands/ - \"core\" commands that shouldn't be modified\n * chat-plugins/ - other commands that can be safely modified\n *\n * The command API is (mostly) documented in chat-plugins/COMMANDS.md\n *\n * @license MIT\n */\n\n/*\n\nTo reload chat commands:\n\n/hotpatch chat\n\n*/\n\nimport type { RoomPermission, GlobalPermission } from './user-groups';\nimport type { Punishment } from './punishments';\nimport type { PartialModlogEntry } from './modlog';\nimport { FriendsDatabase, PM } from './friends';\nimport { SQL, Repl, FS, Utils } from '../lib';\nimport * as Artemis from './artemis';\nimport { Dex } from '../sim';\nimport { PrivateMessages } from './private-messages';\nimport * as pathModule from 'path';\nimport * as JSX from './chat-jsx';\n\nexport type PageHandler = (this: PageContext, query: string[], user: User, connection: Connection)\n=> Promise | string | null | void | JSX.VNode;\nexport interface PageTable {\n\t[k: string]: PageHandler | PageTable;\n}\n\nexport type ChatHandler = (\n\tthis: CommandContext,\n\ttarget: string,\n\troom: Room | null,\n\tuser: User,\n\tconnection: Connection,\n\tcmd: string,\n\tmessage: string\n) => void;\nexport type AnnotatedChatHandler = ChatHandler & {\n\trequiresRoom: boolean | RoomID,\n\thasRoomPermissions: boolean,\n\tbroadcastable: boolean,\n\tcmd: string,\n\tfullCmd: string,\n\tisPrivate: boolean,\n\tdisabled: boolean,\n\taliases: string[],\n\trequiredPermission?: GlobalPermission | RoomPermission,\n};\nexport interface ChatCommands {\n\t[k: string]: ChatHandler | string | string[] | ChatCommands;\n}\nexport interface AnnotatedChatCommands {\n\t[k: string]: AnnotatedChatHandler | string | string[] | AnnotatedChatCommands;\n}\n\nexport type HandlerTable = { [key in keyof Handlers]?: Handlers[key] };\n\ninterface Handlers {\n\tonRoomClose: (id: string, user: User, connection: Connection, page: boolean) => any;\n\tonRenameRoom: (oldId: RoomID, newID: RoomID, room: BasicRoom) => void;\n\tonBattleStart: (user: User, room: GameRoom) => void;\n\tonBattleLeave: (user: User, room: GameRoom) => void;\n\tonRoomJoin: (room: BasicRoom, user: User, connection: Connection) => void;\n\tonBeforeRoomJoin: (room: BasicRoom, user: User, connection: Connection) => void;\n\tonDisconnect: (user: User) => void;\n\tonRoomDestroy: (roomid: RoomID) => void;\n\tonBattleEnd: (battle: RoomBattle, winner: ID, players: ID[]) => void;\n\tonLadderSearch: (user: User, connection: Connection, format: ID) => void;\n\tonBattleRanked: (\n\t\tbattle: Rooms.RoomBattle, winner: ID, ratings: (AnyObject | null | undefined)[], players: ID[]\n\t) => void;\n\tonRename: (user: User, oldID: ID, newID: ID) => void;\n\tonTicketCreate: (ticket: import('./chat-plugins/helptickets').TicketState, user: User) => void;\n\tonChallenge: (user: User, targetUser: User, format: string | ID) => void;\n\tonMessageOffline: (context: Chat.CommandContext, message: string, targetUserID: ID) => void;\n\tonBattleJoin: (slot: string, user: User, battle: RoomBattle) => void;\n\tonPunishUser: (type: string, user: User, room?: Room | null) => void;\n}\n\nexport interface ChatPlugin {\n\tcommands?: AnnotatedChatCommands;\n\tpages?: PageTable;\n\tdestroy?: () => void;\n\troomSettings?: SettingsHandler | SettingsHandler[];\n\t[k: string]: any;\n}\nexport type SettingsHandler = (\n\n\troom: Room,\n\tuser: User,\n\tconnection: Connection\n) => {\n\tlabel: string,\n\tpermission: boolean | RoomPermission,\n\t// button label, command | disabled\n\toptions: [string, string | true][],\n};\n\nexport type CRQHandler = (this: CommandContext, target: string, user: User, trustable?: boolean) => any;\nexport type RoomCloseHandler = (id: string, user: User, connection: Connection, page: boolean) => any;\n\n/**\n * Chat filters can choose to:\n * 1. return false OR null - to not send a user's message\n * 2. return an altered string - to alter a user's message\n * 3. return undefined to send the original message through\n */\nexport type ChatFilter = ((\n\tthis: CommandContext,\n\tmessage: string,\n\tuser: User,\n\troom: Room | null,\n\tconnection: Connection,\n\ttargetUser: User | null,\n\toriginalMessage: string\n) => string | false | null | undefined | void) & { priority?: number };\n\nexport type NameFilter = (name: string, user: User) => string;\nexport type NicknameFilter = (name: string, user: User) => string | false;\nexport type StatusFilter = (status: string, user: User) => string;\nexport type PunishmentFilter = (user: User | ID, punishment: Punishment) => void;\nexport type LoginFilter = (user: User, oldUser: User | null, userType: string) => void;\nexport type HostFilter = (host: string, user: User, connection: Connection, hostType: string) => void;\n\nexport interface Translations {\n\tname?: string;\n\tstrings: { [english: string]: string };\n}\n\nconst LINK_WHITELIST = [\n\t'*.pokemonshowdown.com', 'psim.us', 'smogtours.psim.us',\n\t'*.smogon.com', '*.pastebin.com', '*.hastebin.com',\n];\n\nconst MAX_MESSAGE_LENGTH = 1000;\n\nconst BROADCAST_COOLDOWN = 20 * 1000;\nconst MESSAGE_COOLDOWN = 5 * 60 * 1000;\n\nconst MAX_PARSE_RECURSION = 10;\n\nconst VALID_COMMAND_TOKENS = '/!';\nconst BROADCAST_TOKEN = '!';\n\nconst PLUGIN_DATABASE_PATH = './databases/chat-plugins.db';\nconst MAX_PLUGIN_LOADING_DEPTH = 3;\n\nimport { formatText, linkRegex, stripFormatting } from './chat-formatter';\n\n// @ts-expect-error no typedef available\nimport ProbeModule = require('probe-image-size');\nconst probe: (url: string) => Promise<{ width: number, height: number }> = ProbeModule;\n\nconst EMOJI_REGEX = /[\\p{Emoji_Modifier_Base}\\p{Emoji_Presentation}\\uFE0F]/u;\n\nconst TRANSLATION_DIRECTORY = pathModule.resolve(__dirname, '..', 'translations');\n\nclass PatternTester {\n\t// This class sounds like a RegExp\n\t// In fact, one could in theory implement it as a RegExp subclass\n\t// However, ES2016 RegExp subclassing is a can of worms, and it wouldn't allow us\n\t// to tailor the test method for fast command parsing.\n\treadonly elements: string[];\n\treadonly fastElements: Set;\n\tregexp: RegExp | null;\n\tconstructor() {\n\t\tthis.elements = [];\n\t\tthis.fastElements = new Set();\n\t\tthis.regexp = null;\n\t}\n\tfastNormalize(elem: string) {\n\t\treturn elem.slice(0, -1);\n\t}\n\tupdate() {\n\t\tconst slowElements = this.elements.filter(elem => !this.fastElements.has(this.fastNormalize(elem)));\n\t\tif (slowElements.length) {\n\t\t\tthis.regexp = new RegExp('^(' + slowElements.map(elem => '(?:' + elem + ')').join('|') + ')', 'i');\n\t\t}\n\t}\n\tregister(...elems: string[]) {\n\t\tfor (const elem of elems) {\n\t\t\tthis.elements.push(elem);\n\t\t\tif (/^[^ ^$?|()[\\]]+ $/.test(elem)) {\n\t\t\t\tthis.fastElements.add(this.fastNormalize(elem));\n\t\t\t}\n\t\t}\n\t\tthis.update();\n\t}\n\ttestCommand(text: string) {\n\t\tconst spaceIndex = text.indexOf(' ');\n\t\tif (this.fastElements.has(spaceIndex >= 0 ? text.slice(0, spaceIndex) : text)) {\n\t\t\treturn true;\n\t\t}\n\t\tif (!this.regexp) return false;\n\t\treturn this.regexp.test(text);\n\t}\n\ttest(text: string) {\n\t\tif (!text.includes('\\n')) return null;\n\t\tif (this.testCommand(text)) return text;\n\t\t// The PM matching is a huge mess, and really needs to be replaced with\n\t\t// the new multiline command system soon.\n\t\tconst pmMatches = /^(\\/(?:pm|w|whisper|msg) [^,]*, ?)(.*)/i.exec(text);\n\t\tif (pmMatches && this.testCommand(pmMatches[2])) {\n\t\t\tif (text.split('\\n').every(line => line.startsWith(pmMatches[1]))) {\n\t\t\t\treturn text.replace(/\\n\\/(?:pm|w|whisper|msg) [^,]*, ?/g, '\\n');\n\t\t\t}\n\t\t\treturn text;\n\t\t}\n\t\treturn null;\n\t}\n}\n\n/*********************************************************\n * Parser\n *********************************************************/\n\n/**\n * An ErrorMessage will, if used in a command/page context, simply show the user\n * the error, rather than logging a crash. It's used to simplify showing errors.\n *\n * Outside of a command/page context, it would still cause a crash.\n */\nexport class ErrorMessage extends Error {\n\tconstructor(message: string) {\n\t\tsuper(message);\n\t\tthis.name = 'ErrorMessage';\n\t\tError.captureStackTrace(this, ErrorMessage);\n\t}\n}\n\nexport class Interruption extends Error {\n\tconstructor() {\n\t\tsuper('');\n\t\tthis.name = 'Interruption';\n\t\tError.captureStackTrace(this, ErrorMessage);\n\t}\n}\n\n// These classes need to be declared here because they aren't hoisted\nexport abstract class MessageContext {\n\treadonly user: User;\n\tlanguage: ID | null;\n\trecursionDepth: number;\n\tconstructor(user: User, language: ID | null = null) {\n\t\tthis.user = user;\n\t\tthis.language = language;\n\t\tthis.recursionDepth = 0;\n\t}\n\n\tsplitOne(target: string) {\n\t\tconst commaIndex = target.indexOf(',');\n\t\tif (commaIndex < 0) {\n\t\t\treturn [target.trim(), ''];\n\t\t}\n\t\treturn [target.slice(0, commaIndex).trim(), target.slice(commaIndex + 1).trim()];\n\t}\n\tmeansYes(text: string) {\n\t\tswitch (text.toLowerCase().trim()) {\n\t\tcase 'on': case 'enable': case 'yes': case 'true': case 'allow': case '1':\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\tmeansNo(text: string) {\n\t\tswitch (text.toLowerCase().trim()) {\n\t\tcase 'off': case 'disable': case 'no': case 'false': case 'disallow': case '0':\n\t\t\treturn true;\n\t\t}\n\t\treturn false;\n\t}\n\t/**\n\t * Given an array of strings (or a comma-delimited string), check the\n\t * first and last string for a format/mod/gen. If it exists, remove\n\t * it from the array.\n\t *\n\t * @returns `format` (null if no format was found), `dex` (the dex\n\t * for the format/mod, or the default dex if none was found), and\n\t * `targets` (the rest of the array).\n\t */\n\tsplitFormat(target: string | string[], atLeastOneTarget?: boolean, allowRules?: boolean) {\n\t\tconst targets = typeof target === 'string' ? target.split(',') : target;\n\t\tif (!targets[0].trim()) targets.pop();\n\n\t\tif (targets.length > (atLeastOneTarget ? 1 : 0)) {\n\t\t\tconst { dex, format, isMatch } = this.extractFormat(targets[0].trim(), allowRules);\n\t\t\tif (isMatch) {\n\t\t\t\ttargets.shift();\n\t\t\t\treturn { dex, format, targets };\n\t\t\t}\n\t\t}\n\t\tif (targets.length > 1) {\n\t\t\tconst { dex, format, isMatch } = this.extractFormat(targets[targets.length - 1].trim(), allowRules);\n\t\t\tif (isMatch) {\n\t\t\t\ttargets.pop();\n\t\t\t\treturn { dex, format, targets };\n\t\t\t}\n\t\t}\n\n\t\tconst room = (this as any as CommandContext).room;\n\t\tconst { dex, format } = this.extractFormat(room?.settings.defaultFormat || room?.battle?.format, allowRules);\n\t\treturn { dex, format, targets };\n\t}\n\textractFormat(formatOrMod?: string, allowRules?: boolean): { dex: ModdedDex, format: Format | null, isMatch: boolean } {\n\t\tif (!formatOrMod) {\n\t\t\treturn { dex: Dex.includeData(), format: null, isMatch: false };\n\t\t}\n\n\t\tconst format = Dex.formats.get(formatOrMod);\n\t\tif (format.effectType === 'Format' || allowRules && format.effectType === 'Rule') {\n\t\t\treturn { dex: Dex.forFormat(format), format, isMatch: true };\n\t\t}\n\n\t\tif (toID(formatOrMod) in Dex.dexes) {\n\t\t\treturn { dex: Dex.mod(toID(formatOrMod)), format: null, isMatch: true };\n\t\t}\n\n\t\treturn this.extractFormat();\n\t}\n\tsplitUser(target: string, { exactName }: { exactName?: boolean } = {}) {\n\t\tconst [inputUsername, rest] = this.splitOne(target).map(str => str.trim());\n\t\tconst targetUser = Users.get(inputUsername, exactName);\n\n\t\treturn {\n\t\t\ttargetUser,\n\t\t\tinputUsername,\n\t\t\ttargetUsername: targetUser ? targetUser.name : inputUsername,\n\t\t\trest,\n\t\t};\n\t}\n\trequireUser(target: string, options: { allowOffline?: boolean, exactName?: boolean } = {}) {\n\t\tconst { targetUser, targetUsername, rest } = this.splitUser(target, options);\n\n\t\tif (!targetUser) {\n\t\t\tthrow new Chat.ErrorMessage(`The user \"${targetUsername}\" is offline or misspelled.`);\n\t\t}\n\t\tif (!options.allowOffline && !targetUser.connected) {\n\t\t\tthrow new Chat.ErrorMessage(`The user \"${targetUsername}\" is offline.`);\n\t\t}\n\n\t\t// `inputUsername` and `targetUsername` are never needed because we already handle the \"user not found\" error messages\n\t\t// just use `targetUser.name` where previously necessary\n\t\treturn { targetUser, rest };\n\t}\n\tgetUserOrSelf(target: string, { exactName }: { exactName?: boolean } = {}) {\n\t\tif (!target.trim()) return this.user;\n\n\t\treturn Users.get(target, exactName);\n\t}\n\ttr(strings: TemplateStringsArray | string, ...keys: any[]) {\n\t\treturn Chat.tr(this.language, strings, ...keys);\n\t}\n}\n\nexport class PageContext extends MessageContext {\n\treadonly connection: Connection;\n\troom: Room | null;\n\tpageid: string;\n\tinitialized: boolean;\n\ttitle: string;\n\targs: string[];\n\tconstructor(options: { pageid: string, user: User, connection: Connection, language?: ID }) {\n\t\tsuper(options.user, options.language);\n\n\t\tthis.connection = options.connection;\n\t\tthis.room = null;\n\t\tthis.pageid = options.pageid;\n\t\tthis.args = this.pageid.split('-');\n\n\t\tthis.initialized = false;\n\t\tthis.title = 'Page';\n\t}\n\n\tcheckCan(permission: RoomPermission, target: User | null, room: Room): boolean;\n\tcheckCan(permission: GlobalPermission, target?: User | null): boolean;\n\tcheckCan(permission: string, target: User | null = null, room: Room | null = null) {\n\t\tif (!this.user.can(permission as any, target, room as any)) {\n\t\t\tthrow new Chat.ErrorMessage(`

Permission denied.

`);\n\t\t}\n\t\treturn true;\n\t}\n\n\tprivatelyCheckCan(permission: RoomPermission, target: User | null, room: Room): boolean;\n\tprivatelyCheckCan(permission: GlobalPermission, target?: User | null): boolean;\n\tprivatelyCheckCan(permission: string, target: User | null = null, room: Room | null = null) {\n\t\tif (!this.user.can(permission as any, target, room as any)) {\n\t\t\tthis.pageDoesNotExist();\n\t\t}\n\t\treturn true;\n\t}\n\n\tpageDoesNotExist(): never {\n\t\tthrow new Chat.ErrorMessage(`Page \"${this.pageid}\" not found`);\n\t}\n\n\trequireRoom(pageid?: string) {\n\t\tconst room = this.extractRoom(pageid);\n\t\tif (!room) {\n\t\t\tthrow new Chat.ErrorMessage(`Invalid link: This page requires a room ID.`);\n\t\t}\n\n\t\tthis.room = room;\n\t\treturn room;\n\t}\n\textractRoom(pageid?: string) {\n\t\tif (!pageid) pageid = this.pageid;\n\t\tconst parts = pageid.split('-');\n\n\t\t// The roomid for the page should be view-pagename-roomid\n\t\tconst room = Rooms.get(parts[2]) || null;\n\n\t\tthis.room = room;\n\t\treturn room;\n\t}\n\n\tsetHTML(html: string) {\n\t\tconst roomid = this.room ? `[${this.room.roomid}] ` : '';\n\t\tlet content = `|title|${roomid}${this.title}\\n|pagehtml|${html}`;\n\t\tif (!this.initialized) {\n\t\t\tcontent = `|init|html\\n${content}`;\n\t\t\tthis.initialized = true;\n\t\t}\n\t\tthis.send(content);\n\t}\n\terrorReply(message: string) {\n\t\tthis.setHTML(`

${message}

`);\n\t}\n\n\tsend(content: string) {\n\t\tthis.connection.send(`>${this.pageid}\\n${content}`);\n\t}\n\tclose() {\n\t\tthis.send('|deinit');\n\t}\n\n\tasync resolve(pageid?: string) {\n\t\tif (pageid) this.pageid = pageid;\n\n\t\tconst parts = this.pageid.split('-');\n\t\tparts.shift(); // first part is always `view`\n\n\t\tif (!this.connection.openPages) this.connection.openPages = new Set();\n\t\tthis.connection.openPages.add(parts.join('-'));\n\n\t\tlet handler: PageHandler | PageTable = Chat.pages;\n\t\twhile (handler) {\n\t\t\tif (typeof handler === 'function') {\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\thandler = handler[parts.shift() || 'default'] || handler[''];\n\t\t}\n\n\t\tthis.args = parts;\n\n\t\tlet res;\n\t\ttry {\n\t\t\tif (typeof handler !== 'function') this.pageDoesNotExist();\n\t\t\tres = await handler.call(this, parts, this.user, this.connection);\n\t\t} catch (err: any) {\n\t\t\tif (err.name?.endsWith('ErrorMessage')) {\n\t\t\t\tif (err.message) this.errorReply(err.message);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (err.name.endsWith('Interruption')) {\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tMonitor.crashlog(err, 'A chat page', {\n\t\t\t\tuser: this.user.name,\n\t\t\t\troom: this.room && this.room.roomid,\n\t\t\t\tpageid: this.pageid,\n\t\t\t});\n\t\t\tthis.setHTML(\n\t\t\t\t`
` +\n\t\t\t\t`Pokemon Showdown crashed!
Don't worry, we're working on fixing it.` +\n\t\t\t\t`
`\n\t\t\t);\n\t\t}\n\t\tif (typeof res === 'object' && res) res = JSX.render(res);\n\t\tif (typeof res === 'string') {\n\t\t\tthis.setHTML(res);\n\t\t\tres = undefined;\n\t\t}\n\t\treturn res;\n\t}\n}\n\n/**\n * This is a message sent in a PM or to a chat/battle room.\n *\n * There are three cases to be aware of:\n * - PM to user: `context.pmTarget` will exist and `context.room` will be `null`\n * - message to room: `context.room` will exist and `context.pmTarget` will be `null`\n * - console command (PM to `~`): `context.pmTarget` and `context.room` will both be `null`\n */\nexport class CommandContext extends MessageContext {\n\tmessage: string;\n\tpmTarget: User | null;\n\troom: Room | null;\n\tconnection: Connection;\n\n\tcmd: string;\n\tcmdToken: string;\n\ttarget: string;\n\tfullCmd: string;\n\thandler: AnnotatedChatHandler | null;\n\n\tisQuiet: boolean;\n\tbypassRoomCheck?: boolean;\n\tbroadcasting: boolean;\n\tbroadcastToRoom: boolean;\n\t/** Used only by !rebroadcast */\n\tbroadcastPrefix: string;\n\tbroadcastMessage: string;\n\tconstructor(options: {\n\t\tmessage: string, user: User, connection: Connection,\n\t\troom?: Room | null, pmTarget?: User | null, cmd?: string, cmdToken?: string, target?: string, fullCmd?: string,\n\t\trecursionDepth?: number, isQuiet?: boolean, broadcastPrefix?: string, bypassRoomCheck?: boolean,\n\t}) {\n\t\tsuper(\n\t\t\toptions.user, options.room && options.room.settings.language ?\n\t\t\t\toptions.room.settings.language : options.user.language\n\t\t);\n\n\t\tthis.message = options.message || ``;\n\t\tthis.recursionDepth = options.recursionDepth || 0;\n\n\t\t// message context\n\t\tthis.pmTarget = options.pmTarget || null;\n\t\tthis.room = options.room || null;\n\t\tthis.connection = options.connection;\n\n\t\t// command context\n\t\tthis.cmd = options.cmd || '';\n\t\tthis.cmdToken = options.cmdToken || '';\n\t\tthis.target = options.target || ``;\n\t\tthis.fullCmd = options.fullCmd || '';\n\t\tthis.handler = null;\n\t\tthis.isQuiet = options.isQuiet || false;\n\t\tthis.bypassRoomCheck = options.bypassRoomCheck || false;\n\n\t\t// broadcast context\n\t\tthis.broadcasting = false;\n\t\tthis.broadcastToRoom = true;\n\t\tthis.broadcastPrefix = options.broadcastPrefix || '';\n\t\tthis.broadcastMessage = '';\n\t}\n\n\t// TODO: return should be void | boolean | Promise\n\tparse(\n\t\tmsg?: string,\n\t\toptions: Partial<{ isQuiet: boolean, broadcastPrefix: string, bypassRoomCheck: boolean }> = {}\n\t): any {\n\t\tif (typeof msg === 'string') {\n\t\t\t// spawn subcontext\n\t\t\tconst subcontext = new CommandContext({\n\t\t\t\tmessage: msg,\n\t\t\t\tuser: this.user,\n\t\t\t\tconnection: this.connection,\n\t\t\t\troom: this.room,\n\t\t\t\tpmTarget: this.pmTarget,\n\t\t\t\trecursionDepth: this.recursionDepth + 1,\n\t\t\t\tbypassRoomCheck: this.bypassRoomCheck,\n\t\t\t\t...options,\n\t\t\t});\n\t\t\tif (subcontext.recursionDepth > MAX_PARSE_RECURSION) {\n\t\t\t\tthrow new Error(\"Too much command recursion\");\n\t\t\t}\n\t\t\treturn subcontext.parse();\n\t\t}\n\t\tlet message: string | void | boolean | Promise = this.message;\n\n\t\tconst parsedCommand = Chat.parseCommand(message);\n\t\tif (parsedCommand) {\n\t\t\tthis.cmd = parsedCommand.cmd;\n\t\t\tthis.fullCmd = parsedCommand.fullCmd;\n\t\t\tthis.cmdToken = parsedCommand.cmdToken;\n\t\t\tthis.target = parsedCommand.target;\n\t\t\tthis.handler = parsedCommand.handler;\n\t\t}\n\n\t\tif (!this.bypassRoomCheck && this.room && !(this.user.id in this.room.users)) {\n\t\t\treturn this.popupReply(`You tried to send \"${message}\" to the room \"${this.room.roomid}\" but it failed because you were not in that room.`);\n\t\t}\n\n\t\tif (this.user.statusType === 'idle' && !['unaway', 'unafk', 'back'].includes(this.cmd)) {\n\t\t\tthis.user.setStatusType('online');\n\t\t}\n\n\t\ttry {\n\t\t\tif (this.handler) {\n\t\t\t\tif (this.handler.disabled) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t\t\t`The command /${this.fullCmd.trim()} is temporarily unavailable due to technical difficulties. ` +\n\t\t\t\t\t\t`Please try again in a few hours.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tmessage = this.run(this.handler);\n\t\t\t} else {\n\t\t\t\tif (this.cmdToken) {\n\t\t\t\t\t// To guard against command typos, show an error message\n\t\t\t\t\tif (!(this.shouldBroadcast() && !/[a-z0-9]/.test(this.cmd.charAt(0)))) {\n\t\t\t\t\t\tthis.commandDoesNotExist();\n\t\t\t\t\t}\n\t\t\t\t} else if (\n\t\t\t\t\t!VALID_COMMAND_TOKENS.includes(message.charAt(0)) &&\n\t\t\t\t\tVALID_COMMAND_TOKENS.includes(message.trim().charAt(0))\n\t\t\t\t) {\n\t\t\t\t\tmessage = message.trim();\n\t\t\t\t\tif (!message.startsWith(BROADCAST_TOKEN)) {\n\t\t\t\t\t\tmessage = message.charAt(0) + message;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tmessage = this.checkChat(message);\n\t\t\t}\n\t\t} catch (err: any) {\n\t\t\tif (err.name?.endsWith('ErrorMessage')) {\n\t\t\t\tthis.errorReply(err.message);\n\t\t\t\tthis.update();\n\t\t\t\treturn false;\n\t\t\t}\n\t\t\tif (err.name.endsWith('Interruption')) {\n\t\t\t\tthis.update();\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tMonitor.crashlog(err, 'A chat command', {\n\t\t\t\tuser: this.user.name,\n\t\t\t\troom: this.room?.roomid,\n\t\t\t\tpmTarget: this.pmTarget?.name,\n\t\t\t\tmessage: this.message,\n\t\t\t});\n\t\t\tthis.sendReply(`|html|
Pokemon Showdown crashed!
Don't worry, we're working on fixing it.
`);\n\t\t\treturn;\n\t\t}\n\n\t\t// Output the message\n\t\tif (message && typeof (message as any).then === 'function') {\n\t\t\tthis.update();\n\t\t\treturn (message as Promise).then(resolvedMessage => {\n\t\t\t\tif (resolvedMessage && resolvedMessage !== true) {\n\t\t\t\t\tthis.sendChatMessage(resolvedMessage);\n\t\t\t\t}\n\t\t\t\tthis.update();\n\t\t\t\tif (resolvedMessage === false) return false;\n\t\t\t}).catch(err => {\n\t\t\t\tif (err.name?.endsWith('ErrorMessage')) {\n\t\t\t\t\tthis.errorReply(err.message);\n\t\t\t\t\tthis.update();\n\t\t\t\t\treturn false;\n\t\t\t\t}\n\t\t\t\tif (err.name.endsWith('Interruption')) {\n\t\t\t\t\tthis.update();\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tMonitor.crashlog(err, 'An async chat command', {\n\t\t\t\t\tuser: this.user.name,\n\t\t\t\t\troom: this.room?.roomid,\n\t\t\t\t\tpmTarget: this.pmTarget?.name,\n\t\t\t\t\tmessage: this.message,\n\t\t\t\t});\n\t\t\t\tthis.sendReply(`|html|
Pokemon Showdown crashed!
Don't worry, we're working on fixing it.
`);\n\t\t\t\treturn false;\n\t\t\t});\n\t\t} else if (message && message !== true) {\n\t\t\tthis.sendChatMessage(message as string);\n\t\t\tmessage = true;\n\t\t}\n\n\t\tthis.update();\n\n\t\treturn message;\n\t}\n\n\tsendChatMessage(message: string) {\n\t\tif (this.pmTarget) {\n\t\t\tconst blockInvites = this.pmTarget.settings.blockInvites;\n\t\t\tif (blockInvites && /^<<.*>>$/.test(message.trim())) {\n\t\t\t\tif (\n\t\t\t\t\t!this.user.can('lock') && blockInvites === true ||\n\t\t\t\t\t!Users.globalAuth.atLeast(this.user, blockInvites as GroupSymbol)\n\t\t\t\t) {\n\t\t\t\t\tChat.maybeNotifyBlocked(`invite`, this.pmTarget, this.user);\n\t\t\t\t\treturn this.errorReply(`${this.pmTarget.name} is blocking room invites.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tChat.PrivateMessages.send(message, this.user, this.pmTarget);\n\t\t} else if (this.room) {\n\t\t\tthis.room.add(`|c|${this.user.getIdentity(this.room)}|${message}`);\n\t\t\tthis.room.game?.onLogMessage?.(message, this.user);\n\t\t} else {\n\t\t\tthis.connection.popup(`Your message could not be sent:\\n\\n${message}\\n\\nIt needs to be sent to a user or room.`);\n\t\t}\n\t}\n\trun(handler: string | AnnotatedChatHandler) {\n\t\tif (typeof handler === 'string') handler = Chat.commands[handler] as AnnotatedChatHandler;\n\t\tif (!handler.broadcastable && this.cmdToken === '!') {\n\t\t\tthis.errorReply(`The command \"${this.fullCmd}\" can't be broadcast.`);\n\t\t\tthis.errorReply(`Use /${this.fullCmd} instead.`);\n\t\t\treturn false;\n\t\t}\n\t\tlet result: any = handler.call(this, this.target, this.room, this.user, this.connection, this.cmd, this.message);\n\t\tif (result === undefined) result = false;\n\n\t\treturn result;\n\t}\n\n\tcheckFormat(room: BasicRoom | null | undefined, user: User, message: string) {\n\t\tif (!room) return true;\n\t\tif (\n\t\t\t!room.settings.filterStretching && !room.settings.filterCaps &&\n\t\t\t!room.settings.filterEmojis && !room.settings.filterLinks\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t\tif (user.can('mute', null, room)) return true;\n\n\t\tif (room.settings.filterStretching && /(.+?)\\1{5,}/i.test(user.name)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains too much stretching, which this room doesn't allow.`);\n\t\t}\n\t\tif (room.settings.filterLinks) {\n\t\t\tconst bannedLinks = this.checkBannedLinks(message);\n\t\t\tif (bannedLinks.length) {\n\t\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t\t`You have linked to ${bannedLinks.length > 1 ? 'unrecognized external websites' : 'an unrecognized external website'} ` +\n\t\t\t\t\t`(${bannedLinks.join(', ')}), which this room doesn't allow.`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tif (room.settings.filterCaps && /[A-Z\\s]{6,}/.test(user.name)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains too many capital letters, which this room doesn't allow.`);\n\t\t}\n\t\tif (room.settings.filterEmojis && EMOJI_REGEX.test(user.name)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your username contains emojis, which this room doesn't allow.`);\n\t\t}\n\t\t// Removes extra spaces and null characters\n\t\t// eslint-disable-next-line no-control-regex\n\t\tmessage = message.trim().replace(/[ \\u0000\\u200B-\\u200F]+/g, ' ');\n\n\t\tif (room.settings.filterStretching && /(.+?)\\1{7,}/i.test(message)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains too much stretching, which this room doesn't allow.`);\n\t\t}\n\t\tif (room.settings.filterCaps && /[A-Z\\s]{18,}/.test(message)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains too many capital letters, which this room doesn't allow.`);\n\t\t}\n\t\tif (room.settings.filterEmojis && EMOJI_REGEX.test(message)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your message contains emojis, which this room doesn't allow.`);\n\t\t}\n\n\t\treturn true;\n\t}\n\n\tcheckSlowchat(room: Room | null | undefined, user: User) {\n\t\tif (!room?.settings.slowchat) return true;\n\t\tif (user.can('show', null, room)) return true;\n\t\tconst lastActiveSeconds = (Date.now() - user.lastMessageTime) / 1000;\n\t\tif (lastActiveSeconds < room.settings.slowchat) {\n\t\t\tthrow new Chat.ErrorMessage(this.tr`This room has slow-chat enabled. You can only talk once every ${room.settings.slowchat} seconds.`);\n\t\t}\n\t\treturn true;\n\t}\n\n\tcheckBanwords(room: BasicRoom | null | undefined, message: string): boolean {\n\t\tif (!room) return true;\n\t\tif (!room.banwordRegex) {\n\t\t\tif (room.settings.banwords?.length) {\n\t\t\t\troom.banwordRegex = new RegExp('(?:\\\\b|(?!\\\\w))(?:' + room.settings.banwords.join('|') + ')(?:\\\\b|\\\\B(?!\\\\w))', 'i');\n\t\t\t} else {\n\t\t\t\troom.banwordRegex = true;\n\t\t\t}\n\t\t}\n\t\tif (!message) return true;\n\t\tif (room.banwordRegex !== true && room.banwordRegex.test(message)) {\n\t\t\tthrow new Chat.ErrorMessage(`Your message contained a word banned by this room.`);\n\t\t}\n\t\treturn this.checkBanwords(room.parent as ChatRoom, message);\n\t}\n\tcheckGameFilter() {\n\t\treturn this.room?.game?.onChatMessage?.(this.message, this.user);\n\t}\n\tpmTransform(originalMessage: string, sender?: User, receiver?: User | null | string) {\n\t\tif (!sender) {\n\t\t\tif (this.room) throw new Error(`Not a PM`);\n\t\t\tsender = this.user;\n\t\t\treceiver = this.pmTarget;\n\t\t}\n\t\tconst targetIdentity = typeof receiver === 'string' ? ` ${receiver}` : receiver ? receiver.getIdentity() : '~';\n\t\tconst prefix = `|pm|${sender.getIdentity()}|${targetIdentity}|`;\n\t\treturn originalMessage.split('\\n').map(message => {\n\t\t\tif (message.startsWith('||')) {\n\t\t\t\treturn prefix + `/text ` + message.slice(2);\n\t\t\t} else if (message.startsWith(`|html|`)) {\n\t\t\t\treturn prefix + `/raw ` + message.slice(6);\n\t\t\t} else if (message.startsWith(`|uhtml|`)) {\n\t\t\t\tconst [uhtmlid, html] = Utils.splitFirst(message.slice(7), '|');\n\t\t\t\treturn prefix + `/uhtml ${uhtmlid},${html}`;\n\t\t\t} else if (message.startsWith(`|uhtmlchange|`)) {\n\t\t\t\tconst [uhtmlid, html] = Utils.splitFirst(message.slice(13), '|');\n\t\t\t\treturn prefix + `/uhtmlchange ${uhtmlid},${html}`;\n\t\t\t} else if (message.startsWith(`|modaction|`)) {\n\t\t\t\treturn prefix + `/log ` + message.slice(11);\n\t\t\t} else if (message.startsWith(`|raw|`)) {\n\t\t\t\treturn prefix + `/raw ` + message.slice(5);\n\t\t\t} else if (message.startsWith(`|error|`)) {\n\t\t\t\treturn prefix + `/error ` + message.slice(7);\n\t\t\t} else if (message.startsWith(`|c~|`)) {\n\t\t\t\treturn prefix + message.slice(4);\n\t\t\t} else if (message.startsWith(`|c|~|/`)) {\n\t\t\t\treturn prefix + message.slice(5);\n\t\t\t} else if (message.startsWith(`|c|~|`)) {\n\t\t\t\treturn prefix + `/text ` + message.slice(5);\n\t\t\t}\n\t\t\treturn prefix + `/text ` + message;\n\t\t}).join(`\\n`);\n\t}\n\tsendReply(data: string) {\n\t\tif (this.isQuiet) return;\n\t\tif (this.broadcasting && this.broadcastToRoom) {\n\t\t\t// broadcasting\n\t\t\tthis.add(data);\n\t\t} else {\n\t\t\t// not broadcasting\n\t\t\tif (!this.room) {\n\t\t\t\tdata = this.pmTransform(data);\n\t\t\t\tthis.connection.send(data);\n\t\t\t} else {\n\t\t\t\tthis.connection.sendTo(this.room, data);\n\t\t\t}\n\t\t}\n\t}\n\terrorReply(message: string) {\n\t\tif (this.bypassRoomCheck) { // if they're not in the room, we still want a good error message for them\n\t\t\treturn this.popupReply(\n\t\t\t\t`|html|${message.replace(/\\n/ig, '
')}
`\n\t\t\t);\n\t\t}\n\t\tthis.sendReply(`|error|` + message.replace(/\\n/g, `\\n|error|`));\n\t}\n\taddBox(htmlContent: string | JSX.VNode) {\n\t\tif (typeof htmlContent !== 'string') htmlContent = JSX.render(htmlContent);\n\t\tthis.add(`|html|
${htmlContent}
`);\n\t}\n\tsendReplyBox(htmlContent: string | JSX.VNode) {\n\t\tif (typeof htmlContent !== 'string') htmlContent = JSX.render(htmlContent);\n\t\tthis.sendReply(`|c|${this.room && this.broadcasting ? this.user.getIdentity() : '~'}|/raw
${htmlContent}
`);\n\t}\n\tpopupReply(message: string) {\n\t\tthis.connection.popup(message);\n\t}\n\tadd(data: string) {\n\t\tif (this.room) {\n\t\t\tthis.room.add(data);\n\t\t} else {\n\t\t\tthis.send(data);\n\t\t}\n\t}\n\tsend(data: string) {\n\t\tif (this.room) {\n\t\t\tthis.room.send(data);\n\t\t} else {\n\t\t\tdata = this.pmTransform(data);\n\t\t\tthis.user.send(data);\n\t\t\tif (this.pmTarget && this.pmTarget !== this.user) {\n\t\t\t\tthis.pmTarget.send(data);\n\t\t\t}\n\t\t}\n\t}\n\n\t/** like privateModAction, but also notify Staff room */\n\tprivateGlobalModAction(msg: string) {\n\t\tif (this.room && !this.room.roomid.endsWith('staff')) {\n\t\t\tmsg = msg.replace(IPTools.ipRegex, '');\n\t\t}\n\t\tthis.privateModAction(msg);\n\t\tif (this.room?.roomid !== 'staff') {\n\t\t\tRooms.get('staff')?.addByUser(this.user, `${this.room ? `<<${this.room.roomid}>>` : ``} ${msg}`).update();\n\t\t}\n\t}\n\taddGlobalModAction(msg: string) {\n\t\tif (this.room && !this.room.roomid.endsWith('staff')) {\n\t\t\tmsg = msg.replace(IPTools.ipRegex, '');\n\t\t}\n\t\tthis.addModAction(msg);\n\t\tif (this.room?.roomid !== 'staff') {\n\t\t\tRooms.get('staff')?.addByUser(this.user, `${this.room ? `<<${this.room.roomid}>>` : ``} ${msg}`).update();\n\t\t}\n\t}\n\n\tprivateModAction(msg: string) {\n\t\tif (this.room) {\n\t\t\tif (this.room.roomid === 'staff') {\n\t\t\t\tthis.room.addByUser(this.user, `(${msg})`);\n\t\t\t} else {\n\t\t\t\tthis.room.sendModsByUser(this.user, `(${msg})`);\n\t\t\t\t// roomlogging in staff causes a duplicate log message, since we do addByUser\n\t\t\t\t// and roomlogging in pms has no effect, so we can _just_ call this here\n\t\t\t\tthis.roomlog(`(${msg})`);\n\t\t\t}\n\t\t} else {\n\t\t\tconst data = this.pmTransform(`|modaction|${msg}`);\n\t\t\tthis.user.send(data);\n\t\t\tif (this.pmTarget && this.pmTarget !== this.user && this.pmTarget.isStaff) {\n\t\t\t\tthis.pmTarget.send(data);\n\t\t\t}\n\t\t}\n\t}\n\tglobalModlog(action: string, user: string | User | null = null, note: string | null = null, ip?: string) {\n\t\tconst entry: PartialModlogEntry = {\n\t\t\taction,\n\t\t\tisGlobal: true,\n\t\t\tloggedBy: this.user.id,\n\t\t\tnote: note?.replace(/\\n/gm, ' ') || '',\n\t\t};\n\t\tif (user) {\n\t\t\tif (typeof user === 'string') {\n\t\t\t\tentry.userid = toID(user);\n\t\t\t} else {\n\t\t\t\tentry.ip = user.latestIp;\n\t\t\t\tconst userid = user.getLastId();\n\t\t\t\tentry.userid = userid;\n\t\t\t\tif (user.autoconfirmed && user.autoconfirmed !== userid) entry.autoconfirmedID = user.autoconfirmed;\n\t\t\t\tconst alts = user.getAltUsers(false, true).slice(1).map(alt => alt.getLastId());\n\t\t\t\tif (alts.length) entry.alts = alts;\n\t\t\t}\n\t\t}\n\t\tif (ip) entry.ip = ip;\n\t\tif (this.room) {\n\t\t\tthis.room.modlog(entry);\n\t\t} else {\n\t\t\tRooms.global.modlog(entry);\n\t\t}\n\t}\n\tmodlog(\n\t\taction: string,\n\t\tuser: string | User | null = null,\n\t\tnote: string | null = null,\n\t\toptions: Partial<{ noalts: any, noip: any }> = {}\n\t) {\n\t\tconst entry: PartialModlogEntry = {\n\t\t\taction,\n\t\t\tloggedBy: this.user.id,\n\t\t\tnote: note?.replace(/\\n/gm, ' ') || '',\n\t\t};\n\t\tif (user) {\n\t\t\tif (typeof user === 'string') {\n\t\t\t\tentry.userid = toID(user);\n\t\t\t} else {\n\t\t\t\tconst userid = user.getLastId();\n\t\t\t\tentry.userid = userid;\n\t\t\t\tif (!options.noalts) {\n\t\t\t\t\tif (user.autoconfirmed && user.autoconfirmed !== userid) entry.autoconfirmedID = user.autoconfirmed;\n\t\t\t\t\tconst alts = user.getAltUsers(false, true).slice(1).map(alt => alt.getLastId());\n\t\t\t\t\tif (alts.length) entry.alts = alts;\n\t\t\t\t}\n\t\t\t\tif (!options.noip) entry.ip = user.latestIp;\n\t\t\t}\n\t\t}\n\t\t(this.room || Rooms.global).modlog(entry);\n\t}\n\tparseSpoiler(reason: string) {\n\t\tif (!reason) return { publicReason: \"\", privateReason: \"\" };\n\n\t\tlet publicReason = reason;\n\t\tlet privateReason = reason;\n\t\tconst targetLowercase = reason.toLowerCase();\n\t\tif (targetLowercase.includes('spoiler:') || targetLowercase.includes('spoilers:')) {\n\t\t\tconst proofIndex = targetLowercase.indexOf(targetLowercase.includes('spoilers:') ? 'spoilers:' : 'spoiler:');\n\t\t\tconst proofOffset = (targetLowercase.includes('spoilers:') ? 9 : 8);\n\t\t\tconst proof = reason.slice(proofIndex + proofOffset).trim();\n\t\t\tpublicReason = reason.slice(0, proofIndex).trim();\n\t\t\tprivateReason = `${publicReason}${proof ? ` (PROOF: ${proof})` : ''}`;\n\t\t}\n\t\treturn { publicReason, privateReason };\n\t}\n\troomlog(data: string) {\n\t\tif (this.room) this.room.roomlog(data);\n\t}\n\tstafflog(data: string) {\n\t\t(Rooms.get('staff') || Rooms.lobby || this.room)?.roomlog(data);\n\t}\n\taddModAction(msg: string) {\n\t\tif (this.room) {\n\t\t\tthis.room.addByUser(this.user, msg);\n\t\t} else {\n\t\t\tthis.send(`|modaction|${msg}`);\n\t\t}\n\t}\n\tupdate() {\n\t\tif (this.room) this.room.update();\n\t}\n\tfilter(message: string) {\n\t\treturn Chat.filter(message, this);\n\t}\n\tstatusfilter(status: string) {\n\t\treturn Chat.statusfilter(status, this.user);\n\t}\n\tcheckCan(permission: RoomPermission, target: User | ID | null, room: Room): undefined;\n\tcheckCan(permission: GlobalPermission, target?: User | ID | null): undefined;\n\tcheckCan(permission: string, target: User | ID | null = null, room: Room | null = null) {\n\t\tif (!Users.Auth.hasPermission(this.user, permission, target, room, this.fullCmd, this.cmdToken)) {\n\t\t\tthrow new Chat.ErrorMessage(`${this.cmdToken}${this.fullCmd} - Access denied.`);\n\t\t}\n\t}\n\tprivatelyCheckCan(permission: RoomPermission, target: User | ID | null, room: Room): boolean;\n\tprivatelyCheckCan(permission: GlobalPermission, target?: User | ID | null): boolean;\n\tprivatelyCheckCan(permission: string, target: User | ID | null = null, room: Room | null = null) {\n\t\tthis.handler!.isPrivate = true;\n\t\tif (Users.Auth.hasPermission(this.user, permission, target, room, this.fullCmd, this.cmdToken)) {\n\t\t\treturn true;\n\t\t}\n\t\tthis.commandDoesNotExist();\n\t}\n\tcanUseConsole() {\n\t\tif (!this.user.hasConsoleAccess(this.connection)) {\n\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t(this.cmdToken + this.fullCmd).trim() + \" - Requires console access, please set up `Config.consoleips`.\"\n\t\t\t);\n\t\t}\n\t\treturn true;\n\t}\n\tshouldBroadcast() {\n\t\treturn this.cmdToken === BROADCAST_TOKEN;\n\t}\n\tcheckBroadcast(overrideCooldown?: boolean | string, suppressMessage?: string | null) {\n\t\tif (this.broadcasting || !this.shouldBroadcast()) {\n\t\t\treturn true;\n\t\t}\n\n\t\tif (this.user.locked && !(this.room?.roomid.startsWith('help-') || this.pmTarget?.can('lock'))) {\n\t\t\tthis.errorReply(`You cannot broadcast this command's information while locked.`);\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\n\t\t}\n\n\t\tif (this.room && !this.user.can('show', null, this.room, this.cmd, this.cmdToken)) {\n\t\t\tconst perm = this.room.settings.permissions?.[`!${this.cmd}`];\n\t\t\tconst atLeast = perm ? `at least rank ${perm}` : 'voiced';\n\t\t\tthis.errorReply(`You need to be ${atLeast} to broadcast this command's information.`);\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\n\t\t}\n\n\t\tif (!this.room && !this.pmTarget) {\n\t\t\tthis.errorReply(`Broadcasting a command with \"!\" in a PM or chatroom will show it that user or room.`);\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\n\t\t}\n\n\t\t// broadcast cooldown\n\t\tconst broadcastMessage = (suppressMessage || this.message).toLowerCase().replace(/[^a-z0-9\\s!,]/g, '');\n\t\tconst cooldownMessage = overrideCooldown === true ? null : (overrideCooldown || broadcastMessage);\n\n\t\tif (\n\t\t\tcooldownMessage && this.room && this.room.lastBroadcast === cooldownMessage &&\n\t\t\tthis.room.lastBroadcastTime >= Date.now() - BROADCAST_COOLDOWN\n\t\t) {\n\t\t\tthrow new Chat.ErrorMessage(`You can't broadcast this because it was just broadcasted. If this was intentional, use !rebroadcast ${this.message}`);\n\t\t}\n\n\t\tconst message = this.checkChat(suppressMessage || this.message);\n\t\tif (!message) {\n\t\t\tthrow new Chat.ErrorMessage(`To see it for yourself, use: /${this.message.slice(1)}`);\n\t\t}\n\n\t\t// checkChat will only return true with no message\n\t\tthis.message = message;\n\t\tthis.broadcastMessage = broadcastMessage;\n\t\treturn true;\n\t}\n\trunBroadcast(overrideCooldown?: boolean | string, suppressMessage: string | null = null) {\n\t\tif (this.broadcasting || !this.shouldBroadcast()) {\n\t\t\t// Already being broadcast, or the user doesn't intend to broadcast.\n\t\t\treturn true;\n\t\t}\n\n\t\tif (!this.broadcastMessage) {\n\t\t\t// Permission hasn't been checked yet. Do it now.\n\t\t\tthis.checkBroadcast(overrideCooldown, suppressMessage);\n\t\t}\n\n\t\tthis.broadcasting = true;\n\n\t\tconst message = `${this.broadcastPrefix}${suppressMessage || this.message}`;\n\t\tif (this.pmTarget) {\n\t\t\tthis.sendReply(`|c~|${message}`);\n\t\t} else {\n\t\t\tthis.sendReply(`|c|${this.user.getIdentity(this.room)}|${message}`);\n\t\t}\n\t\tif (this.room) {\n\t\t\t// We don't want broadcasted messages in a room to be translated\n\t\t\t// according to a user's personal language setting.\n\t\t\tthis.language = this.room.settings.language || null;\n\t\t\tif (overrideCooldown !== true) {\n\t\t\t\tthis.room.lastBroadcast = overrideCooldown || this.broadcastMessage;\n\t\t\t\tthis.room.lastBroadcastTime = Date.now();\n\t\t\t}\n\t\t}\n\n\t\treturn true;\n\t}\n\t/* The sucrase transformation of optional chaining is too expensive to be used in a hot function like this. */\n\tcheckChat(message: string, room?: Room | null, targetUser?: User | null): string;\n\tcheckChat(message?: null, room?: Room | null, targetUser?: User | null): void;\n\tcheckChat(message: string | null = null, room: Room | null = null, targetUser: User | null = null) {\n\t\tif (!targetUser && this.pmTarget) {\n\t\t\ttargetUser = this.pmTarget;\n\t\t}\n\t\tif (targetUser) {\n\t\t\troom = null;\n\t\t} else if (!room) {\n\t\t\troom = this.room;\n\t\t}\n\t\tconst user = this.user;\n\t\tconst connection = this.connection;\n\n\t\tif (!user.named) {\n\t\t\tthrow new Chat.ErrorMessage(this.tr`You must choose a name before you can talk.`);\n\t\t}\n\t\tif (!user.can('bypassall')) {\n\t\t\tconst lockType = (user.namelocked ? this.tr`namelocked` : user.locked ? this.tr`locked` : ``);\n\t\t\tconst lockExpiration = Punishments.checkLockExpiration(user.namelocked || user.locked);\n\t\t\tif (room) {\n\t\t\t\tif (lockType && !room.settings.isHelp) {\n\t\t\t\t\tthis.sendReply(`|html|${this.tr`Get help with this`}`);\n\t\t\t\t\tif (user.locked === '#hostfilter') {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are locked due to your proxy / VPN and can't talk in chat.`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are ${lockType} and can't talk in chat. ${lockExpiration}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!room.persist && !room.roomid.startsWith('help-') && !(user.registered || user.autoconfirmed)) {\n\t\t\t\t\tthis.sendReply(\n\t\t\t\t\t\tthis.tr`|html|
You must be registered to chat in temporary rooms (like battles).
` +\n\t\t\t\t\t\tthis.tr`You may register in the menu.`\n\t\t\t\t\t);\n\t\t\t\t\tthrow new Chat.Interruption();\n\t\t\t\t}\n\t\t\t\tif (room.isMuted(user)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are muted and cannot talk in this room.`);\n\t\t\t\t}\n\t\t\t\tif (room.settings.modchat && !room.auth.atLeast(user, room.settings.modchat)) {\n\t\t\t\t\tif (room.settings.modchat === 'autoconfirmed') {\n\t\t\t\t\t\tthis.errorReply(\n\t\t\t\t\t\t\tthis.tr`Moderated chat is set. To speak in this room, your account must be autoconfirmed, which means being registered for at least one week and winning at least one rated game (any game started through the 'Battle!' button).`\n\t\t\t\t\t\t);\n\t\t\t\t\t\tif (!user.registered) {\n\t\t\t\t\t\t\tthis.sendReply(this.tr`|html|You may register in the menu.`);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tthrow new Chat.Interruption();\n\t\t\t\t\t}\n\t\t\t\t\tif (room.settings.modchat === 'trusted') {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t\t\t\tthis.tr`Because moderated chat is set, your account must be staff in a public room or have a global rank to speak in this room.`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst groupName = Config.groups[room.settings.modchat] && Config.groups[room.settings.modchat].name ||\n\t\t\t\t\t\troom.settings.modchat;\n\t\t\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t\t\tthis.tr`Because moderated chat is set, you must be of rank ${groupName} or higher to speak in this room.`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!this.bypassRoomCheck && !(user.id in room.users)) {\n\t\t\t\t\tconnection.popup(`You can't send a message to this room without being in it.`);\n\t\t\t\t\treturn null;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (targetUser) {\n\t\t\t\t// this accounts for users who are autoconfirmed on another alt, but not registered\n\t\t\t\tif (!(user.registered || user.autoconfirmed)) {\n\t\t\t\t\tthis.sendReply(\n\t\t\t\t\t\tthis.tr`|html|
You must be registered to send private messages.
` +\n\t\t\t\t\t\tthis.tr`You may register in the menu.`\n\t\t\t\t\t);\n\t\t\t\t\tthrow new Chat.Interruption();\n\t\t\t\t}\n\t\t\t\tif (targetUser.id !== user.id && !(targetUser.registered || targetUser.autoconfirmed)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`That user is unregistered and cannot be PMed.`);\n\t\t\t\t}\n\t\t\t\tif (lockType && !targetUser.can('lock')) {\n\t\t\t\t\tthis.sendReply(`|html|${this.tr`Get help with this`}`);\n\t\t\t\t\tif (user.locked === '#hostfilter') {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are locked due to your proxy / VPN and can only private message members of the global moderation team.`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are ${lockType} and can only private message members of the global moderation team. ${lockExpiration}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (targetUser.locked && !user.can('lock')) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`The user \"${targetUser.name}\" is locked and cannot be PMed.`);\n\t\t\t\t}\n\t\t\t\tif (Config.pmmodchat && !Users.globalAuth.atLeast(user, Config.pmmodchat) &&\n\t\t\t\t\t!Users.Auth.hasPermission(targetUser, 'promote', Config.pmmodchat as GroupSymbol)) {\n\t\t\t\t\tconst groupName = Config.groups[Config.pmmodchat] && Config.groups[Config.pmmodchat].name || Config.pmmodchat;\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`On this server, you must be of rank ${groupName} or higher to PM users.`);\n\t\t\t\t}\n\t\t\t\tif (!this.checkCanPM(targetUser)) {\n\t\t\t\t\tChat.maybeNotifyBlocked('pm', targetUser, user);\n\t\t\t\t\tif (!targetUser.can('lock')) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`This user is blocking private messages right now.`);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.sendReply(`|html|${this.tr`If you need help, try opening a help ticket`}`);\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`This ${Config.groups[targetUser.tempGroup].name} is too busy to answer private messages right now. Please contact a different staff member.`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!this.checkCanPM(user, targetUser)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You are blocking private messages right now.`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (typeof message !== 'string') return true;\n\n\t\tif (!message) {\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message can't be blank.`);\n\t\t}\n\t\tlet length = message.length;\n\t\tlength += 10 * message.replace(/[^\\ufdfd]*/g, '').length;\n\t\tif (length > MAX_MESSAGE_LENGTH && !user.can('ignorelimits')) {\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message is too long: ` + message);\n\t\t}\n\n\t\t// remove zalgo\n\t\tmessage = message.replace(\n\t\t\t/[\\u0300-\\u036f\\u0483-\\u0489\\u0610-\\u0615\\u064B-\\u065F\\u0670\\u06D6-\\u06DC\\u06DF-\\u06ED\\u0E31\\u0E34-\\u0E3A\\u0E47-\\u0E4E]{3,}/g,\n\t\t\t''\n\t\t);\n\t\tif (/[\\u3164\\u115f\\u1160\\u239b-\\u23b9]/.test(message)) {\n\t\t\tthrow new Chat.ErrorMessage(this.tr`Your message contains banned characters.`);\n\t\t}\n\n\t\t// If the corresponding config option is set, non-AC users cannot send links, except to staff.\n\t\tif (Config.restrictLinks && !user.autoconfirmed) {\n\t\t\tif (this.checkBannedLinks(message).length && !(targetUser?.can('lock') || room?.settings.isHelp)) {\n\t\t\t\tthrow new Chat.ErrorMessage(\"Your account must be autoconfirmed to send links to other users, except for global staff.\");\n\t\t\t}\n\t\t}\n\n\t\tthis.checkFormat(room, user, message);\n\n\t\tthis.checkSlowchat(room, user);\n\n\t\tif (room && !user.can('mute', null, room)) this.checkBanwords(room, message);\n\n\t\tconst gameFilter = this.checkGameFilter();\n\t\tif (typeof gameFilter === 'string') {\n\t\t\tif (gameFilter === '') throw new Chat.Interruption();\n\t\t\tthrow new Chat.ErrorMessage(gameFilter);\n\t\t}\n\n\t\tif (room?.settings.highTraffic &&\n\t\t\ttoID(message).replace(/[^a-z]+/, '').length < 2 &&\n\t\t\t!user.can('show', null, room)) {\n\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\tthis.tr`Due to this room being a high traffic room, your message must contain at least two letters.`\n\t\t\t);\n\t\t}\n\n\t\tif (room) {\n\t\t\tconst normalized = message.trim();\n\t\t\tif (\n\t\t\t\t!user.can('bypassall') && (['help', 'lobby'].includes(room.roomid)) && (normalized === user.lastMessage) &&\n\t\t\t\t((Date.now() - user.lastMessageTime) < MESSAGE_COOLDOWN) && !Config.nothrottle\n\t\t\t) {\n\t\t\t\tthrow new Chat.ErrorMessage(this.tr`You can't send the same message again so soon.`);\n\t\t\t}\n\t\t\tuser.lastMessage = message;\n\t\t\tuser.lastMessageTime = Date.now();\n\t\t}\n\n\t\tif (Chat.filters.length) {\n\t\t\treturn this.filter(message);\n\t\t}\n\n\t\treturn message;\n\t}\n\tcheckCanPM(targetUser: User, user?: User) {\n\t\tif (!user) user = this.user;\n\t\tif (user.id === targetUser.id) return true; // lol.\n\t\tconst setting = targetUser.settings.blockPMs;\n\t\tif (user.can('lock') || !setting) return true;\n\t\tif (setting === true && !user.can('lock')) return false; // this is to appease TS\n\t\tconst friends = targetUser.friends || new Set();\n\t\tif (setting === 'friends') return friends.has(user.id);\n\t\treturn Users.globalAuth.atLeast(user, setting as AuthLevel);\n\t}\n\tcheckPMHTML(targetUser: User) {\n\t\tif (!(this.room && (targetUser.id in this.room.users)) && !this.user.can('addhtml')) {\n\t\t\tthrow new Chat.ErrorMessage(\"You do not have permission to use PM HTML to users who are not in this room.\");\n\t\t}\n\t\tconst friends = targetUser.friends || new Set();\n\t\tif (\n\t\t\ttargetUser.settings.blockPMs &&\n\t\t\t(targetUser.settings.blockPMs === true ||\n\t\t\t\t(targetUser.settings.blockPMs === 'friends' && !friends.has(this.user.id)) ||\n\t\t\t\t!Users.globalAuth.atLeast(this.user, targetUser.settings.blockPMs as AuthLevel)) &&\n\t\t\t\t!this.user.can('lock')\n\t\t) {\n\t\t\tChat.maybeNotifyBlocked('pm', targetUser, this.user);\n\t\t\tthrow new Chat.ErrorMessage(\"This user is currently blocking PMs.\");\n\t\t}\n\t\tif (targetUser.locked && !this.user.can('lock')) {\n\t\t\tthrow new Chat.ErrorMessage(\"This user is currently locked, so you cannot send them HTML.\");\n\t\t}\n\t\treturn true;\n\t}\n\n\tcheckBannedLinks(message: string) {\n\t\t// RegExp#exec only returns one match, String#match returns all of them\n\t\treturn (message.match(Chat.linkRegex) || []).filter(link => {\n\t\t\tlink = link.toLowerCase();\n\t\t\tconst domainMatches = /^(?:http:\\/\\/|https:\\/\\/)?(?:[^/]*\\.)?([^/.]*\\.[^/.]*)\\.?($|\\/|:)/.exec(link);\n\t\t\tconst domain = domainMatches?.[1];\n\t\t\tconst hostMatches = /^(?:http:\\/\\/|https:\\/\\/)?([^/]*[^/.])\\.?($|\\/|:)/.exec(link);\n\t\t\tlet host = hostMatches?.[1];\n\t\t\tif (host?.startsWith('www.')) host = host.slice(4);\n\t\t\tif (!domain || !host) return null;\n\t\t\treturn !(LINK_WHITELIST.includes(host) || LINK_WHITELIST.includes(`*.${domain}`));\n\t\t});\n\t}\n\tcheckEmbedURI(uri: string) {\n\t\tif (uri.startsWith('https://')) return uri;\n\t\tif (uri.startsWith('//')) return uri;\n\t\tif (uri.startsWith('data:')) {\n\t\t\treturn uri;\n\t\t} else {\n\t\t\tthrow new Chat.ErrorMessage(\"Image URLs must begin with 'https://' or 'data:'; 'http://' cannot be used.\");\n\t\t}\n\t}\n\t/**\n\t * This is a quick and dirty first-pass \"is this good HTML\" check. The full\n\t * sanitization is done on the client by Caja in `src/battle-log.ts`\n\t * `BattleLog.sanitizeHTML`.\n\t */\n\tcheckHTML(htmlContent: string | null) {\n\t\thtmlContent = `${htmlContent || ''}`.trim();\n\t\tif (!htmlContent) return '';\n\t\tif (/>here.?]]');\n\t\t}\n\n\t\t// check for mismatched tags\n\t\tconst tags = htmlContent.match(/|<\\/?[^<>]*/g);\n\t\tif (tags) {\n\t\t\tconst ILLEGAL_TAGS = [\n\t\t\t\t'script', 'head', 'body', 'html', 'canvas', 'base', 'meta', 'link', 'iframe',\n\t\t\t];\n\t\t\tconst LEGAL_AUTOCLOSE_TAGS = [\n\t\t\t\t// void elements (no-close tags)\n\t\t\t\t'br', 'area', 'embed', 'hr', 'img', 'source', 'track', 'input', 'wbr', 'col',\n\t\t\t\t// autoclose tags\n\t\t\t\t'p', 'li', 'dt', 'dd', 'option', 'tr', 'th', 'td', 'thead', 'tbody', 'tfoot', 'colgroup',\n\t\t\t\t// PS custom element\n\t\t\t\t'psicon', 'youtube',\n\t\t\t];\n\t\t\tconst stack = [];\n\t\t\tfor (const tag of tags) {\n\t\t\t\tconst isClosingTag = tag.charAt(1) === '/';\n\t\t\t\tconst contentEndLoc = tag.endsWith('/') ? -1 : undefined;\n\t\t\t\tconst tagContent = tag.slice(isClosingTag ? 2 : 1, contentEndLoc).replace(/\\s+/, ' ').trim();\n\t\t\t\tconst tagNameEndIndex = tagContent.indexOf(' ');\n\t\t\t\tconst tagName = tagContent.slice(0, tagNameEndIndex >= 0 ? tagNameEndIndex : undefined).toLowerCase();\n\t\t\t\tif (tagName === '!--') continue;\n\t\t\t\tif (isClosingTag) {\n\t\t\t\t\tif (LEGAL_AUTOCLOSE_TAGS.includes(tagName)) continue;\n\t\t\t\t\tif (!stack.length) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Extraneous without an opening tag.`);\n\t\t\t\t\t}\n\t\t\t\t\tconst expectedTagName = stack.pop();\n\t\t\t\t\tif (tagName !== expectedTagName) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Extraneous where was expected.`);\n\t\t\t\t\t}\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (ILLEGAL_TAGS.includes(tagName) || !/^[a-z]+[0-9]?$/.test(tagName)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(`Illegal tag <${tagName}> can't be used here.`);\n\t\t\t\t}\n\t\t\t\tif (!LEGAL_AUTOCLOSE_TAGS.includes(tagName)) {\n\t\t\t\t\tstack.push(tagName);\n\t\t\t\t}\n\n\t\t\t\tif (tagName === 'img') {\n\t\t\t\t\tif (!this.room || (this.room.settings.isPersonal && !this.user.can('lock'))) {\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\t\t\t\t`This tag is not allowed: <${tagContent}>. Images are not allowed outside of chatrooms.`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (!/width ?= ?(?:[0-9]+|\"[0-9]+\")/i.test(tagContent) || !/height ?= ?(?:[0-9]+|\"[0-9]+\")/i.test(tagContent)) {\n\t\t\t\t\t\t// Width and height are required because most browsers insert the\n\t\t\t\t\t\t// element before width and height are known, and when the\n\t\t\t\t\t\t// image is loaded, this changes the height of the chat area, which\n\t\t\t\t\t\t// messes up autoscrolling.\n\t\t\t\t\t\tthis.errorReply(`This image is missing a width/height attribute: <${tagContent}>`);\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Images without predefined width/height cause problems with scrolling because loading them changes their height.`);\n\t\t\t\t\t}\n\t\t\t\t\tconst srcMatch = / src ?= ?(?:\"|')?([^ \"']+)(?: ?(?:\"|'))?/i.exec(tagContent);\n\t\t\t\t\tif (srcMatch) {\n\t\t\t\t\t\tthis.checkEmbedURI(srcMatch[1]);\n\t\t\t\t\t} else {\n\t\t\t\t\t\tthis.errorReply(`This image has a broken src attribute: <${tagContent}>`);\n\t\t\t\t\t\tthrow new Chat.ErrorMessage(`The src attribute must exist and have no spaces in the URL`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (tagName === 'button') {\n\t\t\t\t\tif ((!this.room || this.room.settings.isPersonal || this.room.settings.isPrivate === true) && !this.user.can('lock')) {\n\t\t\t\t\t\tconst buttonName = / name ?= ?\"([^\"]*)\"/i.exec(tagContent)?.[1];\n\t\t\t\t\t\tconst buttonValue = / value ?= ?\"([^\"]*)\"/i.exec(tagContent)?.[1];\n\t\t\t\t\t\tconst msgCommandRegex = /^\\/(?:msg|pm|w|whisper|botmsg) /;\n\t\t\t\t\t\tconst botmsgCommandRegex = /^\\/msgroom (?:[a-z0-9-]+), ?\\/botmsg /;\n\t\t\t\t\t\tif (buttonName === 'send' && buttonValue && msgCommandRegex.test(buttonValue)) {\n\t\t\t\t\t\t\tconst [pmTarget] = buttonValue.replace(msgCommandRegex, '').split(',');\n\t\t\t\t\t\t\tconst auth = this.room ? this.room.auth : Users.globalAuth;\n\t\t\t\t\t\t\tif (auth.get(toID(pmTarget)) !== '*' && toID(pmTarget) !== this.user.id) {\n\t\t\t\t\t\t\t\tthis.errorReply(`This button is not allowed: <${tagContent}>`);\n\t\t\t\t\t\t\t\tthrow new Chat.ErrorMessage(`Your scripted button can't send PMs to ${pmTarget}, because that user is not a Room Bot.`);\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else if (buttonName === 'send' && buttonValue && botmsgCommandRegex.test(buttonValue)) {\n\t\t\t\t\t\t\t// no need to validate the bot being an actual bot; `/botmsg` will do it for us and is not abusable\n\t\t\t\t\t\t} else if (buttonName) {\n\t\t\t\t\t\t\tthis.errorReply(`This button is not allowed: <${tagContent}>`);\n\t\t\t\t\t\t\tthis.errorReply(`You do not have permission to use most buttons. Here are the two types you're allowed to use:`);\n\t\t\t\t\t\t\tthis.errorReply(`1. Linking to a room: `);\n\t\t\t\t\t\t\tthrow new Chat.ErrorMessage(`2. Sending a message to a Bot: `);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (stack.length) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Missing .`);\n\t\t\t}\n\t\t}\n\n\t\treturn htmlContent;\n\t}\n\n\t/**\n\t * This is to be used for commands that replicate other commands\n\t * (for example, `/pm username, command` or `/msgroom roomid, command`)\n\t * to ensure they do not crash with too many levels of recursion.\n\t */\n\tcheckRecursion() {\n\t\tif (this.recursionDepth > 5) {\n\t\t\tthrow new Chat.ErrorMessage(`/${this.cmd} - Too much command recursion has occurred.`);\n\t\t}\n\t}\n\n\trequireRoom(id?: RoomID) {\n\t\tif (!this.room) {\n\t\t\tthrow new Chat.ErrorMessage(`/${this.cmd} - must be used in a chat room, not a ${this.pmTarget ? \"PM\" : \"console\"}`);\n\t\t}\n\t\tif (id && this.room.roomid !== id) {\n\t\t\tconst targetRoom = Rooms.get(id);\n\t\t\tif (!targetRoom) {\n\t\t\t\tthrow new Chat.ErrorMessage(`This command can only be used in the room '${id}', but that room does not exist.`);\n\t\t\t}\n\t\t\tthrow new Chat.ErrorMessage(`This command can only be used in the ${targetRoom.title} room.`);\n\t\t}\n\t\treturn this.room;\n\t}\n\trequireGame(constructor: new (...args: any[]) => T, subGame = false) {\n\t\tconst room = this.requireRoom();\n\t\tif (subGame) {\n\t\t\tif (!room.subGame) {\n\t\t\t\tthrow new Chat.ErrorMessage(`This command requires a sub-game of ${constructor.name} (this room has no sub-game).`);\n\t\t\t}\n\t\t\tconst game = room.getGame(constructor, subGame);\n\t\t\t// must be a different game\n\t\t\tif (!game) {\n\t\t\t\tthrow new Chat.ErrorMessage(`This command requires a sub-game of ${constructor.name} (this sub-game is ${room.subGame.title}).`);\n\t\t\t}\n\t\t\treturn game;\n\t\t}\n\t\tif (!room.game) {\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a game of ${constructor.name} (this room has no game).`);\n\t\t}\n\t\tconst game = room.getGame(constructor);\n\t\t// must be a different game\n\t\tif (!game) {\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a game of ${constructor.name} (this game is ${room.game.title}).`);\n\t\t}\n\t\treturn game;\n\t}\n\trequireMinorActivity(constructor: new (...args: any[]) => T) {\n\t\tconst room = this.requireRoom();\n\t\tif (!room.minorActivity) {\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a ${constructor.name} (this room has no minor activity).`);\n\t\t}\n\t\tconst game = room.getMinorActivity(constructor);\n\t\t// must be a different game\n\t\tif (!game) {\n\t\t\tthrow new Chat.ErrorMessage(`This command requires a ${constructor.name} (this minor activity is a(n) ${room.minorActivity.name}).`);\n\t\t}\n\t\treturn game;\n\t}\n\tcommandDoesNotExist(): never {\n\t\tif (this.cmdToken === '!') {\n\t\t\tthrow new Chat.ErrorMessage(`The command \"${this.cmdToken}${this.fullCmd}\" does not exist.`);\n\t\t}\n\t\tthrow new Chat.ErrorMessage(\n\t\t\t`The command \"${(this.cmdToken + this.fullCmd).trim()}\" does not exist. To send a message starting with \"${this.cmdToken}${this.fullCmd}\", type \"${this.cmdToken}${this.cmdToken}${this.fullCmd}\".`\n\t\t);\n\t}\n\trefreshPage(pageid: string) {\n\t\tif (this.connection.openPages?.has(pageid)) {\n\t\t\tthis.parse(`/join view-${pageid}`);\n\t\t}\n\t}\n\tclosePage(pageid: string) {\n\t\tfor (const connection of this.user.connections) {\n\t\t\tif (connection.openPages?.has(pageid)) {\n\t\t\t\tconnection.send(`>view-${pageid}\\n|deinit`);\n\t\t\t\tconnection.openPages.delete(pageid);\n\t\t\t\tif (!connection.openPages.size) {\n\t\t\t\t\tconnection.openPages = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n}\n\nexport const Chat = new class {\n\tconstructor() {\n\t\tvoid this.loadTranslations().then(() => {\n\t\t\tChat.translationsLoaded = true;\n\t\t});\n\t}\n\ttranslationsLoaded = false;\n\t/**\n\t * As per the node.js documentation at https://nodejs.org/api/timers.html#timers_settimeout_callback_delay_args,\n\t * timers with durations that are too long for a 32-bit signed integer will be invoked after 1 millisecond,\n\t * which tends to cause unexpected behavior.\n\t */\n\treadonly MAX_TIMEOUT_DURATION = 2147483647;\n\treadonly Friends = new FriendsDatabase();\n\treadonly PM = PM;\n\treadonly PrivateMessages = PrivateMessages;\n\n\treadonly multiLinePattern = new PatternTester();\n\n\t/*********************************************************\n\t * Load command files\n\t *********************************************************/\n\tbaseCommands!: AnnotatedChatCommands;\n\tcommands!: AnnotatedChatCommands;\n\tbasePages!: PageTable;\n\tpages!: PageTable;\n\treadonly destroyHandlers: (() => void)[] = [Artemis.destroy];\n\treadonly crqHandlers: { [k: string]: CRQHandler } = {};\n\treadonly handlers: { [k: string]: ((...args: any) => any)[] } = Object.create(null);\n\t/** The key is the name of the plugin. */\n\treadonly plugins: { [k: string]: ChatPlugin } = {};\n\t/** Will be empty except during hotpatch */\n\toldPlugins: { [k: string]: ChatPlugin } = {};\n\troomSettings: SettingsHandler[] = [];\n\n\t/*********************************************************\n\t * Load chat filters\n\t *********************************************************/\n\treadonly filters: ChatFilter[] = [];\n\tfilter(message: string, context: CommandContext) {\n\t\t// Chat filters can choose to:\n\t\t// 1. return false OR null - to not send a user's message\n\t\t// 2. return an altered string - to alter a user's message\n\t\t// 3. return undefined to send the original message through\n\t\tconst originalMessage = message;\n\t\tfor (const curFilter of Chat.filters) {\n\t\t\tconst output = curFilter.call(\n\t\t\t\tcontext,\n\t\t\t\tmessage,\n\t\t\t\tcontext.user,\n\t\t\t\tcontext.room,\n\t\t\t\tcontext.connection,\n\t\t\t\tcontext.pmTarget,\n\t\t\t\toriginalMessage\n\t\t\t);\n\t\t\tif (output === false) return null;\n\t\t\tif (!output && output !== undefined) return output;\n\t\t\tif (output !== undefined) message = output;\n\t\t}\n\n\t\treturn message;\n\t}\n\n\treadonly namefilters: NameFilter[] = [];\n\tnamefilter(name: string, user: User) {\n\t\tif (!Config.disablebasicnamefilter) {\n\t\t\t// whitelist\n\t\t\t// \\u00A1-\\u00BF\\u00D7\\u00F7 Latin punctuation/symbols\n\t\t\t// \\u02B9-\\u0362 basic combining accents\n\t\t\t// \\u2012-\\u2027\\u2030-\\u205E Latin punctuation/symbols extended\n\t\t\t// \\u2050-\\u205F fractions extended\n\t\t\t// \\u2190-\\u23FA\\u2500-\\u2BD1 misc symbols\n\t\t\t// \\u2E80-\\u32FF CJK symbols\n\t\t\t// \\u3400-\\u9FFF CJK\n\t\t\t// \\uF900-\\uFAFF\\uFE00-\\uFE6F CJK extended\n\t\t\tname = name.replace(\n\t\t\t\t// eslint-disable-next-line no-misleading-character-class\n\t\t\t\t/[^a-zA-Z0-9 /\\\\.~()<>^*%&=+$#_'?!\"\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2190-\\u23FA\\u2500-\\u2BD1\\u2E80-\\u32FF\\u3400-\\u9FFF\\uF900-\\uFAFF\\uFE00-\\uFE6F-]+/g,\n\t\t\t\t''\n\t\t\t);\n\n\t\t\t// blacklist\n\t\t\t// \\u00a1 upside-down exclamation mark (i)\n\t\t\t// \\u2580-\\u2590 black bars\n\t\t\t// \\u25A0\\u25Ac\\u25AE\\u25B0 black bars\n\t\t\t// \\u534d\\u5350 swastika\n\t\t\t// \\u2a0d crossed integral (f)\n\t\t\tname = name.replace(/[\\u00a1\\u2580-\\u2590\\u25A0\\u25Ac\\u25AE\\u25B0\\u2a0d\\u534d\\u5350]/g, '');\n\n\t\t\t// e-mail address\n\t\t\tif (name.includes('@') && name.includes('.')) return '';\n\n\t\t\t// url\n\t\t\tif (/[a-z0-9]\\.(com|net|org|us|uk|co|gg|tk|ml|gq|ga|xxx|download|stream)\\b/i.test(name)) name = name.replace(/\\./g, '');\n\n\t\t\t// Limit the amount of symbols allowed in usernames to 4 maximum, and\n\t\t\t// disallow (R) and (C) from being used in the middle of names.\n\t\t\tconst nameSymbols = name.replace(\n\t\t\t\t/[^\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2090-\\u23FA\\u2500-\\u2BD1]+/g,\n\t\t\t\t''\n\t\t\t);\n\t\t\t// \\u00ae\\u00a9 (R) (C)\n\t\t\tif (\n\t\t\t\tnameSymbols.length > 4 ||\n\t\t\t\t/[^a-z0-9][a-z0-9][^a-z0-9]/.test(name.toLowerCase() + ' ') || /[\\u00ae\\u00a9].*[a-zA-Z0-9]/.test(name)\n\t\t\t) {\n\t\t\t\tname = name.replace(\n\t\t\t\t\t// eslint-disable-next-line no-misleading-character-class\n\t\t\t\t\t/[\\u00A1-\\u00BF\\u00D7\\u00F7\\u02B9-\\u0362\\u2012-\\u2027\\u2030-\\u205E\\u2050-\\u205F\\u2190-\\u23FA\\u2500-\\u2BD1\\u2E80-\\u32FF\\u3400-\\u9FFF\\uF900-\\uFAFF\\uFE00-\\uFE6F]+/g,\n\t\t\t\t\t''\n\t\t\t\t).replace(/[^A-Za-z0-9]{2,}/g, ' ').trim();\n\t\t\t}\n\t\t}\n\t\tname = name.replace(/^[^A-Za-z0-9]+/, \"\"); // remove symbols from start\n\t\tname = name.replace(/@/g, \"\"); // Remove @ as this is used to indicate status messages\n\n\t\t// cut name length down to 18 chars\n\t\tif (/[A-Za-z0-9]/.test(name.slice(18))) {\n\t\t\tname = name.replace(/[^A-Za-z0-9]+/g, \"\");\n\t\t} else {\n\t\t\tname = name.slice(0, 18);\n\t\t}\n\n\t\tname = Dex.getName(name);\n\t\tfor (const curFilter of Chat.namefilters) {\n\t\t\tname = curFilter(name, user);\n\t\t\tif (!name) return '';\n\t\t}\n\t\treturn name;\n\t}\n\n\treadonly hostfilters: HostFilter[] = [];\n\thostfilter(host: string, user: User, connection: Connection, hostType: string) {\n\t\tfor (const curFilter of Chat.hostfilters) {\n\t\t\tcurFilter(host, user, connection, hostType);\n\t\t}\n\t}\n\n\treadonly loginfilters: LoginFilter[] = [];\n\tloginfilter(user: User, oldUser: User | null, usertype: string) {\n\t\tfor (const curFilter of Chat.loginfilters) {\n\t\t\tcurFilter(user, oldUser, usertype);\n\t\t}\n\t}\n\n\treadonly punishmentfilters: PunishmentFilter[] = [];\n\tpunishmentfilter(user: User | ID, punishment: Punishment) {\n\t\tfor (const curFilter of Chat.punishmentfilters) {\n\t\t\tcurFilter(user, punishment);\n\t\t}\n\t}\n\n\treadonly nicknamefilters: NicknameFilter[] = [];\n\tnicknamefilter(nickname: string, user: User) {\n\t\tfor (const curFilter of Chat.nicknamefilters) {\n\t\t\tconst filtered = curFilter(nickname, user);\n\t\t\tif (filtered === false) return false;\n\t\t\tif (!filtered) return '';\n\t\t}\n\t\treturn nickname;\n\t}\n\n\treadonly statusfilters: StatusFilter[] = [];\n\tstatusfilter(status: string, user: User) {\n\t\tstatus = status.replace(/\\|/g, '');\n\t\tfor (const curFilter of Chat.statusfilters) {\n\t\t\tstatus = curFilter(status, user);\n\t\t\tif (!status) return '';\n\t\t}\n\t\treturn status;\n\t}\n\t/*********************************************************\n\t * Translations\n\t *********************************************************/\n\t/** language id -> language name */\n\treadonly languages = new Map();\n\t/** language id -> (english string -> translated string) */\n\treadonly translations = new Map>();\n\n\tasync loadTranslations() {\n\t\tconst directories = await FS(TRANSLATION_DIRECTORY).readdir();\n\n\t\t// ensure that english is the first entry when we iterate over Chat.languages\n\t\tChat.languages.set('english' as ID, 'English');\n\t\tfor (const dirname of directories) {\n\t\t\t// translation dirs shouldn't have caps, but things like sourceMaps and the README will\n\t\t\tif (/[^a-z0-9]/.test(dirname)) continue;\n\t\t\tconst dir = FS(`${TRANSLATION_DIRECTORY}/${dirname}`);\n\n\t\t\t// For some reason, toID() isn't available as a global when this executes.\n\t\t\tconst languageID = Dex.toID(dirname);\n\t\t\tconst files = await dir.readdir();\n\t\t\tfor (const filename of files) {\n\t\t\t\tif (!filename.endsWith('.js')) continue;\n\n\t\t\t\tconst content: Translations = require(`${TRANSLATION_DIRECTORY}/${dirname}/${filename}`).translations;\n\n\t\t\t\tif (!Chat.translations.has(languageID)) {\n\t\t\t\t\tChat.translations.set(languageID, new Map());\n\t\t\t\t}\n\t\t\t\tconst translationsSoFar = Chat.translations.get(languageID)!;\n\n\t\t\t\tif (content.name && !Chat.languages.has(languageID)) {\n\t\t\t\t\tChat.languages.set(languageID, content.name);\n\t\t\t\t}\n\n\t\t\t\tif (content.strings) {\n\t\t\t\t\tfor (const key in content.strings) {\n\t\t\t\t\t\tconst keyLabels: string[] = [];\n\t\t\t\t\t\tconst valLabels: string[] = [];\n\t\t\t\t\t\tconst newKey = key.replace(/\\${.+?}/g, str => {\n\t\t\t\t\t\t\tkeyLabels.push(str);\n\t\t\t\t\t\t\treturn '${}';\n\t\t\t\t\t\t}).replace(/\\[TN: ?.+?\\]/g, '');\n\t\t\t\t\t\tconst val = content.strings[key].replace(/\\${.+?}/g, (str: string) => {\n\t\t\t\t\t\t\tvalLabels.push(str);\n\t\t\t\t\t\t\treturn '${}';\n\t\t\t\t\t\t}).replace(/\\[TN: ?.+?\\]/g, '');\n\t\t\t\t\t\ttranslationsSoFar.set(newKey, [val, keyLabels, valLabels]);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!Chat.languages.has(languageID)) {\n\t\t\t\t// Fallback in case no translation files provide the language's name\n\t\t\t\tChat.languages.set(languageID, \"Unknown Language\");\n\t\t\t}\n\t\t}\n\t}\n\ttr(language: ID | null): (fStrings: TemplateStringsArray | string, ...fKeys: any) => string;\n\ttr(language: ID | null, strings: TemplateStringsArray | string, ...keys: any[]): string;\n\ttr(language: ID | null, strings: TemplateStringsArray | string = '', ...keys: any[]) {\n\t\tif (!language) language = 'english' as ID;\n\t\t// If strings is an array (normally the case), combine before translating.\n\t\tconst trString = typeof strings === 'string' ? strings : strings.join('${}');\n\n\t\tif (Chat.translationsLoaded && !Chat.translations.has(language)) {\n\t\t\tthrow new Error(`Trying to translate to a nonexistent language: ${language}`);\n\t\t}\n\t\tif (!strings.length) {\n\t\t\treturn (fStrings: TemplateStringsArray | string, ...fKeys: any) => Chat.tr(language, fStrings, ...fKeys);\n\t\t}\n\n\t\tconst entry = Chat.translations.get(language)?.get(trString);\n\t\tlet [translated, keyLabels, valLabels] = entry || [\"\", [], []];\n\t\tif (!translated) translated = trString;\n\n\t\t// Replace the gaps in the species string\n\t\tif (keys.length) {\n\t\t\tlet reconstructed = '';\n\n\t\t\tconst left: (string | null)[] = keyLabels.slice();\n\t\t\tfor (const [i, str] of translated.split('${}').entries()) {\n\t\t\t\treconstructed += str;\n\t\t\t\tif (keys[i]) {\n\t\t\t\t\tlet index = left.indexOf(valLabels[i]);\n\t\t\t\t\tif (index < 0) {\n\t\t\t\t\t\tindex = left.findIndex(val => !!val);\n\t\t\t\t\t}\n\t\t\t\t\tif (index < 0) index = i;\n\t\t\t\t\treconstructed += keys[index];\n\t\t\t\t\tleft[index] = null;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\ttranslated = reconstructed;\n\t\t}\n\t\treturn translated;\n\t}\n\n\t/**\n\t * SQL handler\n\t *\n\t * All chat plugins share one database.\n\t * Chat.databaseReadyPromise will be truthy if the database is not yet ready.\n\t */\n\tdatabase = SQL(module, {\n\t\tfile: global.Config?.nofswriting ? ':memory:' : PLUGIN_DATABASE_PATH,\n\t\tprocesses: global.Config?.chatdbprocesses,\n\t});\n\tdatabaseReadyPromise: Promise | null = null;\n\n\tasync prepareDatabase() {\n\t\t// PLEASE NEVER ACTUALLY ADD MIGRATIONS\n\t\t// things break in weird ways that are hard to reason about, probably because of subprocesses\n\t\t// it WILL crash and it WILL make your life and that of your users extremely unpleasant until it is fixed\n\t\tif (process.send) return; // We don't need a database in a subprocess that requires Chat.\n\t\tif (!Config.usesqlite) return;\n\t\t// check if we have the db_info table, which will always be present unless the schema needs to be initialized\n\t\tconst { hasDBInfo } = await this.database.get(\n\t\t\t`SELECT count(*) AS hasDBInfo FROM sqlite_master WHERE type = 'table' AND name = 'db_info'`\n\t\t);\n\t\tif (!hasDBInfo) await this.database.runFile('./databases/schemas/chat-plugins.sql');\n\n\t\tconst result = await this.database.get(\n\t\t\t`SELECT value as curVersion FROM db_info WHERE key = 'version'`\n\t\t);\n\t\tconst curVersion = parseInt(result.curVersion);\n\t\tif (!curVersion) throw new Error(`db_info table is present, but schema version could not be parsed`);\n\n\t\t// automatically run migrations of the form \"v{number}.sql\" in the migrations/chat-plugins folder\n\t\tconst migrationsFolder = './databases/migrations/chat-plugins';\n\t\tconst migrationsToRun = [];\n\t\tfor (const migrationFile of (await FS(migrationsFolder).readdir())) {\n\t\t\tconst migrationVersion = parseInt(/v(\\d+)\\.sql$/.exec(migrationFile)?.[1] || '');\n\t\t\tif (!migrationVersion) continue;\n\t\t\tif (migrationVersion > curVersion) {\n\t\t\t\tmigrationsToRun.push({ version: migrationVersion, file: migrationFile });\n\t\t\t\tMonitor.adminlog(`Pushing to migrationsToRun: ${migrationVersion} at ${migrationFile} - mainModule ${process.mainModule === module} !process.send ${!process.send}`);\n\t\t\t}\n\t\t}\n\t\tUtils.sortBy(migrationsToRun, ({ version }) => version);\n\t\tfor (const { file } of migrationsToRun) {\n\t\t\tawait this.database.runFile(pathModule.resolve(migrationsFolder, file));\n\t\t}\n\n\t\tChat.destroyHandlers.push(\n\t\t\t() => void Chat.database?.destroy(),\n\t\t\t() => Chat.PrivateMessages.destroy(),\n\t\t);\n\t}\n\n\treadonly MessageContext = MessageContext;\n\treadonly CommandContext = CommandContext;\n\treadonly PageContext = PageContext;\n\treadonly ErrorMessage = ErrorMessage;\n\treadonly Interruption = Interruption;\n\n\t// JSX handling\n\treadonly JSX = JSX;\n\treadonly html = JSX.html;\n\treadonly h = JSX.h;\n\treadonly Fragment = JSX.Fragment;\n\n\t/**\n\t * Command parser\n\t *\n\t * Usage:\n\t * Chat.parse(message, room, user, connection)\n\t *\n\t * Parses the message. If it's a command, the command is executed, if\n\t * not, it's displayed directly in the room.\n\t *\n\t * Examples:\n\t * Chat.parse(\"/join lobby\", room, user, connection)\n\t * will make the user join the lobby.\n\t *\n\t * Chat.parse(\"Hi, guys!\", room, user, connection)\n\t * will return \"Hi, guys!\" if the user isn't muted, or\n\t * if he's muted, will warn him that he's muted.\n\t *\n\t * The return value is the return value of the command handler, if any,\n\t * or the message, if there wasn't a command. This value could be a success\n\t * or failure (few commands report these) or a Promise for when the command\n\t * is done executing, if it's not currently done.\n\t *\n\t * @param message - the message the user is trying to say\n\t * @param room - the room the user is trying to say it in\n\t * @param user - the user that sent the message\n\t * @param connection - the connection the user sent the message from\n\t */\n\tparse(message: string, room: Room | null | undefined, user: User, connection: Connection) {\n\t\tChat.loadPlugins();\n\n\t\tconst initialRoomlogLength = room?.log.getLineCount();\n\t\tconst context = new CommandContext({ message, room, user, connection });\n\t\tconst start = Date.now();\n\t\tconst result = context.parse();\n\t\tif (typeof result?.then === 'function') {\n\t\t\tvoid result.then(() => {\n\t\t\t\tthis.logSlowMessage(start, context);\n\t\t\t});\n\t\t} else {\n\t\t\tthis.logSlowMessage(start, context);\n\t\t}\n\t\tif (room && room.log.getLineCount() !== initialRoomlogLength) {\n\t\t\troom.messagesSent++;\n\t\t\tfor (const [handler, numMessages] of room.nthMessageHandlers) {\n\t\t\t\tif (room.messagesSent % numMessages === 0) handler(room, message);\n\t\t\t}\n\t\t}\n\n\t\treturn result;\n\t}\n\tlogSlowMessage(start: number, context: CommandContext) {\n\t\tconst timeUsed = Date.now() - start;\n\t\tif (timeUsed < 1000) return;\n\t\tif (context.cmd === 'search' || context.cmd === 'savereplay') return;\n\n\t\tconst logMessage = (\n\t\t\t`[slow command] ${timeUsed}ms - ${context.user.name} (${context.connection.ip}): ` +\n\t\t\t`<${context.room ? context.room.roomid : context.pmTarget ? `PM:${context.pmTarget?.name}` : 'CMD'}> ` +\n\t\t\t`${context.message.replace(/\\n/ig, ' ')}`\n\t\t);\n\n\t\tMonitor.slow(logMessage);\n\t}\n\n\tpackageData: AnyObject = {};\n\n\tgetPluginName(file: string) {\n\t\tconst nameWithExt = pathModule.relative(__dirname, file).replace(/^chat-(?:commands|plugins)./, '');\n\t\tlet name = nameWithExt.slice(0, nameWithExt.lastIndexOf('.'));\n\t\tif (name.endsWith('/index')) name = name.slice(0, -6);\n\t\treturn name;\n\t}\n\n\tloadPluginFile(file: string) {\n\t\tif (!file.endsWith('.js')) return;\n\t\tthis.loadPlugin(require(file), this.getPluginName(file));\n\t}\n\n\tloadPluginDirectory(dir: string, depth = 0) {\n\t\tfor (const file of FS(dir).readdirSync()) {\n\t\t\tconst path = pathModule.resolve(dir, file);\n\t\t\tif (FS(path).isDirectorySync()) {\n\t\t\t\tdepth++;\n\t\t\t\tif (depth > MAX_PLUGIN_LOADING_DEPTH) continue;\n\t\t\t\tthis.loadPluginDirectory(path, depth);\n\t\t\t} else {\n\t\t\t\ttry {\n\t\t\t\t\tthis.loadPluginFile(path);\n\t\t\t\t} catch (e) {\n\t\t\t\t\tMonitor.crashlog(e, \"A loading chat plugin\");\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\tannotateCommands(commandTable: AnyObject, namespace = ''): AnnotatedChatCommands {\n\t\tfor (const cmd in commandTable) {\n\t\t\tconst entry = commandTable[cmd];\n\t\t\tif (typeof entry === 'object') {\n\t\t\t\tthis.annotateCommands(entry, `${namespace}${cmd} `);\n\t\t\t}\n\t\t\tif (typeof entry === 'string') {\n\t\t\t\tconst base = commandTable[entry];\n\t\t\t\tif (!base) continue;\n\t\t\t\tif (!base.aliases) base.aliases = [];\n\t\t\t\tif (!base.aliases.includes(cmd)) base.aliases.push(cmd);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof entry !== 'function') continue;\n\n\t\t\tconst handlerCode = entry.toString();\n\t\t\tentry.requiresRoom = /requireRoom\\((?:'|\"|`)(.*?)(?:'|\"|`)/.exec(handlerCode)?.[1] as RoomID || /this\\.requireRoom\\(/.test(handlerCode);\n\t\t\tentry.hasRoomPermissions = /\\bthis\\.(checkCan|can)\\([^,)\\n]*, [^,)\\n]*,/.test(handlerCode);\n\t\t\tentry.broadcastable = cmd.endsWith('help') || /\\bthis\\.(?:(check|can|run|should)Broadcast)\\(/.test(handlerCode);\n\t\t\tentry.isPrivate = /\\bthis\\.(?:privately(Check)?Can|commandDoesNotExist)\\(/.test(handlerCode);\n\t\t\tentry.requiredPermission = /this\\.(?:checkCan|privately(?:Check)?Can)\\(['`\"]([a-zA-Z0-9]+)['\"`](\\)|, )/.exec(handlerCode)?.[1];\n\t\t\tif (!entry.aliases) entry.aliases = [];\n\n\t\t\t// assign properties from the base command if the current command uses CommandContext.run.\n\t\t\tconst runsCommand = /this.run\\((?:'|\"|`)(.*?)(?:'|\"|`)\\)/.exec(handlerCode);\n\t\t\tif (runsCommand) {\n\t\t\t\tconst [, baseCommand] = runsCommand;\n\t\t\t\tconst baseEntry = commandTable[baseCommand];\n\t\t\t\tif (baseEntry) {\n\t\t\t\t\tif (baseEntry.requiresRoom) entry.requiresRoom = baseEntry.requiresRoom;\n\t\t\t\t\tif (baseEntry.hasRoomPermissions) entry.hasRoomPermissions = baseEntry.hasRoomPermissions;\n\t\t\t\t\tif (baseEntry.broadcastable) entry.broadcastable = baseEntry.broadcastable;\n\t\t\t\t\tif (baseEntry.isPrivate) entry.isPrivate = baseEntry.isPrivate;\n\t\t\t\t}\n\t\t\t}\n\t\t\t// This is usually the same as `entry.name`, but some weirdness like\n\t\t\t// `commands.a = b` could screw it up. This should make it consistent.\n\t\t\tentry.cmd = cmd;\n\t\t\tentry.fullCmd = `${namespace}${cmd}`;\n\t\t}\n\t\treturn commandTable;\n\t}\n\tloadPlugin(plugin: AnyObject, name: string) {\n\t\t// esbuild builds cjs exports in such a way that they use getters, leading to crashes\n\t\t// in the plugin.roomSettings = [plugin.roomSettings] action. So, we have to make them not getters\n\t\tplugin = { ...plugin };\n\t\tif (plugin.commands) {\n\t\t\tObject.assign(Chat.commands, this.annotateCommands(plugin.commands));\n\t\t}\n\t\tif (plugin.pages) {\n\t\t\tObject.assign(Chat.pages, plugin.pages);\n\t\t}\n\n\t\tif (plugin.destroy) {\n\t\t\tChat.destroyHandlers.push(plugin.destroy);\n\t\t}\n\t\tif (plugin.crqHandlers) {\n\t\t\tObject.assign(Chat.crqHandlers, plugin.crqHandlers);\n\t\t}\n\t\tif (plugin.roomSettings) {\n\t\t\tif (!Array.isArray(plugin.roomSettings)) plugin.roomSettings = [plugin.roomSettings];\n\t\t\tChat.roomSettings = Chat.roomSettings.concat(plugin.roomSettings);\n\t\t}\n\t\tif (plugin.chatfilter) Chat.filters.push(plugin.chatfilter);\n\t\tif (plugin.namefilter) Chat.namefilters.push(plugin.namefilter);\n\t\tif (plugin.hostfilter) Chat.hostfilters.push(plugin.hostfilter);\n\t\tif (plugin.loginfilter) Chat.loginfilters.push(plugin.loginfilter);\n\t\tif (plugin.punishmentfilter) Chat.punishmentfilters.push(plugin.punishmentfilter);\n\t\tif (plugin.nicknamefilter) Chat.nicknamefilters.push(plugin.nicknamefilter);\n\t\tif (plugin.statusfilter) Chat.statusfilters.push(plugin.statusfilter);\n\t\tif (plugin.onRenameRoom) {\n\t\t\tif (!Chat.handlers['onRenameRoom']) Chat.handlers['onRenameRoom'] = [];\n\t\t\tChat.handlers['onRenameRoom'].push(plugin.onRenameRoom);\n\t\t}\n\t\tif (plugin.onRoomClose) {\n\t\t\tif (!Chat.handlers['onRoomClose']) Chat.handlers['onRoomClose'] = [];\n\t\t\tChat.handlers['onRoomClose'].push(plugin.onRoomClose);\n\t\t}\n\t\tif (plugin.handlers) {\n\t\t\tfor (const handlerName in plugin.handlers) {\n\t\t\t\tif (!Chat.handlers[handlerName]) Chat.handlers[handlerName] = [];\n\t\t\t\tChat.handlers[handlerName].push(plugin.handlers[handlerName]);\n\t\t\t}\n\t\t}\n\t\tChat.plugins[name] = plugin;\n\t}\n\tloadPlugins(oldPlugins?: { [k: string]: ChatPlugin }) {\n\t\tif (Chat.commands) return;\n\t\tif (oldPlugins) Chat.oldPlugins = oldPlugins;\n\n\t\tvoid FS('package.json').readIfExists().then(data => {\n\t\t\tif (data) Chat.packageData = JSON.parse(data);\n\t\t});\n\n\t\t// Install plug-in commands and chat filters\n\n\t\tChat.commands = Object.create(null);\n\t\tChat.pages = Object.create(null);\n\t\tthis.loadPluginDirectory('dist/server/chat-commands');\n\t\tChat.baseCommands = Chat.commands;\n\t\tChat.basePages = Chat.pages;\n\t\tChat.commands = Object.assign(Object.create(null), Chat.baseCommands);\n\t\tChat.pages = Object.assign(Object.create(null), Chat.basePages);\n\n\t\t// Load filters from Config\n\t\tthis.loadPlugin(Config, 'config');\n\t\tthis.loadPlugin(Tournaments, 'tournaments');\n\n\t\tthis.loadPluginDirectory('dist/server/chat-plugins');\n\t\tChat.oldPlugins = {};\n\t\t// lower priority should run later\n\t\tUtils.sortBy(Chat.filters, filter => -(filter.priority || 0));\n\t}\n\n\tdestroy() {\n\t\tfor (const handler of Chat.destroyHandlers) {\n\t\t\thandler();\n\t\t}\n\t}\n\n\trunHandlers(name: keyof Handlers, ...args: Parameters) {\n\t\tconst handlers = this.handlers[name];\n\t\tif (!handlers) return;\n\t\tfor (const h of handlers) {\n\t\t\tvoid h.call(this, ...args);\n\t\t}\n\t}\n\n\thandleRoomRename(oldID: RoomID, newID: RoomID, room: Room) {\n\t\tChat.runHandlers('onRenameRoom', oldID, newID, room);\n\t}\n\n\thandleRoomClose(roomid: RoomID, user: User, connection: Connection) {\n\t\tChat.runHandlers('onRoomClose', roomid, user, connection, roomid.startsWith('view-'));\n\t}\n\n\t/**\n\t * Takes a chat message and returns data about any command it's\n\t * trying to use.\n\t *\n\t * Returning `null` means the chat message isn't trying to use\n\t * a command, and returning `{handler: null}` means it's trying\n\t * to use a command that doesn't exist.\n\t */\n\tparseCommand(message: string, recursing = false): {\n\t\tcmd: string, fullCmd: string, cmdToken: string, target: string, handler: AnnotatedChatHandler | null,\n\t} | null {\n\t\tif (!message.trim()) return null;\n\n\t\t// hardcoded commands\n\t\tif (message.startsWith(`>> `)) {\n\t\t\tmessage = `/eval ${message.slice(3)}`;\n\t\t} else if (message.startsWith(`>>> `)) {\n\t\t\tmessage = `/evalbattle ${message.slice(4)}`;\n\t\t} else if (message.startsWith('>>sql ')) {\n\t\t\tmessage = `/evalsql ${message.slice(6)}`;\n\t\t} else if (message.startsWith(`/me`) && /[^A-Za-z0-9 ]/.test(message.charAt(3))) {\n\t\t\tmessage = `/mee ${message.slice(3)}`;\n\t\t} else if (message.startsWith(`/ME`) && /[^A-Za-z0-9 ]/.test(message.charAt(3))) {\n\t\t\tmessage = `/MEE ${message.slice(3)}`;\n\t\t}\n\n\t\tconst cmdToken = message.charAt(0);\n\t\tif (!VALID_COMMAND_TOKENS.includes(cmdToken)) return null;\n\t\tif (cmdToken === message.charAt(1)) return null;\n\t\tif (cmdToken === BROADCAST_TOKEN && /[^A-Za-z0-9]/.test(message.charAt(1))) return null;\n\n\t\tlet [cmd, target] = Utils.splitFirst(message.slice(1), ' ');\n\t\tcmd = cmd.toLowerCase();\n\n\t\tif (cmd.endsWith(',')) cmd = cmd.slice(0, -1);\n\n\t\tlet curCommands: AnnotatedChatCommands = Chat.commands;\n\t\tlet commandHandler;\n\t\tlet fullCmd = cmd;\n\t\tlet prevCmdName = '';\n\n\t\tdo {\n\t\t\tif (cmd in curCommands) {\n\t\t\t\tcommandHandler = curCommands[cmd];\n\t\t\t} else {\n\t\t\t\tcommandHandler = undefined;\n\t\t\t}\n\t\t\tif (typeof commandHandler === 'string') {\n\t\t\t\t// in case someone messed up, don't loop\n\t\t\t\tcommandHandler = curCommands[commandHandler];\n\t\t\t} else if (Array.isArray(commandHandler) && !recursing) {\n\t\t\t\treturn this.parseCommand(cmdToken + 'help ' + fullCmd.slice(0, -4), true);\n\t\t\t}\n\t\t\tif (commandHandler && typeof commandHandler === 'object') {\n\t\t\t\t[cmd, target] = Utils.splitFirst(target, ' ');\n\t\t\t\tcmd = cmd.toLowerCase();\n\n\t\t\t\tprevCmdName = fullCmd;\n\t\t\t\tfullCmd += ' ' + cmd;\n\t\t\t\tcurCommands = commandHandler as AnnotatedChatCommands;\n\t\t\t}\n\t\t} while (commandHandler && typeof commandHandler === 'object');\n\n\t\tif (!commandHandler && (curCommands.default || curCommands[''])) {\n\t\t\tcommandHandler = curCommands.default || curCommands[''];\n\t\t\tfullCmd = prevCmdName;\n\t\t\ttarget = `${cmd}${target ? ` ${target}` : ''}`;\n\t\t\tcmd = fullCmd.split(' ').shift()!;\n\t\t\tif (typeof commandHandler === 'string') {\n\t\t\t\tcommandHandler = curCommands[commandHandler];\n\t\t\t}\n\t\t}\n\n\t\tif (!commandHandler && !recursing) {\n\t\t\tfor (const g in Config.groups) {\n\t\t\t\tconst groupid = Config.groups[g].id;\n\t\t\t\tif (fullCmd === groupid) {\n\t\t\t\t\treturn this.parseCommand(`/promote ${target}, ${g}`, true);\n\t\t\t\t} else if (fullCmd === 'global' + groupid) {\n\t\t\t\t\treturn this.parseCommand(`/globalpromote ${target}, ${g}`, true);\n\t\t\t\t} else if (\n\t\t\t\t\tfullCmd === 'de' + groupid || fullCmd === 'un' + groupid ||\n\t\t\t\t\tfullCmd === 'globalde' + groupid || fullCmd === 'deglobal' + groupid\n\t\t\t\t) {\n\t\t\t\t\treturn this.parseCommand(`/demote ${target}`, true);\n\t\t\t\t} else if (fullCmd === 'room' + groupid) {\n\t\t\t\t\treturn this.parseCommand(`/roompromote ${target}, ${g}`, true);\n\t\t\t\t} else if (fullCmd === 'forceroom' + groupid) {\n\t\t\t\t\treturn this.parseCommand(`/forceroompromote ${target}, ${g}`, true);\n\t\t\t\t} else if (fullCmd === 'roomde' + groupid || fullCmd === 'deroom' + groupid || fullCmd === 'roomun' + groupid) {\n\t\t\t\t\treturn this.parseCommand(`/roomdemote ${target}`, true);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn {\n\t\t\tcmd,\n\t\t\tcmdToken,\n\t\t\ttarget,\n\t\t\tfullCmd,\n\t\t\thandler: commandHandler as AnnotatedChatHandler | null,\n\t\t};\n\t}\n\tallCommands(table: ChatCommands = Chat.commands) {\n\t\tconst results: AnnotatedChatHandler[] = [];\n\t\tfor (const cmd in table) {\n\t\t\tconst handler = table[cmd];\n\t\t\tif (Array.isArray(handler) || !handler || ['string', 'boolean'].includes(typeof handler)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (typeof handler === 'object') {\n\t\t\t\tresults.push(...this.allCommands(handler));\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tresults.push(handler as AnnotatedChatHandler);\n\t\t}\n\t\tif (table !== Chat.commands) return results;\n\t\treturn results.filter((handler, i) => results.indexOf(handler) === i);\n\t}\n\n\t/**\n\t * Strips HTML from a string.\n\t */\n\tstripHTML(htmlContent: string) {\n\t\tif (!htmlContent) return '';\n\t\treturn htmlContent.replace(/<[^>]*>/g, '');\n\t}\n\t/**\n\t * Validates input regex and ensures it won't crash.\n\t */\n\tvalidateRegex(word: string) {\n\t\tword = word.trim();\n\t\tif ((word.endsWith('|') && !word.endsWith('\\\\|')) || word.startsWith('|')) {\n\t\t\tthrow new Chat.ErrorMessage(`Your regex was rejected because it included an unterminated |.`);\n\t\t}\n\t\ttry {\n\t\t\tnew RegExp(word);\n\t\t} catch (e: any) {\n\t\t\tthrow new Chat.ErrorMessage(\n\t\t\t\te.message.startsWith('Invalid regular expression: ') ?\n\t\t\t\t\te.message :\n\t\t\t\t\t`Invalid regular expression: /${word}/: ${e.message}`\n\t\t\t);\n\t\t}\n\t}\n\n\t/**\n\t * Returns singular (defaulting to '') if num is 1, or plural\n\t * (defaulting to 's') otherwise. Helper function for pluralizing\n\t * words.\n\t */\n\tplural(num: any, pluralSuffix = 's', singular = '') {\n\t\tif (num && typeof num.length === 'number') {\n\t\t\tnum = num.length;\n\t\t} else if (num && typeof num.size === 'number') {\n\t\t\tnum = num.size;\n\t\t} else {\n\t\t\tnum = Number(num);\n\t\t}\n\t\treturn (num !== 1 ? pluralSuffix : singular);\n\t}\n\n\t/**\n\t * Counts the thing passed.\n\t *\n\t * Chat.count(2, \"days\") === \"2 days\"\n\t * Chat.count(1, \"days\") === \"1 day\"\n\t * Chat.count([\"foo\"], \"things are\") === \"1 thing is\"\n\t *\n\t */\n\tcount(num: any, pluralSuffix: string, singular = \"\") {\n\t\tif (num && typeof num.length === 'number') {\n\t\t\tnum = num.length;\n\t\t} else if (num && typeof num.size === 'number') {\n\t\t\tnum = num.size;\n\t\t} else {\n\t\t\tnum = Number(num);\n\t\t}\n\t\tif (!singular) {\n\t\t\tif (pluralSuffix.endsWith(\"s\")) {\n\t\t\t\tsingular = pluralSuffix.slice(0, -1);\n\t\t\t} else if (pluralSuffix.endsWith(\"s have\")) {\n\t\t\t\tsingular = pluralSuffix.slice(0, -6) + \" has\";\n\t\t\t} else if (pluralSuffix.endsWith(\"s were\")) {\n\t\t\t\tsingular = pluralSuffix.slice(0, -6) + \" was\";\n\t\t\t}\n\t\t}\n\t\tconst space = singular.startsWith('<') ? '' : ' ';\n\t\treturn `${num}${space}${num > 1 ? pluralSuffix : singular}`;\n\t}\n\n\t/**\n\t * Returns a timestamp in the form {yyyy}-{MM}-{dd} {hh}:{mm}:{ss}.\n\t *\n\t * options.human = true will use a 12-hour clock\n\t */\n\ttoTimestamp(date: Date, options: { human?: boolean } = {}) {\n\t\tconst human = options.human;\n\t\tlet parts: any[] = [\n\t\t\tdate.getFullYear(),\tdate.getMonth() + 1, date.getDate(),\n\t\t\tdate.getHours(), date.getMinutes(),\tdate.getSeconds(),\n\t\t];\n\t\tif (human) {\n\t\t\tparts.push(parts[3] >= 12 ? 'pm' : 'am');\n\t\t\tparts[3] = parts[3] % 12 || 12;\n\t\t}\n\t\tparts = parts.map(val => `${val}`.padStart(2, '0'));\n\t\treturn parts.slice(0, 3).join(\"-\") + \" \" + parts.slice(3, 6).join(\":\") + (parts[6] || '');\n\t}\n\n\t/**\n\t * Takes a number of milliseconds, and reports the duration in English: hours, minutes, etc.\n\t *\n\t * options.hhmmss = true will instead report the duration in 00:00:00 format\n\t *\n\t */\n\ttoDurationString(val: number, options: { hhmmss?: boolean, precision?: number } = {}) {\n\t\t// TODO: replace by Intl.DurationFormat or equivalent when it becomes available (ECMA-402)\n\t\t// https://github.com/tc39/ecma402/issues/47\n\t\tconst date = new Date(+val);\n\t\tif (isNaN(date.getTime())) return 'forever';\n\n\t\tconst parts = [\n\t\t\tdate.getUTCFullYear() - 1970, date.getUTCMonth(), date.getUTCDate() - 1,\n\t\t\tdate.getUTCHours(), date.getUTCMinutes(), date.getUTCSeconds(),\n\t\t];\n\t\tconst roundingBoundaries = [6, 15, 12, 30, 30];\n\t\tconst unitNames = [\"second\", \"minute\", \"hour\", \"day\", \"month\", \"year\"];\n\t\tconst positiveIndex = parts.findIndex(elem => elem > 0);\n\t\tlet precision = (options?.precision ? options.precision : 3);\n\t\tif (options?.hhmmss) {\n\t\t\tconst str = parts.slice(positiveIndex).map(value => `${value}`.padStart(2, '0')).join(\":\");\n\t\t\treturn str.length === 2 ? \"00:\" + str : str;\n\t\t}\n\n\t\t// round least significant displayed unit\n\t\tif (positiveIndex + precision < parts.length && precision > 0 && positiveIndex >= 0) {\n\t\t\tif (parts[positiveIndex + precision] >= roundingBoundaries[positiveIndex + precision - 1]) {\n\t\t\t\tparts[positiveIndex + precision - 1]++;\n\t\t\t}\n\t\t}\n\n\t\t// don't display trailing 0's if the number is exact\n\t\tlet precisionIndex = 5;\n\t\twhile (precisionIndex > positiveIndex && !parts[precisionIndex]) {\n\t\t\tprecisionIndex--;\n\t\t}\n\t\tprecision = Math.min(precision, precisionIndex - positiveIndex + 1);\n\n\t\treturn parts\n\t\t\t.slice(positiveIndex)\n\t\t\t.reverse()\n\t\t\t.map((value, index) => `${value} ${unitNames[index]}${value !== 1 ? \"s\" : \"\"}`)\n\t\t\t.reverse()\n\t\t\t.slice(0, precision)\n\t\t\t.join(\" \")\n\t\t\t.trim();\n\t}\n\n\t/**\n\t * Takes an array and turns it into a sentence string by adding commas and the word \"and\"\n\t */\n\ttoListString(arr: string[], conjunction = \"and\") {\n\t\tif (!arr.length) return '';\n\t\tif (arr.length === 1) return arr[0];\n\t\tif (arr.length === 2) return `${arr[0]} ${conjunction.trim()} ${arr[1]}`;\n\t\treturn `${arr.slice(0, -1).join(\", \")}, ${conjunction.trim()} ${arr.slice(-1)[0]}`;\n\t}\n\n\t/**\n\t * Takes an array and turns it into a sentence string by adding commas and the word \"or\"\n\t */\n\ttoOrList(arr: string[]) {\n\t\tif (!arr.length) return '';\n\t\tif (arr.length === 1) return arr[0];\n\t\tif (arr.length === 2) return `${arr[0]} or ${arr[1]}`;\n\t\treturn `${arr.slice(0, -1).join(\", \")}, or ${arr.slice(-1)[0]}`;\n\t}\n\n\t/**\n\t * Convert multiline HTML into a single line without losing whitespace (so\n\t *
 blocks still render correctly). Linebreaks inside <> are replaced\n\t * with ` `, and linebreaks outside <> are replaced with `
`.\n\t *\n\t * PS's protocol often requires sending a block of HTML in a single line,\n\t * so this ensures any block of HTML ends up as a single line.\n\t */\n\tcollapseLineBreaksHTML(htmlContent: string) {\n\t\thtmlContent = htmlContent.replace(/<[^>]*>/g, tag => tag.replace(/\\n/g, ' '));\n\t\thtmlContent = htmlContent.replace(/\\n/g, '
');\n\t\treturn htmlContent;\n\t}\n\t/**\n\t * Takes a string of text and transforms it into a block of html using the details tag.\n\t * If it has a newline, will make the 3 lines the preview, and fill the rest in.\n\t * @param str string to block\n\t */\n\tgetReadmoreBlock(str: string, isCode?: boolean, cutoff = 3) {\n\t\tconst params = str.slice(str.startsWith('\\n') ? 1 : 0).split('\\n');\n\t\tconst output: string[] = [];\n\t\tfor (const [i, param] of params.entries()) {\n\t\t\tif (output.length < cutoff && param.length > 80 && cutoff > 2) cutoff--;\n\t\t\tif (param.length > cutoff * 160 && i < cutoff) cutoff = i;\n\t\t\toutput.push(Utils[isCode ? 'escapeHTMLForceWrap' : 'escapeHTML'](param));\n\t\t}\n\n\t\tif (output.length > cutoff) {\n\t\t\treturn `
${\n\t\t\t\toutput.slice(0, cutoff).join('
')\n\t\t\t}
${\n\t\t\t\toutput.slice(cutoff).join('
')\n\t\t\t}
`;\n\t\t} else {\n\t\t\tconst tag = isCode ? `code` : `div`;\n\t\t\treturn `<${tag} style=\"white-space: pre-wrap; display: table; tab-size: 3\">${\n\t\t\t\toutput.join('
')\n\t\t\t}`;\n\t\t}\n\t}\n\n\tgetReadmoreCodeBlock(str: string, cutoff?: number) {\n\t\treturn Chat.getReadmoreBlock(str, true, cutoff);\n\t}\n\n\tgetDataPokemonHTML(species: Species, gen = 8, tier = '') {\n\t\tlet buf = '
  • ';\n\t\tbuf += `${tier || species.tier} `;\n\t\tbuf += ` `;\n\t\tbuf += `${species.name} `;\n\t\tbuf += '';\n\t\tif (species.types) {\n\t\t\tfor (const type of species.types) {\n\t\t\t\tbuf += `\"${type}\"`;\n\t\t\t}\n\t\t}\n\t\tbuf += ' ';\n\t\tif (gen >= 3) {\n\t\t\tbuf += '';\n\t\t\tif (species.abilities['1'] && (gen >= 4 || Dex.abilities.get(species.abilities['1']).gen === 3)) {\n\t\t\t\tbuf += `${species.abilities['0']}
    ${species.abilities['1']}
    `;\n\t\t\t} else {\n\t\t\t\tbuf += `${species.abilities['0']}`;\n\t\t\t}\n\t\t\tif (species.abilities['H'] && species.abilities['S']) {\n\t\t\t\tbuf += `${species.abilities['H']}
    (${species.abilities['S']})
    `;\n\t\t\t} else if (species.abilities['H']) {\n\t\t\t\tbuf += `${species.abilities['H']}`;\n\t\t\t} else if (species.abilities['S']) {\n\t\t\t\t// special case for Zygarde\n\t\t\t\tbuf += `(${species.abilities['S']})`;\n\t\t\t} else {\n\t\t\t\tbuf += '';\n\t\t\t}\n\t\t\tbuf += '
    ';\n\t\t}\n\t\tbuf += '';\n\t\tbuf += `HP
    ${species.baseStats.hp}
    `;\n\t\tbuf += `Atk
    ${species.baseStats.atk}
    `;\n\t\tbuf += `Def
    ${species.baseStats.def}
    `;\n\t\tif (gen <= 1) {\n\t\t\tbuf += `Spc
    ${species.baseStats.spa}
    `;\n\t\t} else {\n\t\t\tbuf += `SpA
    ${species.baseStats.spa}
    `;\n\t\t\tbuf += `SpD
    ${species.baseStats.spd}
    `;\n\t\t}\n\t\tbuf += `Spe
    ${species.baseStats.spe}
    `;\n\t\tbuf += `BST
    ${species.bst}
    `;\n\t\tbuf += '
    ';\n\t\tbuf += '
  • ';\n\t\treturn `
      ${buf}
    `;\n\t}\n\tgetDataMoveHTML(move: Move) {\n\t\tlet buf = `
    • `;\n\t\tbuf += `${move.name} `;\n\t\t// encoding is important for the ??? type icon\n\t\tconst encodedMoveType = encodeURIComponent(move.type);\n\t\tbuf += `\"${move.type}\"`;\n\t\tbuf += `\"${move.category}\" `;\n\t\tif (move.basePower) {\n\t\t\tbuf += `Power
      ${typeof move.basePower === 'number' ? move.basePower : '\u2014'}
      `;\n\t\t}\n\t\tbuf += `Accuracy
      ${typeof move.accuracy === 'number' ? (`${move.accuracy}%`) : '\u2014'}
      `;\n\t\tconst basePP = move.pp || 1;\n\t\tconst pp = Math.floor(move.noPPBoosts ? basePP : basePP * 8 / 5);\n\t\tbuf += `PP
      ${pp}
      `;\n\t\tbuf += `${move.shortDesc || move.desc} `;\n\t\tbuf += `
    `;\n\t\treturn buf;\n\t}\n\tgetDataAbilityHTML(ability: Ability) {\n\t\tlet buf = `
    • `;\n\t\tbuf += `${ability.name} `;\n\t\tbuf += `${ability.shortDesc || ability.desc} `;\n\t\tbuf += `
    `;\n\t\treturn buf;\n\t}\n\tgetDataItemHTML(item: Item) {\n\t\tlet buf = `
    • `;\n\t\tbuf += ` ${item.name} `;\n\t\tbuf += `${item.shortDesc || item.desc} `;\n\t\tbuf += `
    `;\n\t\treturn buf;\n\t}\n\n\t/**\n\t * Gets the dimension of the image at url. Returns 0x0 if the image isn't found, as well as the relevant error.\n\t */\n\tgetImageDimensions(url: string): Promise<{ height: number, width: number }> {\n\t\treturn probe(url);\n\t}\n\n\tparseArguments(\n\t\tstr: string,\n\t\tdelim = ',',\n\t\topts: Partial<{ paramDelim: string, useIDs: boolean, allowEmpty: boolean }> = { useIDs: true }\n\t) {\n\t\tconst result: Record = {};\n\t\tfor (const part of str.split(delim)) {\n\t\t\tlet [key, val] = Utils.splitFirst(part, opts.paramDelim ||= \"=\").map(f => f.trim());\n\t\t\tif (opts.useIDs) key = toID(key);\n\t\t\tif (!toID(key) || (!opts.allowEmpty && !toID(val))) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Invalid option ${part}. Must be in [key]${opts.paramDelim}[value] format.`);\n\t\t\t}\n\t\t\tif (!result[key]) result[key] = [];\n\t\t\tresult[key].push(val);\n\t\t}\n\t\treturn result;\n\t}\n\n\t/**\n\t * Normalize a message for the purposes of applying chat filters.\n\t *\n\t * Not used by PS itself, but feel free to use it in your own chat filters.\n\t */\n\tnormalize(message: string) {\n\t\tmessage = message.replace(/'/g, '').replace(/[^A-Za-z0-9]+/g, ' ').trim();\n\t\tif (!/[A-Za-z][A-Za-z]/.test(message)) {\n\t\t\tmessage = message.replace(/ */g, '');\n\t\t} else if (!message.includes(' ')) {\n\t\t\tmessage = message.replace(/([A-Z])/g, ' $1').trim();\n\t\t}\n\t\treturn ' ' + message.toLowerCase() + ' ';\n\t}\n\n\t/**\n\t * Generates dimensions to fit an image at url into a maximum size of maxWidth x maxHeight,\n\t * preserving aspect ratio.\n\t *\n\t * @return [width, height, resized]\n\t */\n\tasync fitImage(url: string, maxHeight = 300, maxWidth = 300): Promise<[number, number, boolean]> {\n\t\tconst { height, width } = await Chat.getImageDimensions(url);\n\n\t\tif (width <= maxWidth && height <= maxHeight) return [width, height, false];\n\n\t\tconst ratio = Math.min(maxHeight / height, maxWidth / width);\n\n\t\treturn [Math.round(width * ratio), Math.round(height * ratio), true];\n\t}\n\n\trefreshPageFor(\n\t\tpageid: string,\n\t\troomid: Room | RoomID,\n\t\tcheckPrefix = false,\n\t\tignoreUsers: ID[] | null = null\n\t) {\n\t\tconst room = Rooms.get(roomid);\n\t\tif (!room) return false;\n\t\tfor (const id in room.users) {\n\t\t\tif (ignoreUsers?.includes(id as ID)) continue;\n\t\t\tconst u = room.users[id];\n\t\t\tfor (const conn of u.connections) {\n\t\t\t\tif (conn.openPages) {\n\t\t\t\t\tfor (const page of conn.openPages) {\n\t\t\t\t\t\tif ((checkPrefix ? page.startsWith(pageid) : page === pageid)) {\n\t\t\t\t\t\t\tvoid this.parse(`/j view-${page}`, room, u, conn);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Notifies a targetUser that a user was blocked from reaching them due to a setting they have enabled.\n\t */\n\tmaybeNotifyBlocked(blocked: 'pm' | 'challenge' | 'invite', targetUser: User, user: User) {\n\t\tconst prefix = `|pm|~|${targetUser.getIdentity()}|/nonotify `;\n\t\tconst options = 'or change it in the menu in the upper right.';\n\t\tif (blocked === 'pm') {\n\t\t\tif (!targetUser.notified.blockPMs) {\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to PM you but was blocked. To enable PMs, use /unblockpms ${options}`);\n\t\t\t\ttargetUser.notified.blockPMs = true;\n\t\t\t}\n\t\t} else if (blocked === 'challenge') {\n\t\t\tif (!targetUser.notified.blockChallenges) {\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to challenge you to a battle but was blocked. To enable challenges, use /unblockchallenges ${options}`);\n\t\t\t\ttargetUser.notified.blockChallenges = true;\n\t\t\t}\n\t\t} else if (blocked === 'invite') {\n\t\t\tif (!targetUser.notified.blockInvites) {\n\t\t\t\ttargetUser.send(`${prefix}The user '${Utils.escapeHTML(user.name)}' attempted to invite you to a room but was blocked. To enable invites, use /unblockinvites.`);\n\t\t\t\ttargetUser.notified.blockInvites = true;\n\t\t\t}\n\t\t}\n\t}\n\n\treadonly formatText = formatText;\n\treadonly linkRegex = linkRegex;\n\treadonly stripFormatting = stripFormatting;\n\n\t/** Helper function to ensure no state issues occur when regex testing for links. */\n\tisLink(possibleUrl: string) {\n\t\t// if we don't do this, it starts spitting out false every other time even if it's a valid link\n\t\t// since global regexes are stateful.\n\t\t// this took me so much pain to debug.\n\t\t// Yes, that is intended JS behavior. Yes, it fills me with unyielding rage.\n\t\t// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/test\n\t\tthis.linkRegex.lastIndex = -1;\n\t\treturn this.linkRegex.test(possibleUrl);\n\t}\n\n\treadonly filterWords: { [k: string]: FilterWord[] } = {};\n\treadonly monitors: { [k: string]: Monitor } = {};\n\n\tregisterMonitor(id: string, entry: Monitor) {\n\t\tif (!Chat.filterWords[id]) Chat.filterWords[id] = [];\n\t\tChat.monitors[id] = entry;\n\t}\n\n\tresolvePage(pageid: string, user: User, connection: Connection) {\n\t\treturn (new PageContext({ pageid, user, connection, language: user.language! })).resolve();\n\t}\n};\n\n// backwards compatibility; don't actually use these\n// they're just there so forks have time to slowly transition\n(Chat as any).escapeHTML = Utils.escapeHTML;\n(Chat as any).splitFirst = Utils.splitFirst;\n(Chat as any).sendPM = Chat.PrivateMessages.send.bind(Chat.PrivateMessages);\n(CommandContext.prototype as any).can = CommandContext.prototype.checkCan;\n(CommandContext.prototype as any).canTalk = CommandContext.prototype.checkChat;\n(CommandContext.prototype as any).canBroadcast = CommandContext.prototype.checkBroadcast;\n(CommandContext.prototype as any).canHTML = CommandContext.prototype.checkHTML;\n(CommandContext.prototype as any).canEmbedURI = CommandContext.prototype.checkEmbedURI;\n(CommandContext.prototype as any).privatelyCan = CommandContext.prototype.privatelyCheckCan;\n(CommandContext.prototype as any).requiresRoom = CommandContext.prototype.requireRoom;\n(CommandContext.prototype as any).targetUserOrSelf = function (this: any, target: string, exactName: boolean) {\n\tconst user = this.getUserOrSelf(target, exactName);\n\tthis.targetUser = user;\n\tthis.inputUsername = target;\n\tthis.targetUsername = user?.name || target;\n\treturn user;\n};\n(CommandContext.prototype as any).splitTarget = function (this: any, target: string, exactName: boolean) {\n\tconst { targetUser, inputUsername, targetUsername, rest } = this.splitUser(target, exactName);\n\tthis.targetUser = targetUser;\n\tthis.inputUsername = inputUsername;\n\tthis.targetUsername = targetUsername;\n\treturn rest;\n};\n\n/**\n * Used by ChatMonitor.\n */\nexport interface FilterWord {\n\tregex: RegExp;\n\tword: string;\n\thits: number;\n\treason?: string;\n\tpublicReason?: string;\n\treplacement?: string;\n}\n\nexport type MonitorHandler = (\n\tthis: CommandContext,\n\tline: FilterWord,\n\troom: Room | null,\n\tuser: User,\n\tmessage: string,\n\tlcMessage: string,\n\tisStaff: boolean\n) => string | false | undefined;\nexport interface Monitor {\n\tlocation: string;\n\tpunishment: string;\n\tlabel: string;\n\tcondition?: string;\n\tmonitor?: MonitorHandler;\n}\n\n// explicitly check this so it doesn't happen in other child processes\nif (!process.send) {\n\tChat.database.spawn(Config.chatdbprocesses || 1);\n\tChat.databaseReadyPromise = Chat.prepareDatabase();\n\t// we need to make sure it is explicitly JUST the child of the original parent db process\n\t// no other child processes\n} else if (process.mainModule === module) {\n\tglobal.Monitor = {\n\t\tcrashlog(error: Error, source = 'A chat child process', details: AnyObject | null = null) {\n\t\t\tconst repr = JSON.stringify([error.name, error.message, source, details]);\n\t\t\tprocess.send!(`THROW\\n@!!@${repr}\\n${error.stack}`);\n\t\t},\n\t} as any;\n\tprocess.on('uncaughtException', err => {\n\t\tMonitor.crashlog(err, 'A chat database process');\n\t});\n\tprocess.on('unhandledRejection', err => {\n\t\tMonitor.crashlog(err as Error, 'A chat database process');\n\t});\n\tglobal.Config = require('./config-loader').Config;\n\t// eslint-disable-next-line no-eval\n\tRepl.start('chat-db', cmd => eval(cmd));\n}\n"], "mappings": "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", "names": ["dex", "format", "game", "cmd"] }