{ "version": 3, "sources": ["../../server/rooms.ts"], "sourcesContent": ["/**\n * Rooms\n * Pokemon Showdown - http://pokemonshowdown.com/\n *\n * Every chat room and battle is a room, and what they do is done in\n * rooms.ts. There's also a global room which every user is in, and\n * handles miscellaneous things like welcoming the user.\n *\n * `Rooms.rooms` is the global table of all rooms, a `Map` of `RoomID:Room`.\n * Rooms should normally be accessed with `Rooms.get(roomid)`.\n *\n * All rooms extend `BasicRoom`, whose important properties like `.users`\n * and `.game` are documented near the the top of its class definition.\n *\n * @license MIT\n */\n\nconst ALPHABET = '0123456789abcdefghijklmnopqrstuvwxyz'.split('');\n\nconst TIMEOUT_EMPTY_DEALLOCATE = 10 * 60 * 1000;\nconst TIMEOUT_INACTIVE_DEALLOCATE = 40 * 60 * 1000;\nconst REPORT_USER_STATS_INTERVAL = 10 * 60 * 1000;\nconst MAX_CHATROOM_ID_LENGTH = 225;\n\nconst CRASH_REPORT_THROTTLE = 60 * 60 * 1000;\n\nconst LAST_BATTLE_WRITE_THROTTLE = 10;\n\nconst RETRY_AFTER_LOGIN = null;\n\nimport { FS, Utils, Streams } from '../lib';\nimport { type RoomSection, RoomSections } from './chat-commands/room-settings';\nimport { type QueuedHunt } from './chat-plugins/scavengers';\nimport { type ScavengerGameTemplate } from './chat-plugins/scavenger-games';\nimport { type RepeatedPhrase } from './chat-plugins/repeats';\nimport {\n\tPM as RoomBattlePM, RoomBattle, RoomBattlePlayer, RoomBattleTimer, type RoomBattleOptions,\n} from \"./room-battle\";\nimport { BestOfGame } from './room-battle-bestof';\nimport { RoomGame, SimpleRoomGame, RoomGamePlayer } from './room-game';\nimport { MinorActivity, type MinorActivityData } from './room-minor-activity';\nimport { Roomlogs, type Roomlog } from './roomlogs';\nimport { RoomAuth } from './user-groups';\nimport { type PartialModlogEntry, mainModlog } from './modlog';\nimport { Replays } from './replays';\nimport * as crypto from 'crypto';\n\n/*********************************************************\n * the Room object.\n *********************************************************/\n\ninterface MuteEntry {\n\tuserid: ID;\n\ttime: number;\n\tguestNum: number;\n\tautoconfirmed: string;\n}\n\ninterface ChatRoomTable {\n\ttitle: string;\n\tdesc: string;\n\tuserCount: number;\n\tsection?: string;\n\tsubRooms?: string[];\n\tspotlight?: string;\n\tprivacy: RoomSettings['isPrivate'];\n}\n\ninterface ShowRequest {\n\tname: string;\n\tlink: string;\n\tcomment: string;\n\tdimensions?: [number, number, boolean];\n}\n\ninterface BattleRoomTable {\n\tp1?: string;\n\tp2?: string;\n\tminElo?: 'tour' | number;\n}\n\ninterface UserTable {\n\t[userid: string]: User;\n}\n\nexport interface RoomSettings {\n\ttitle: string;\n\tauth: { [userid: string]: GroupSymbol };\n\tcreationTime: number;\n\tsection?: RoomSection;\n\n\treadonly autojoin?: boolean;\n\taliases?: string[];\n\tbanwords?: string[];\n\tisPrivate?: PrivacySetting;\n\tmodjoin?: AuthLevel | true | null;\n\tmodchat?: AuthLevel | null;\n\tstaffRoom?: boolean;\n\tlanguage?: ID | false;\n\tslowchat?: number | false;\n\tevents?: { [k: string]: RoomEvent | RoomEventAlias | RoomEventCategory };\n\tfilterStretching?: boolean;\n\tfilterEmojis?: boolean;\n\tfilterCaps?: boolean;\n\tfilterLinks?: boolean;\n\tjeopardyDisabled?: boolean;\n\tmafiaDisabled?: boolean;\n\tunoDisabled?: boolean;\n\thangmanDisabled?: boolean;\n\tauctionDisabled?: boolean;\n\tgameNumber?: number;\n\thighTraffic?: boolean;\n\tspotlight?: string;\n\tparentid?: string | null;\n\tdesc?: string | null;\n\tintroMessage?: string | null;\n\tstaffMessage?: string | null;\n\trulesLink?: string | null;\n\tdataCommandTierDisplay?: 'tiers' | 'doubles tiers' | 'National Dex tiers' | 'numbers';\n\trequestShowEnabled?: boolean | null;\n\tpermissions?: { [k: string]: GroupSymbol };\n\tminorActivity?: PollData | AnnouncementData;\n\tminorActivityQueue?: MinorActivityData[];\n\trepeats?: RepeatedPhrase[];\n\ttopics?: string[];\n\tautoModchat?: {\n\t\trank: GroupSymbol,\n\t\ttime: number,\n\t\t// stores previous modchat setting. if true, modchat was fully off\n\t\tactive: boolean | AuthLevel,\n\t};\n\ttournaments?: TournamentRoomSettings;\n\tdefaultFormat?: string;\n\n\tscavSettings?: AnyObject;\n\tscavQueue?: QueuedHunt[];\n\n\t// should not ever be saved because they're inapplicable to persistent rooms\n\t/** This includes groupchats, battles, and help-ticket rooms. */\n\tisPersonal?: boolean;\n\tisHelp?: boolean;\n\tnoLogTimes?: boolean;\n\tnoAutoTruncate?: boolean;\n\tisMultichannel?: boolean;\n}\n\nexport type MessageHandler = (room: BasicRoom, message: string) => void;\nexport type Room = GameRoom | ChatRoom;\nexport type PrivacySetting = boolean | 'hidden' | 'voice' | 'unlisted';\n\nimport type { AnnouncementData } from './chat-plugins/announcements';\nimport type { PollData } from './chat-plugins/poll';\nimport type { AutoResponder } from './chat-plugins/responder';\nimport type { RoomEvent, RoomEventAlias, RoomEventCategory } from './chat-plugins/room-events';\nimport type { Tournament, TournamentRoomSettings } from './tournaments/index';\n\nexport abstract class BasicRoom {\n\t/** to rename use room.rename */\n\treadonly roomid: RoomID;\n\ttitle: string;\n\treadonly type: 'chat' | 'battle';\n\treadonly users: UserTable;\n\t/**\n\t * Scrollback log. This is the log that's sent to users when\n\t * joining the room. Should roughly match what's on everyone's\n\t * screen.\n\t */\n\treadonly log: Roomlog;\n\t/**\n\t * The room's current RoomGame, if it exists. Each room can have 0 to 2\n\t * `RoomGame`s, and `this.game.room === this`.\n\t * Rooms may also have an additional game in `this.subGame`.\n\t * However, `subGame`s do not update `user.game`.\n\t */\n\tgame: RoomGame | null;\n\tsubGame: RoomGame | null;\n\t/**\n\t * The room's current battle. Battles are a type of RoomGame, so in battle\n\t * rooms (which can only be `GameRoom`s), `this.battle === this.game`.\n\t * In all other rooms, `this.battle` is `null`.\n\t */\n\tbattle: RoomBattle | null;\n\t/**\n\t * The room's current best-of set. Best-of sets are a type of RoomGame, so in best-of set\n\t * rooms (which can only be `GameRoom`s), `this.bestof === this.game`.\n\t * In all other rooms, `this.bestof` is `null`.\n\t */\n\tbestOf: BestOfGame | null;\n\t/**\n\t * The game room's current tournament. If the room is a battle room whose\n\t * battle is part of a tournament, `this.tour === this.parent.game`.\n\t * In all other rooms, `this.tour` is `null`.\n\t */\n\ttour: Tournament | null;\n\n\tauth: RoomAuth;\n\t/** use `setParent` to set this */\n\treadonly parent: Room | null;\n\t/** use `subroom.setParent` to set this, or `clearSubRooms` to clear it */\n\treadonly subRooms: ReadonlyMap | null;\n\n\treadonly muteQueue: MuteEntry[];\n\tuserCount: number;\n\tactive: boolean;\n\tmuteTimer: NodeJS.Timeout | null;\n\tmodchatTimer: NodeJS.Timeout | null;\n\tlastUpdate: number;\n\tlastBroadcast: string;\n\tlastBroadcastTime: number;\n\tsettings: RoomSettings;\n\t/** If true, this room's settings will be saved in config/chatrooms.json, allowing it to stay past restarts. */\n\tpersist: boolean;\n\n\tscavgame: ScavengerGameTemplate | null;\n\tscavLeaderboard: AnyObject;\n\tresponder?: AutoResponder | null;\n\tprivacySetter?: Set | null;\n\thideReplay: boolean;\n\n\treportJoins: boolean;\n\tbatchJoins: number;\n\treportJoinsInterval: NodeJS.Timeout | null;\n\n\tminorActivity: MinorActivity | null;\n\tminorActivityQueue: MinorActivityData[] | null;\n\tbanwordRegex: RegExp | true | null;\n\tlogUserStatsInterval: NodeJS.Timeout | null;\n\texpireTimer: NodeJS.Timeout | null;\n\tuserList: string;\n\tpendingApprovals: Map | null;\n\n\tmessagesSent: number;\n\t/**\n\t * These handlers will be invoked every n messages.\n\t * handler:number-of-messages map\n\t */\n\tnthMessageHandlers: Map;\n\n\tconstructor(roomid: RoomID, title?: string, options: Partial = {}) {\n\t\tthis.users = Object.create(null);\n\t\tthis.type = 'chat';\n\t\tthis.muteQueue = [];\n\n\t\tthis.battle = null;\n\t\tthis.bestOf = null;\n\t\tthis.game = null;\n\t\tthis.subGame = null;\n\t\tthis.tour = null;\n\n\t\tthis.roomid = roomid;\n\t\tthis.title = (title || roomid);\n\t\tthis.parent = null;\n\n\t\tthis.userCount = 0;\n\n\t\tthis.game = null;\n\t\tthis.active = false;\n\n\t\tthis.muteTimer = null;\n\n\t\tthis.lastUpdate = 0;\n\t\tthis.lastBroadcast = '';\n\t\tthis.lastBroadcastTime = 0;\n\n\t\t// room settings\n\n\t\tthis.settings = {\n\t\t\ttitle: this.title,\n\t\t\tauth: Object.create(null),\n\t\t\tcreationTime: Date.now(),\n\t\t};\n\t\tthis.persist = false;\n\t\tthis.hideReplay = false;\n\t\tthis.subRooms = null;\n\t\tthis.scavgame = null;\n\t\tthis.scavLeaderboard = {};\n\t\tthis.auth = new RoomAuth(this);\n\n\t\tthis.reportJoins = true;\n\t\tthis.batchJoins = 0;\n\t\tthis.reportJoinsInterval = null;\n\n\t\toptions.title = this.title;\n\t\tif (options.isHelp) options.noAutoTruncate = true;\n\t\tthis.reportJoins = !!(Config.reportjoins || options.isPersonal);\n\t\tthis.batchJoins = options.isPersonal ? 0 : Config.reportjoinsperiod || 0;\n\t\tif (!options.auth) options.auth = {};\n\n\t\tthis.log = Roomlogs.create(this, options);\n\n\t\tthis.banwordRegex = null;\n\n\t\tthis.settings = options as RoomSettings;\n\t\tif (!this.settings.creationTime) this.settings.creationTime = Date.now();\n\t\tthis.auth.load();\n\n\t\tif (!options.isPersonal) this.persist = true;\n\n\t\tthis.minorActivity = null;\n\t\tthis.minorActivityQueue = null;\n\t\tif (options.parentid) {\n\t\t\tthis.setParent(Rooms.get(options.parentid) || null);\n\t\t}\n\n\t\tthis.subRooms = null;\n\n\t\tthis.active = false;\n\t\tthis.muteTimer = null;\n\t\tthis.modchatTimer = null;\n\n\t\tthis.logUserStatsInterval = null;\n\t\tthis.expireTimer = null;\n\t\tif (Config.logchat) {\n\t\t\tthis.roomlog('NEW CHATROOM: ' + this.roomid);\n\t\t\tif (Config.loguserstats) {\n\t\t\t\tthis.logUserStatsInterval = setInterval(() => this.logUserStats(), Config.loguserstats);\n\t\t\t}\n\t\t}\n\n\t\tthis.userList = '';\n\t\tif (this.batchJoins) {\n\t\t\tthis.userList = this.getUserList();\n\t\t}\n\t\tthis.pendingApprovals = null;\n\t\tthis.messagesSent = 0;\n\t\tthis.nthMessageHandlers = new Map();\n\t\tthis.tour = null;\n\t\tthis.game = null;\n\t\tthis.battle = null;\n\t\tthis.validateTitle(this.title, this.roomid);\n\t}\n\n\ttoString() {\n\t\treturn this.roomid;\n\t}\n\n\t/**\n\t * Send a room message to all users in the room, without recording it\n\t * in the scrollback log.\n\t */\n\tsend(message: string) {\n\t\tif (this.roomid !== 'lobby') message = '>' + this.roomid + '\\n' + message;\n\t\tif (this.userCount) Sockets.roomBroadcast(this.roomid, message);\n\t}\n\tsendMods(data: string) {\n\t\tthis.sendRankedUsers(data, '*');\n\t}\n\tsendRankedUsers(data: string, minRank: GroupSymbol = '+') {\n\t\tif (this.settings.staffRoom) {\n\t\t\tif (!this.log) throw new Error(`Staff room ${this.roomid} has no log`);\n\t\t\tthis.log.add(data);\n\t\t\treturn;\n\t\t}\n\n\t\tfor (const i in this.users) {\n\t\t\tconst user = this.users[i];\n\t\t\t// hardcoded for performance reasons (this is an inner loop)\n\t\t\tif (user.isStaff || this.auth.atLeast(user, minRank)) {\n\t\t\t\tuser.sendTo(this, data);\n\t\t\t}\n\t\t}\n\t}\n\t/**\n\t * Send a room message to a single user.\n\t */\n\tsendUser(user: Connection | User, message: string) {\n\t\tuser.sendTo(this, message);\n\t}\n\t/**\n\t * Add a room message to the room log, so it shows up in the room\n\t * for everyone, and appears in the scrollback for new users who\n\t * join.\n\t */\n\tadd(message: string) {\n\t\tthis.log.add(message);\n\t\treturn this;\n\t}\n\troomlog(message: string) {\n\t\tthis.log.roomlog(message);\n\t\treturn this;\n\t}\n\t/**\n\t * Writes an entry to the modlog for that room, and the global modlog if entry.isGlobal is true.\n\t */\n\tmodlog(entry: PartialModlogEntry) {\n\t\tconst override = this.tour ? `${this.roomid} tournament: ${this.tour.roomid}` : undefined;\n\t\tthis.log.modlog(entry, override);\n\t\treturn this;\n\t}\n\tuhtmlchange(name: string, message: string) {\n\t\tthis.log.uhtmlchange(name, message);\n\t}\n\tattributedUhtmlchange(user: User, name: string, message: string) {\n\t\tthis.log.attributedUhtmlchange(user, name, message);\n\t}\n\thideText(userids: ID[], lineCount = 0, hideRevealButton?: boolean) {\n\t\tconst cleared = this.log.clearText(userids, lineCount);\n\t\tfor (const userid of cleared) {\n\t\t\tthis.send(`|hidelines|${hideRevealButton ? 'delete' : 'hide'}|${userid}|${lineCount}`);\n\t\t}\n\t\tthis.update();\n\t}\n\t/**\n\t * Inserts (sanitized) HTML into the room log.\n\t */\n\taddRaw(message: string) {\n\t\treturn this.add('|raw|' + message);\n\t}\n\t/**\n\t * Inserts some text into the room log, attributed to user. The\n\t * attribution will not appear, and is used solely as a hint not to\n\t * highlight the user.\n\t */\n\taddByUser(user: User, text: string): this {\n\t\treturn this.add('|c|' + user.getIdentity(this) + '|/log ' + text);\n\t}\n\t/**\n\t * Like addByUser, but without logging\n\t */\n\tsendByUser(user: User | null, text: string) {\n\t\tthis.send('|c|' + (user ? user.getIdentity(this) : '~') + '|/log ' + text);\n\t}\n\t/**\n\t * Like addByUser, but sends to mods only.\n\t */\n\tsendModsByUser(user: User, text: string) {\n\t\tthis.sendMods('|c|' + user.getIdentity(this) + '|/log ' + text);\n\t}\n\tupdate() {\n\t\tif (!this.log.broadcastBuffer.length) return;\n\t\tif (this.reportJoinsInterval) {\n\t\t\tclearInterval(this.reportJoinsInterval);\n\t\t\tthis.reportJoinsInterval = null;\n\t\t\tthis.userList = this.getUserList();\n\t\t}\n\t\tthis.send(this.log.broadcastBuffer.join('\\n'));\n\t\tthis.log.broadcastBuffer = [];\n\t\tthis.log.truncate();\n\n\t\tthis.pokeExpireTimer();\n\t}\n\n\tgetUserList() {\n\t\tlet buffer = '';\n\t\tlet counter = 0;\n\t\tfor (const i in this.users) {\n\t\t\tif (!this.users[i].named) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tcounter++;\n\t\t\tbuffer += ',' + this.users[i].getIdentityWithStatus(this);\n\t\t}\n\t\tconst msg = `|users|${counter}${buffer}`;\n\t\treturn msg;\n\t}\n\n\tnextGameNumber() {\n\t\tconst gameNumber = (this.settings.gameNumber || 0) + 1;\n\t\tthis.settings.gameNumber = gameNumber;\n\t\tthis.saveSettings();\n\t\treturn gameNumber;\n\t}\n\n\t// mute handling\n\n\trunMuteTimer(forceReschedule = false) {\n\t\tif (forceReschedule && this.muteTimer) {\n\t\t\tclearTimeout(this.muteTimer);\n\t\t\tthis.muteTimer = null;\n\t\t}\n\t\tif (this.muteTimer || this.muteQueue.length === 0) return;\n\n\t\tconst timeUntilExpire = this.muteQueue[0].time - Date.now();\n\t\tif (timeUntilExpire <= 1000) { // one second of leeway\n\t\t\tthis.unmute(this.muteQueue[0].userid, \"Your mute in '\" + this.title + \"' has expired.\");\n\t\t\t// runMuteTimer() is called again in unmute() so this function instance should be closed\n\t\t\treturn;\n\t\t}\n\t\tthis.muteTimer = setTimeout(() => {\n\t\t\tthis.muteTimer = null;\n\t\t\tthis.runMuteTimer(true);\n\t\t}, timeUntilExpire);\n\t}\n\tisMuted(user: User): ID | undefined {\n\t\tif (!user) return;\n\t\tif (this.muteQueue) {\n\t\t\tfor (const entry of this.muteQueue) {\n\t\t\t\tif (user.id === entry.userid ||\n\t\t\t\t\tuser.guestNum === entry.guestNum ||\n\t\t\t\t\t(user.autoconfirmed && user.autoconfirmed === entry.autoconfirmed)) {\n\t\t\t\t\tif (entry.time - Date.now() < 0) {\n\t\t\t\t\t\tthis.unmute(user.id);\n\t\t\t\t\t\treturn;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn entry.userid;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (this.parent) return this.parent.isMuted(user);\n\t}\n\tgetMuteTime(user: User): number | undefined {\n\t\tconst userid = this.isMuted(user);\n\t\tif (!userid) return;\n\t\tfor (const entry of this.muteQueue) {\n\t\t\tif (userid === entry.userid) {\n\t\t\t\treturn entry.time - Date.now();\n\t\t\t}\n\t\t}\n\t\tif (this.parent) return this.parent.getMuteTime(user);\n\t}\n\tgetGame(constructor: new (...args: any[]) => T, subGame = false): T | null {\n\t\t// TODO: switch to `static readonly gameid` when all game files are TypeScripted\n\t\tif (subGame && this.subGame && this.subGame.constructor.name === constructor.name) return this.subGame as T;\n\t\tif (this.game && this.game.constructor.name === constructor.name) return this.game as T;\n\t\treturn null;\n\t}\n\tgetMinorActivity(constructor: new (...args: any[]) => T): T | null {\n\t\tif (this.minorActivity?.constructor.name === constructor.name) return this.minorActivity as T;\n\t\treturn null;\n\t}\n\tgetMinorActivityQueue(settings = false): MinorActivityData[] | null {\n\t\tconst usedQueue = settings ? this.settings.minorActivityQueue : this.minorActivityQueue;\n\t\tif (!usedQueue?.length) return null;\n\t\treturn usedQueue;\n\t}\n\tqueueMinorActivity(activity: MinorActivityData): void {\n\t\tif (!this.minorActivityQueue) this.minorActivityQueue = [];\n\t\tthis.minorActivityQueue.push(activity);\n\t\tthis.settings.minorActivityQueue = this.minorActivityQueue;\n\t}\n\tclearMinorActivityQueue(slot?: number, depth = 1) {\n\t\tif (!this.minorActivityQueue) return;\n\t\tif (slot === undefined) {\n\t\t\tthis.minorActivityQueue = null;\n\t\t\tdelete this.settings.minorActivityQueue;\n\t\t\tthis.saveSettings();\n\t\t} else {\n\t\t\tthis.minorActivityQueue.splice(slot, depth);\n\t\t\tthis.settings.minorActivityQueue = this.minorActivityQueue;\n\t\t\tthis.saveSettings();\n\t\t\tif (!this.minorActivityQueue.length) this.clearMinorActivityQueue();\n\t\t}\n\t}\n\tsetMinorActivity(activity: MinorActivity | null, noDisplay = false): void {\n\t\tthis.minorActivity?.endTimer();\n\t\tthis.minorActivity = activity;\n\t\tif (this.minorActivity) {\n\t\t\tthis.minorActivity.save();\n\t\t\tif (!noDisplay) this.minorActivity.display();\n\t\t} else {\n\t\t\tdelete this.settings.minorActivity;\n\t\t\tthis.saveSettings();\n\t\t}\n\t}\n\tsaveSettings() {\n\t\tif (!this.persist) return;\n\n\t\tif (!Rooms.global) return; // during initialization\n\n\t\tRooms.global.writeChatRoomData();\n\t}\n\tcheckModjoin(user: User) {\n\t\tif (user.id in this.users) return true;\n\t\tif (!this.settings.modjoin) return true;\n\t\t// users with a room rank can always join\n\t\tif (this.auth.has(user.id)) return true;\n\n\t\tconst modjoinSetting = this.settings.modjoin !== true ? this.settings.modjoin : this.settings.modchat;\n\t\tif (!modjoinSetting) return true;\n\t\tif (!Users.Auth.isAuthLevel(modjoinSetting)) {\n\t\t\tMonitor.error(`Invalid modjoin setting in ${this.roomid}: ${modjoinSetting}`);\n\t\t}\n\t\treturn (\n\t\t\tthis.auth.atLeast(user, modjoinSetting) || Users.globalAuth.atLeast(user, modjoinSetting)\n\t\t);\n\t}\n\tmute(user: User, setTime?: number) {\n\t\tconst userid = user.id;\n\n\t\tif (!setTime) setTime = 7 * 60000; // default time: 7 minutes\n\t\tif (setTime > 90 * 60000) setTime = 90 * 60000; // limit 90 minutes\n\n\t\t// If the user is already muted, the existing queue position for them should be removed\n\t\tif (this.isMuted(user)) this.unmute(userid);\n\n\t\t// Place the user in a queue for the unmute timer\n\t\tfor (let i = 0; i <= this.muteQueue.length; i++) {\n\t\t\tconst time = Date.now() + setTime;\n\t\t\tif (i === this.muteQueue.length || time < this.muteQueue[i].time) {\n\t\t\t\tconst entry = {\n\t\t\t\t\tuserid,\n\t\t\t\t\ttime,\n\t\t\t\t\tguestNum: user.guestNum,\n\t\t\t\t\tautoconfirmed: user.autoconfirmed,\n\t\t\t\t};\n\t\t\t\tthis.muteQueue.splice(i, 0, entry);\n\t\t\t\t// The timer needs to be switched to the new entry if it is to be unmuted\n\t\t\t\t// before the entry the timer is currently running for\n\t\t\t\tif (i === 0 && this.muteTimer) {\n\t\t\t\t\tclearTimeout(this.muteTimer);\n\t\t\t\t\tthis.muteTimer = null;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tthis.runMuteTimer();\n\n\t\tuser.updateIdentity();\n\n\t\tif (!(this.settings.isPrivate === true || this.settings.isPersonal)) {\n\t\t\tvoid Punishments.monitorRoomPunishments(user);\n\t\t}\n\n\t\treturn userid;\n\t}\n\tunmute(userid: string, notifyText?: string) {\n\t\tlet successUserid = '';\n\t\tconst user = Users.get(userid);\n\t\tlet autoconfirmed = '';\n\t\tif (user) {\n\t\t\tuserid = user.id;\n\t\t\tautoconfirmed = user.autoconfirmed;\n\t\t}\n\n\t\tfor (const [i, entry] of this.muteQueue.entries()) {\n\t\t\tif (entry.userid === userid ||\n\t\t\t\t(user && entry.guestNum === user.guestNum) ||\n\t\t\t\t(autoconfirmed && entry.autoconfirmed === autoconfirmed)) {\n\t\t\t\tif (i === 0) {\n\t\t\t\t\tthis.muteQueue.splice(0, 1);\n\t\t\t\t\tthis.runMuteTimer(true);\n\t\t\t\t} else {\n\t\t\t\t\tthis.muteQueue.splice(i, 1);\n\t\t\t\t}\n\t\t\t\tsuccessUserid = entry.userid;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (user && successUserid && userid in this.users) {\n\t\t\tuser.updateIdentity();\n\t\t\tif (notifyText) user.popup(notifyText);\n\t\t}\n\t\treturn successUserid;\n\t}\n\n\tlogUserStats() {\n\t\tlet total = 0;\n\t\tlet guests = 0;\n\t\tconst groups: { [k: string]: number } = {};\n\t\tfor (const group of Config.groupsranking) {\n\t\t\tgroups[group] = 0;\n\t\t}\n\t\tfor (const i in this.users) {\n\t\t\tconst user = this.users[i];\n\t\t\t++total;\n\t\t\tif (!user.named) {\n\t\t\t\t++guests;\n\t\t\t}\n\t\t\t++groups[this.auth.get(user.id)];\n\t\t}\n\t\tlet entry = `|userstats|total:${total}|guests:${guests}`;\n\t\tfor (const i in groups) {\n\t\t\tentry += `|${i}:${groups[i]}`;\n\t\t}\n\t\tthis.roomlog(entry);\n\t}\n\n\tpokeExpireTimer() {\n\t\tif (this.expireTimer) clearTimeout(this.expireTimer);\n\t\tif (this.settings.isPersonal) {\n\t\t\tthis.expireTimer = setTimeout(() => this.expire(), TIMEOUT_INACTIVE_DEALLOCATE);\n\t\t} else {\n\t\t\tthis.expireTimer = null;\n\t\t}\n\t}\n\texpire() {\n\t\tthis.send('|expire|');\n\t\tthis.destroy();\n\t}\n\treportJoin(type: 'j' | 'l' | 'n', entry: string, user: User) {\n\t\tconst canTalk = this.auth.atLeast(user, this.settings.modchat ?? 'unlocked') && !this.isMuted(user);\n\t\tif (this.reportJoins && (canTalk || this.auth.has(user.id))) {\n\t\t\tthis.add(`|${type}|${entry}`).update();\n\t\t\treturn;\n\t\t}\n\t\tlet ucType = '';\n\t\tswitch (type) {\n\t\tcase 'j': ucType = 'J'; break;\n\t\tcase 'l': ucType = 'L'; break;\n\t\tcase 'n': ucType = 'N'; break;\n\t\t}\n\t\tentry = `|${ucType}|${entry}`;\n\t\tif (this.batchJoins) {\n\t\t\tthis.log.broadcastBuffer.push(entry);\n\n\t\t\tif (!this.reportJoinsInterval) {\n\t\t\t\tthis.reportJoinsInterval = setTimeout(\n\t\t\t\t\t() => this.update(), this.batchJoins\n\t\t\t\t);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.send(entry);\n\t\t}\n\t\tthis.roomlog(entry);\n\t}\n\tgetIntroMessage(user: User) {\n\t\tlet message = Utils.html`\\n|raw|
You joined ${this.title}`;\n\t\tif (this.settings.modchat) {\n\t\t\tmessage += ` [${this.settings.modchat} or higher to talk]`;\n\t\t}\n\t\tif (this.settings.modjoin) {\n\t\t\tconst modjoin = this.settings.modjoin === true ? this.settings.modchat : this.settings.modjoin;\n\t\t\tmessage += ` [${modjoin} or higher to join]`;\n\t\t}\n\t\tif (this.settings.slowchat) {\n\t\t\tmessage += ` [Slowchat ${this.settings.slowchat}s]`;\n\t\t}\n\t\tmessage += `
`;\n\t\tif (this.settings.introMessage) {\n\t\t\tmessage += `\\n|raw|
` +\n\t\t\t\tthis.settings.introMessage.replace(/\\n/g, '') +\n\t\t\t\t`
`;\n\t\t}\n\t\tconst staffIntro = this.getStaffIntroMessage(user);\n\t\tif (staffIntro) message += `\\n${staffIntro}`;\n\t\treturn message;\n\t}\n\tgetStaffIntroMessage(user: User) {\n\t\tif (!user.can('mute', null, this)) return ``;\n\t\tconst messages = [];\n\t\tif (this.settings.staffMessage) {\n\t\t\tmessages.push(`|raw|
(Staff intro:)
` +\n\t\t\t\tthis.settings.staffMessage.replace(/\\n/g, '') +\n\t\t\t\t`
`);\n\t\t}\n\t\tif (this.pendingApprovals?.size) {\n\t\t\tlet message = `|raw|
`;\n\t\t\tmessage += `
(Pending media requests: ${this.pendingApprovals.size})`;\n\t\t\tfor (const [userid, entry] of this.pendingApprovals) {\n\t\t\t\tmessage += `
`;\n\t\t\t\tmessage += `Requester ID: ${userid}
`;\n\t\t\t\tif (entry.dimensions) {\n\t\t\t\t\tconst [width, height, resized] = entry.dimensions;\n\t\t\t\t\tmessage += `Link:

`;\n\t\t\t\t\tif (resized) message += `(Resized)
`;\n\t\t\t\t} else {\n\t\t\t\t\tmessage += `Link:
Link
`;\n\t\t\t\t}\n\t\t\t\tmessage += `Comment: ${entry.comment ? entry.comment : 'None.'}
`;\n\t\t\t\tmessage += `` +\n\t\t\t\t\t`
`;\n\t\t\t\tmessage += `
`;\n\t\t\t}\n\t\t\tmessage += `
`;\n\t\t\tmessages.push(message);\n\t\t}\n\t\tif (\n\t\t\t!this.settings.isPrivate && !this.settings.isPersonal &&\n\t\t\tthis.settings.modchat && this.settings.modchat !== 'autoconfirmed'\n\t\t) {\n\t\t\tmessages.push(`|raw|
Modchat currently set to ${this.settings.modchat}
`);\n\t\t}\n\t\treturn messages.join('\\n');\n\t}\n\tgetSubRooms(includeSecret = false) {\n\t\tif (!this.subRooms) return [];\n\t\treturn [...this.subRooms.values()].filter(\n\t\t\troom => includeSecret ? true : !room.settings.isPrivate && !room.settings.isPersonal\n\t\t);\n\t}\n\tvalidateTitle(newTitle: string, newID?: string, oldID?: string) {\n\t\tif (!newID) newID = toID(newTitle);\n\t\t// `,` is a delimiter used by a lot of /commands\n\t\t// `|` and `[` are delimiters used by the protocol\n\t\t// `-` has special meaning in roomids\n\t\tif (newTitle.includes(',') || newTitle.includes('|')) {\n\t\t\tthrow new Chat.ErrorMessage(`Room title \"${newTitle}\" can't contain any of: ,|`);\n\t\t}\n\t\tif ((!newID.includes('-') || newID.startsWith('groupchat-')) && newTitle.includes('-')) {\n\t\t\tthrow new Chat.ErrorMessage(`Room title \"${newTitle}\" can't contain -`);\n\t\t}\n\t\tif (newID.length > MAX_CHATROOM_ID_LENGTH) throw new Chat.ErrorMessage(\"The given room title is too long.\");\n\t\tif (newID !== oldID && Rooms.search(newTitle)) throw new Chat.ErrorMessage(`The room '${newTitle}' already exists.`);\n\t}\n\tsetParent(room: Room | null) {\n\t\tif (this.parent === room) return;\n\n\t\tif (this.parent) {\n\t\t\t(this.parent.subRooms as any).delete(this.roomid);\n\t\t\tif (!this.parent.subRooms!.size) {\n\t\t\t\t(this.parent.subRooms as any) = null;\n\t\t\t}\n\t\t}\n\t\t(this as any).parent = room;\n\t\tif (room) {\n\t\t\tif (!room.subRooms) {\n\t\t\t\t(room as any).subRooms = new Map();\n\t\t\t}\n\t\t\t(room as any).subRooms.set(this.roomid, this);\n\t\t\tthis.settings.parentid = room.roomid;\n\t\t} else {\n\t\t\tdelete this.settings.parentid;\n\t\t}\n\n\t\tthis.saveSettings();\n\n\t\tfor (const userid in this.users) {\n\t\t\tthis.users[userid].updateIdentity(this.roomid);\n\t\t}\n\t}\n\tclearSubRooms() {\n\t\tif (!this.subRooms) return;\n\t\tfor (const room of this.subRooms.values()) {\n\t\t\t(room as any).parent = null;\n\t\t}\n\t\t(this as any).subRooms = null;\n\n\t\t// this doesn't update parentid or subroom user symbols because it's\n\t\t// intended to be used for cleanup only\n\t}\n\tsetPrivate(privacy: PrivacySetting) {\n\t\tthis.settings.isPrivate = privacy;\n\t\tthis.saveSettings();\n\n\t\tif (privacy) {\n\t\t\tfor (const user of Object.values(this.users)) {\n\t\t\t\tif (!user.named) {\n\t\t\t\t\tuser.leaveRoom(this.roomid);\n\t\t\t\t\tuser.popup(`The room <<${this.roomid}>> has been made private; you must log in to be in private rooms.`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (this.battle || this.bestOf) {\n\t\t\tif (privacy) {\n\t\t\t\tif (this.roomid.endsWith('pw')) return true;\n\n\t\t\t\t// This is the same password generation approach as genPassword in the client replays.lib.php\n\t\t\t\t// but obviously will not match given mt_rand there uses a different RNG and seed.\n\t\t\t\tlet password = '';\n\t\t\t\tfor (let i = 0; i < 31; i++) password += ALPHABET[crypto.randomInt(0, ALPHABET.length - 1)];\n\n\t\t\t\tthis.rename(this.title, `${this.roomid}-${password}pw` as RoomID, true);\n\t\t\t} else {\n\t\t\t\tif (!this.roomid.endsWith('pw')) return true;\n\n\t\t\t\tconst lastDashIndex = this.roomid.lastIndexOf('-');\n\t\t\t\tif (lastDashIndex < 0) throw new Error(`invalid battle ID ${this.roomid}`);\n\n\t\t\t\tthis.rename(this.title, this.roomid.slice(0, lastDashIndex) as RoomID);\n\t\t\t}\n\t\t}\n\t\tthis.bestOf?.setPrivacyOfGames(privacy);\n\n\t\tif (this.game) {\n\t\t\tfor (const player of this.game.players) {\n\t\t\t\tplayer.getUser()?.updateSearch();\n\t\t\t}\n\t\t}\n\t}\n\tvalidateSection(section: string) {\n\t\tconst target = toID(section);\n\t\tif (!RoomSections.sections.includes(target as any)) {\n\t\t\tthrow new Chat.ErrorMessage(`\"${target}\" is not a valid room section. Valid categories include: ${RoomSections.sections.join(', ')}`);\n\t\t}\n\t\treturn target as RoomSection;\n\t}\n\tsetSection(section?: string) {\n\t\tif (!this.persist) {\n\t\t\tthrow new Chat.ErrorMessage(`You cannot change the section of temporary rooms.`);\n\t\t}\n\t\tif (section) {\n\t\t\tconst validatedSection = this.validateSection(section);\n\t\t\tif (this.settings.isPrivate && [true, 'hidden'].includes(this.settings.isPrivate)) {\n\t\t\t\tthrow new Chat.ErrorMessage(`Only public rooms can change their section.`);\n\t\t\t}\n\t\t\tconst oldSection = this.settings.section;\n\t\t\tif (oldSection === section) {\n\t\t\t\tthrow new Chat.ErrorMessage(`${this.title}'s room section is already set to \"${RoomSections.sectionNames[oldSection]}\".`);\n\t\t\t}\n\t\t\tthis.settings.section = validatedSection;\n\t\t\tthis.saveSettings();\n\t\t\treturn validatedSection;\n\t\t}\n\t\tdelete this.settings.section;\n\t\tthis.saveSettings();\n\t\treturn undefined;\n\t}\n\n\t/**\n\t * Displays a warning popup to all non-staff users users in the room.\n\t * Returns a list of all the user IDs that were warned.\n\t */\n\twarnParticipants(message: string) {\n\t\tconst warned = Object.values(this.users).filter(u => !u.can('lock'));\n\t\tfor (const user of warned) {\n\t\t\tuser.popup(`|modal|${message}`);\n\t\t}\n\t\treturn warned;\n\t}\n\n\t/**\n\t * @param newID Add this param if the roomid is different from `toID(newTitle)`\n\t * @param noAlias Set this param to true to not redirect aliases and the room's old name to its new name.\n\t */\n\trename(newTitle: string, newID?: RoomID, noAlias?: boolean) {\n\t\tif (!newID) newID = toID(newTitle) as RoomID;\n\t\tconst oldID = this.roomid;\n\t\tthis.validateTitle(newTitle, newID, oldID);\n\t\tif (this.type === 'chat' && this.game) {\n\t\t\tthrow new Chat.ErrorMessage(`Please finish your game (${this.game.title}) before renaming ${this.roomid}.`);\n\t\t}\n\t\t(this as any).roomid = newID;\n\t\tthis.title = this.settings.title = newTitle;\n\t\tthis.saveSettings();\n\t\tif (newID === oldID) {\n\t\t\tfor (const user of Object.values(this.users)) {\n\t\t\t\tuser.sendTo(this, `|title|${newTitle}`);\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\tRooms.rooms.delete(oldID);\n\t\tRooms.rooms.set(newID, this as Room);\n\t\tif (this.battle && oldID) {\n\t\t\tfor (const player of this.battle.players) {\n\t\t\t\tif (player.invite) {\n\t\t\t\t\tconst chall = Ladders.challenges.searchByRoom(player.invite, oldID);\n\t\t\t\t\tif (chall) chall.roomid = this.roomid;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (oldID === 'lobby') {\n\t\t\tRooms.lobby = null;\n\t\t} else if (newID === 'lobby') {\n\t\t\tRooms.lobby = this as ChatRoom;\n\t\t}\n\n\t\tif (!noAlias) {\n\t\t\tfor (const [alias, roomid] of Rooms.aliases.entries()) {\n\t\t\t\tif (roomid === oldID) {\n\t\t\t\t\tRooms.aliases.set(alias, newID);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// add an alias from the old id\n\t\t\tRooms.aliases.set(oldID, newID);\n\t\t\tif (!this.settings.aliases) this.settings.aliases = [];\n\t\t\t// resolve an old (fixed) bug in /renameroom\n\t\t\tif (!this.settings.aliases.includes(oldID)) this.settings.aliases.push(oldID);\n\t\t} else {\n\t\t\t// clear aliases\n\t\t\tfor (const [alias, roomid] of Rooms.aliases.entries()) {\n\t\t\t\tif (roomid === oldID) {\n\t\t\t\t\tRooms.aliases.delete(alias);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthis.settings.aliases = undefined;\n\t\t}\n\n\t\tthis.game?.renameRoom(newID);\n\n\t\tfor (const user of Object.values(this.users)) {\n\t\t\tuser.moveConnections(oldID, newID);\n\t\t\tuser.send(`>${oldID}\\n|noinit|rename|${newID}|${newTitle}`);\n\t\t}\n\n\t\tif (this.parent?.subRooms) {\n\t\t\t(this as any).parent.subRooms.delete(oldID);\n\t\t\t(this as any).parent.subRooms.set(newID, this as ChatRoom);\n\t\t}\n\t\tif (this.subRooms) {\n\t\t\tfor (const subRoom of this.subRooms.values()) {\n\t\t\t\t(subRoom as any).parent = this as ChatRoom;\n\t\t\t\tsubRoom.settings.parentid = newID;\n\t\t\t}\n\t\t}\n\n\t\tthis.saveSettings();\n\n\t\tPunishments.renameRoom(oldID, newID);\n\n\t\tvoid this.log.rename(newID);\n\t}\n\n\tonConnect(user: User, connection: Connection) {\n\t\tconst userList = this.userList ? this.userList : this.getUserList();\n\t\tthis.sendUser(\n\t\t\tconnection,\n\t\t\t'|init|chat\\n|title|' + this.title + '\\n' + userList + '\\n' + this.log.getScrollback() + this.getIntroMessage(user)\n\t\t);\n\t\tthis.minorActivity?.onConnect?.(user, connection);\n\t\tthis.game?.onConnect?.(user, connection);\n\t}\n\tonJoin(user: User, connection: Connection) {\n\t\tif (!user) return false; // ???\n\t\tif (this.users[user.id]) return false;\n\n\t\tChat.runHandlers('onBeforeRoomJoin', this, user, connection);\n\t\tif (user.named) {\n\t\t\tthis.reportJoin('j', user.getIdentityWithStatus(this), user);\n\t\t}\n\n\t\tconst staffIntro = this.getStaffIntroMessage(user);\n\t\tif (staffIntro) this.sendUser(user, staffIntro);\n\n\t\tthis.users[user.id] = user;\n\t\tthis.userCount++;\n\t\tthis.checkAutoModchat(user);\n\n\t\tthis.game?.onJoin?.(user, connection);\n\t\tChat.runHandlers('onRoomJoin', this, user, connection);\n\t\treturn true;\n\t}\n\tonRename(user: User, oldid: ID, joining: boolean) {\n\t\tif (user.id === oldid) {\n\t\t\treturn this.onUpdateIdentity(user);\n\t\t}\n\t\tif (!this.users[oldid]) {\n\t\t\tMonitor.crashlog(new Error(`user ${oldid} not in room ${this.roomid}`));\n\t\t}\n\t\tif (this.users[user.id]) {\n\t\t\tMonitor.crashlog(new Error(`user ${user.id} already in room ${this.roomid}`));\n\t\t}\n\t\tdelete this.users[oldid];\n\t\tthis.users[user.id] = user;\n\t\tif (joining) {\n\t\t\tthis.reportJoin('j', user.getIdentityWithStatus(this), user);\n\t\t\tconst staffIntro = this.getStaffIntroMessage(user);\n\t\t\tif (staffIntro) this.sendUser(user, staffIntro);\n\t\t} else if (!user.named) {\n\t\t\tthis.reportJoin('l', ' ' + oldid, user);\n\t\t} else {\n\t\t\tthis.reportJoin('n', user.getIdentityWithStatus(this) + '|' + oldid, user);\n\t\t}\n\t\tthis.minorActivity?.onRename?.(user, oldid, joining);\n\t\tthis.checkAutoModchat(user);\n\t\treturn true;\n\t}\n\t/**\n\t * onRename, but without a userid change\n\t */\n\tonUpdateIdentity(user: User) {\n\t\tif (user?.connected) {\n\t\t\tif (!this.users[user.id]) return false;\n\t\t\tif (user.named) {\n\t\t\t\tthis.reportJoin('n', user.getIdentityWithStatus(this) + '|' + user.id, user);\n\t\t\t}\n\t\t}\n\t\treturn true;\n\t}\n\tonLeave(user: User) {\n\t\tif (!user) return false; // ...\n\n\t\tif (!(user.id in this.users)) {\n\t\t\tMonitor.crashlog(new Error(`user ${user.id} already left`));\n\t\t\treturn false;\n\t\t}\n\t\tdelete this.users[user.id];\n\t\tthis.userCount--;\n\n\t\tif (user.named) {\n\t\t\tthis.reportJoin('l', user.getIdentity(this), user);\n\t\t}\n\t\tthis.game?.onLeave?.(user);\n\t\tthis.runAutoModchat();\n\n\t\treturn true;\n\t}\n\n\trunAutoModchat() {\n\t\tif (!this.settings.autoModchat || this.settings.autoModchat.active) return;\n\t\t// they are staff and online\n\t\tconst staff = Object.values(this.users).filter(u => this.auth.atLeast(u, '%'));\n\t\tif (!staff.length) {\n\t\t\tconst { time } = this.settings.autoModchat;\n\t\t\tif (!time || time < 5) {\n\t\t\t\tthrow new Error(`Invalid time setting for automodchat (${Utils.visualize(this.settings.autoModchat)})`);\n\t\t\t}\n\t\t\tif (this.modchatTimer) return;\n\t\t\tthis.modchatTimer = setTimeout(() => {\n\t\t\t\tif (!this.settings.autoModchat) return;\n\t\t\t\tconst { rank } = this.settings.autoModchat;\n\t\t\t\tconst oldSetting = this.settings.modchat;\n\t\t\t\tthis.settings.modchat = rank;\n\t\t\t\tthis.add(\n\t\t\t\t\t// always gonna be minutes so we can just use the number directly lol\n\t\t\t\t\t`|raw|
This room has had no active staff for ${time} minutes,` +\n\t\t\t\t\t` and has had modchat set to ${rank}.
`\n\t\t\t\t).update();\n\t\t\t\tthis.modlog({\n\t\t\t\t\taction: 'AUTOMODCHAT ACTIVATE',\n\t\t\t\t});\n\t\t\t\t// automodchat will always exist\n\t\t\t\tthis.settings.autoModchat.active = oldSetting || true;\n\t\t\t\tthis.saveSettings();\n\t\t\t\tthis.modchatTimer = null;\n\t\t\t}, time * 60 * 1000);\n\t\t}\n\t}\n\n\tcheckAutoModchat(user: User) {\n\t\tif (user.can('mute', null, this, 'modchat')) {\n\t\t\tif (this.modchatTimer) {\n\t\t\t\tclearTimeout(this.modchatTimer);\n\t\t\t}\n\t\t\tif (this.settings.autoModchat?.active) {\n\t\t\t\tconst oldSetting = this.settings.autoModchat.active;\n\t\t\t\tif (typeof oldSetting === 'string') {\n\t\t\t\t\tthis.settings.modchat = oldSetting;\n\t\t\t\t} else {\n\t\t\t\t\tdelete this.settings.modchat;\n\t\t\t\t}\n\t\t\t\tthis.settings.autoModchat.active = false;\n\t\t\t\tthis.saveSettings();\n\t\t\t}\n\t\t}\n\t}\n\n\tdestroy(): void {\n\t\t// deallocate ourself\n\n\t\tif (this.game) {\n\t\t\tthis.game.destroy();\n\t\t\tthis.game = null;\n\t\t\tthis.battle = null;\n\t\t\tthis.tour = null;\n\t\t}\n\n\t\t// remove references to ourself\n\t\tfor (const i in this.users) {\n\t\t\tthis.users[i].leaveRoom(this as Room, null);\n\t\t\tdelete this.users[i];\n\t\t}\n\n\t\tthis.setParent(null);\n\t\tthis.clearSubRooms();\n\n\t\tChat.runHandlers('onRoomDestroy', this.roomid);\n\n\t\tRooms.global.deregisterChatRoom(this.roomid);\n\t\tRooms.global.delistChatRoom(this.roomid);\n\n\t\tif (this.settings.aliases) {\n\t\t\tfor (const alias of this.settings.aliases) {\n\t\t\t\tRooms.aliases.delete(alias);\n\t\t\t}\n\t\t}\n\n\t\tthis.active = false;\n\n\t\t// Ensure there aren't any pending messages that could restart the expire timer\n\t\tthis.update();\n\n\t\t// Clear any active timers for the room\n\t\tif (this.muteTimer) {\n\t\t\tclearTimeout(this.muteTimer);\n\t\t\tthis.muteTimer = null;\n\t\t}\n\t\tif (this.expireTimer) {\n\t\t\tclearTimeout(this.expireTimer);\n\t\t\tthis.expireTimer = null;\n\t\t}\n\t\tif (this.reportJoinsInterval) {\n\t\t\tclearInterval(this.reportJoinsInterval);\n\t\t}\n\t\tthis.reportJoinsInterval = null;\n\t\tif (this.logUserStatsInterval) {\n\t\t\tclearInterval(this.logUserStatsInterval);\n\t\t}\n\t\tthis.logUserStatsInterval = null;\n\n\t\tvoid this.log.destroy();\n\n\t\tRooms.rooms.delete(this.roomid);\n\t\tif (this.roomid === 'lobby') Rooms.lobby = null;\n\t}\n\ttr(strings: string | TemplateStringsArray, ...keys: any[]) {\n\t\treturn Chat.tr(this.settings.language || 'english' as ID, strings, ...keys);\n\t}\n}\n\nexport class GlobalRoomState {\n\treadonly settingsList: RoomSettings[];\n\treadonly chatRooms: ChatRoom[];\n\t/**\n\t * Rooms that users autojoin upon connecting\n\t */\n\treadonly autojoinList: RoomID[];\n\t/**\n\t * Rooms that users autojoin upon logging in\n\t */\n\treadonly modjoinedAutojoinList: RoomID[];\n\treadonly ladderIpLog: Streams.WriteStream;\n\treadonly reportUserStatsInterval: NodeJS.Timeout;\n\tlockdown: boolean | 'pre' | 'ddos';\n\tbattleCount: number;\n\tlastReportedCrash: number;\n\tlastBattle: number;\n\tlastWrittenBattle: number;\n\tmaxUsers: number;\n\tmaxUsersDate: number;\n\tformatList: string;\n\n\tconstructor() {\n\t\tthis.settingsList = [];\n\t\ttry {\n\t\t\tthis.settingsList = require(FS('config/chatrooms.json').path);\n\t\t\tif (!Array.isArray(this.settingsList)) this.settingsList = [];\n\t\t} catch {} // file doesn't exist [yet]\n\n\t\tif (!this.settingsList.length) {\n\t\t\tthis.settingsList = [{\n\t\t\t\ttitle: 'Lobby',\n\t\t\t\tauth: {},\n\t\t\t\tcreationTime: Date.now(),\n\t\t\t\tautojoin: true,\n\t\t\t\tsection: 'official',\n\t\t\t}, {\n\t\t\t\ttitle: 'Staff',\n\t\t\t\tauth: {},\n\t\t\t\tcreationTime: Date.now(),\n\t\t\t\tisPrivate: 'hidden',\n\t\t\t\tmodjoin: '%',\n\t\t\t\tautojoin: true,\n\t\t\t}];\n\t\t}\n\n\t\tthis.chatRooms = [];\n\n\t\tthis.autojoinList = [];\n\t\tthis.modjoinedAutojoinList = [];\n\t\tfor (const [i, settings] of this.settingsList.entries()) {\n\t\t\tif (!settings?.title) {\n\t\t\t\tMonitor.warn(`ERROR: Room number ${i} has no data and could not be loaded.`);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif ((settings as any).staffAutojoin) {\n\t\t\t\t// convert old staffAutojoin format\n\t\t\t\tdelete (settings as any).staffAutojoin;\n\t\t\t\t(settings as any).autojoin = true;\n\t\t\t\tif (!settings.modjoin) settings.modjoin = '%';\n\t\t\t\tif (settings.isPrivate === true) settings.isPrivate = 'hidden';\n\t\t\t}\n\n\t\t\t// We're okay with assinging type `ID` to `RoomID` here\n\t\t\t// because the hyphens in chatrooms don't have any special\n\t\t\t// meaning, unlike in helptickets, groupchats, battles etc\n\t\t\t// where they are used for shared modlogs and the like\n\t\t\tconst id = toID(settings.title) as RoomID;\n\t\t\tMonitor.notice(\"RESTORE CHATROOM: \" + id);\n\t\t\tconst room = Rooms.createChatRoom(id, settings.title, settings);\n\t\t\tif (room.settings.aliases) {\n\t\t\t\tfor (const alias of room.settings.aliases) {\n\t\t\t\t\tRooms.aliases.set(alias, id);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis.chatRooms.push(room);\n\t\t\tif (room.settings.autojoin) {\n\t\t\t\tif (room.settings.modjoin) {\n\t\t\t\t\tthis.modjoinedAutojoinList.push(id);\n\t\t\t\t} else {\n\t\t\t\t\tthis.autojoinList.push(id);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tRooms.lobby = Rooms.rooms.get('lobby') as ChatRoom;\n\n\t\t// init battle room logging\n\t\tif (Config.logladderip) {\n\t\t\tthis.ladderIpLog = Monitor.logPath('ladderip/ladderip.txt').createAppendStream();\n\t\t} else {\n\t\t\t// Prevent there from being two possible hidden classes an instance\n\t\t\t// of GlobalRoom can have.\n\t\t\tthis.ladderIpLog = new Streams.WriteStream({ write() { return undefined; } });\n\t\t}\n\n\t\tthis.reportUserStatsInterval = setInterval(\n\t\t\t() => this.reportUserStats(),\n\t\t\tREPORT_USER_STATS_INTERVAL\n\t\t);\n\n\t\t// init users\n\t\tthis.maxUsers = 0;\n\t\tthis.maxUsersDate = 0;\n\t\tthis.lockdown = false;\n\n\t\tthis.battleCount = 0;\n\t\tthis.lastReportedCrash = 0;\n\n\t\tthis.formatList = '';\n\n\t\tlet lastBattle;\n\t\ttry {\n\t\t\tlastBattle = Monitor.logPath('lastbattle.txt').readSync('utf8');\n\t\t} catch {}\n\t\tthis.lastBattle = Number(lastBattle) || 0;\n\t\tthis.lastWrittenBattle = this.lastBattle;\n\t\tvoid this.loadBattles();\n\t}\n\n\tasync serializeBattleRoom(room: Room) {\n\t\tif (!room.battle || room.battle.ended) return null;\n\t\troom.battle.frozen = true;\n\t\tconst log = await room.battle.getLog();\n\t\tconst players = room.battle.players.map(p => p.id).filter(Boolean);\n\t\tif (!players.length || !log?.length) return null; // shouldn't happen???\n\t\t// players can be empty right after `/importinputlog`\n\t\treturn {\n\t\t\troomid: room.roomid,\n\t\t\tinputLog: log.join('\\n'),\n\t\t\tplayers,\n\t\t\ttitle: room.title,\n\t\t\trated: room.battle.rated,\n\t\t\ttimer: {\n\t\t\t\t...room.battle.timer.settings,\n\t\t\t\tactive: !!room.battle.timer.timer || false,\n\t\t\t},\n\t\t};\n\t}\n\tdeserializeBattleRoom(battle: NonNullable>>) {\n\t\tconst { inputLog, players, roomid, title, rated, timer } = battle;\n\t\tconst [, formatid] = roomid.split('-');\n\t\tconst room = Rooms.createBattle({\n\t\t\tformat: formatid,\n\t\t\tinputLog,\n\t\t\troomid,\n\t\t\ttitle,\n\t\t\trated: Number(rated),\n\t\t\tplayers: [],\n\t\t\tdelayedTimer: timer.active,\n\t\t});\n\t\tif (!room?.battle) return false; // shouldn't happen???\n\t\tif (timer) { // json blob of settings\n\t\t\tObject.assign(room.battle.timer.settings, timer);\n\t\t}\n\t\tfor (const [i, playerid] of players.entries()) {\n\t\t\troom.auth.set(playerid, Users.PLAYER_SYMBOL);\n\t\t\tconst player = room.battle.players[i];\n\t\t\t(player.id as string) = playerid;\n\t\t\troom.battle.playerTable[playerid] = player;\n\t\t\tplayer.hasTeam = true;\n\t\t\tconst user = Users.getExact(playerid);\n\t\t\tplayer.name = user?.name || playerid; // in case user hasn't reconnected yet\n\t\t\tuser?.joinRoom(room);\n\t\t}\n\t\treturn true;\n\t}\n\n\tasync saveBattles() {\n\t\tlet count = 0;\n\t\tconst out = Monitor.logPath('battles.jsonl.progress').createAppendStream();\n\t\tfor (const room of Rooms.rooms.values()) {\n\t\t\tif (!room.battle || room.battle.ended) continue;\n\t\t\troom.battle.frozen = true;\n\t\t\troom.battle.timer.stop();\n\t\t\tconst b = await this.serializeBattleRoom(room);\n\t\t\tif (!b) continue;\n\t\t\tawait out.writeLine(JSON.stringify(b));\n\t\t\tcount++;\n\t\t}\n\t\tawait out.writeEnd();\n\t\tawait Monitor.logPath('battles.jsonl.progress').rename(Monitor.logPath('battles.jsonl').path);\n\t\treturn count;\n\t}\n\n\tbattlesLoading = false;\n\tasync loadBattles() {\n\t\tthis.battlesLoading = true;\n\t\tfor (const u of Users.users.values()) {\n\t\t\tu.send(\n\t\t\t\t`|pm|~|${u.getIdentity()}|/uhtml restartmsg,` +\n\t\t\t\t`
Your battles are currently being restored.
Please be patient as they load.
`\n\t\t\t);\n\t\t}\n\t\tconst startTime = Date.now();\n\t\tlet count = 0;\n\t\tlet input;\n\t\ttry {\n\t\t\tconst stream = Monitor.logPath('battles.jsonl').createReadStream();\n\t\t\tawait stream.fd;\n\t\t\tinput = stream.byLine();\n\t\t} catch {\n\t\t\treturn;\n\t\t}\n\t\tfor await (const line of input) {\n\t\t\tif (!line) continue;\n\t\t\tif (this.deserializeBattleRoom(JSON.parse(line))) count++;\n\t\t}\n\t\tfor (const u of Users.users.values()) {\n\t\t\tu.send(`|pm|~|${u.getIdentity()}|/uhtmlchange restartmsg,`);\n\t\t}\n\t\tawait Monitor.logPath('battles.jsonl').unlinkIfExists();\n\t\tMonitor.notice(`Loaded ${count} battles in ${Date.now() - startTime}ms`);\n\t\tthis.battlesLoading = false;\n\t}\n\n\trejoinGames(user: User) {\n\t\tfor (const room of Rooms.rooms.values()) {\n\t\t\tconst player = room.game && !room.game.ended && room.game.playerTable[user.id];\n\t\t\tif (!player) continue;\n\t\t\t// prevents players from being re-added to games like Scavengers after they've finished\n\t\t\tif (player.completed) continue;\n\t\t\tuser.games.add(room.roomid);\n\t\t\tplayer.name = user.name;\n\t\t\tuser.joinRoom(room.roomid);\n\t\t}\n\t}\n\n\tmodlog(entry: PartialModlogEntry, overrideID?: string) {\n\t\tvoid Rooms.Modlog.write('global', entry, overrideID);\n\t}\n\n\twriteChatRoomData() {\n\t\tFS('config/chatrooms.json').writeUpdate(() => (\n\t\t\tJSON.stringify(this.settingsList)\n\t\t\t\t.replace(/\\{\"title\":/g, '\\n{\"title\":')\n\t\t\t\t.replace(/\\]$/, '\\n]')\n\t\t), { throttle: 5000 });\n\t}\n\n\twriteNumRooms() {\n\t\tif (this.lockdown) {\n\t\t\tif (this.lastBattle === this.lastWrittenBattle) return;\n\t\t\tthis.lastWrittenBattle = this.lastBattle;\n\t\t} else {\n\t\t\t// batch writes so we don't have to write them every new battle\n\t\t\t// very probably premature optimization, considering by default we\n\t\t\t// write significantly larger log files every new battle\n\t\t\tif (this.lastBattle < this.lastWrittenBattle) return;\n\t\t\tthis.lastWrittenBattle = this.lastBattle + LAST_BATTLE_WRITE_THROTTLE;\n\t\t}\n\t\tMonitor.logPath('lastbattle.txt').writeUpdate(\n\t\t\t() => `${this.lastWrittenBattle}`\n\t\t);\n\t}\n\n\treportUserStats() {\n\t\tif (this.maxUsersDate) {\n\t\t\tvoid LoginServer.request('updateuserstats', {\n\t\t\t\tdate: this.maxUsersDate,\n\t\t\t\tusers: this.maxUsers,\n\t\t\t});\n\t\t\tthis.maxUsersDate = 0;\n\t\t}\n\t\tvoid LoginServer.request('updateuserstats', {\n\t\t\tdate: Date.now(),\n\t\t\tusers: Users.onlineCount,\n\t\t});\n\t}\n\n\tget formatListText() {\n\t\tif (this.formatList) {\n\t\t\treturn this.formatList;\n\t\t}\n\t\tthis.formatList = `|formats${Ladders.formatsListPrefix || ''}`;\n\t\tlet section = '';\n\t\tlet prevSection = '';\n\t\tlet curColumn = 1;\n\t\tfor (const format of Dex.formats.all()) {\n\t\t\tif (format.section) section = format.section;\n\t\t\tif (format.column) curColumn = format.column;\n\t\t\tif (!format.name) continue;\n\t\t\tif (!format.challengeShow && !format.searchShow && !format.tournamentShow) continue;\n\n\t\t\tif (section !== prevSection) {\n\t\t\t\tprevSection = section;\n\t\t\t\tthis.formatList += `|,${curColumn}|${section}`;\n\t\t\t}\n\t\t\tthis.formatList += `|${format.name}`;\n\t\t\tlet displayCode = 0;\n\t\t\tif (format.team) displayCode |= 1;\n\t\t\tif (format.searchShow) displayCode |= 2;\n\t\t\tif (format.challengeShow) displayCode |= 4;\n\t\t\tif (format.tournamentShow) displayCode |= 8;\n\t\t\tconst ruleTable = Dex.formats.getRuleTable(format);\n\t\t\tconst level = ruleTable.adjustLevel || ruleTable.adjustLevelDown || ruleTable.maxLevel;\n\t\t\tif (level === 50) displayCode |= 16;\n\t\t\t// 32 was previously used for Multi Battles\n\t\t\tif (format.bestOfDefault) displayCode |= 64;\n\t\t\tif (format.teraPreviewDefault) displayCode |= 128;\n\t\t\tthis.formatList += ',' + displayCode.toString(16);\n\t\t}\n\t\treturn this.formatList;\n\t}\n\tget configRankList() {\n\t\tif (Config.nocustomgrouplist) return '';\n\n\t\t// putting the resultant object in Config would enable this to be run again should config.js be reloaded.\n\t\tif (Config.rankList) {\n\t\t\treturn Config.rankList;\n\t\t}\n\t\tconst rankList = [];\n\n\t\tfor (const rank in Config.groups) {\n\t\t\tif (!Config.groups[rank] || !rank) continue;\n\n\t\t\tconst tarGroup = Config.groups[rank];\n\t\t\tconst groupType = tarGroup.id === 'bot' || (!tarGroup.mute && !tarGroup.root) ?\n\t\t\t\t'normal' : (tarGroup.root || tarGroup.declare) ? 'leadership' : 'staff';\n\n\t\t\trankList.push({\n\t\t\t\tsymbol: rank,\n\t\t\t\tname: (Config.groups[rank].name || null),\n\t\t\t\ttype: groupType }); // send the first character in the rank, incase they put a string several characters long\n\t\t}\n\n\t\tconst typeOrder = ['punishment', 'normal', 'staff', 'leadership'];\n\n\t\tUtils.sortBy(rankList, rank => -typeOrder.indexOf(rank.type));\n\n\t\t// add the punishment types at the very end.\n\t\tfor (const rank in Config.punishgroups) {\n\t\t\trankList.push({ symbol: Config.punishgroups[rank].symbol, name: Config.punishgroups[rank].name, type: 'punishment' });\n\t\t}\n\n\t\tConfig.rankList = '|customgroups|' + JSON.stringify(rankList) + '\\n';\n\t\treturn Config.rankList;\n\t}\n\n\t/**\n\t * @param filter formatfilter, elofilter, usernamefilter\n\t */\n\tgetBattles(filter: string) {\n\t\tconst rooms: GameRoom[] = [];\n\t\tconst [formatFilter, eloFilterString, usernameFilter] = filter.split(',');\n\t\tconst eloFilter = +eloFilterString;\n\t\tfor (const room of Rooms.rooms.values()) {\n\t\t\tif (!room?.active || room.settings.isPrivate) continue;\n\t\t\tif (room.type !== 'battle') continue;\n\t\t\tif (formatFilter && formatFilter !== room.format) continue;\n\t\t\tif (eloFilter && (!room.rated || room.rated < eloFilter)) continue;\n\t\t\tif (usernameFilter && room.battle) {\n\t\t\t\tconst p1userid = room.battle.p1.id;\n\t\t\t\tconst p2userid = room.battle.p2.id;\n\t\t\t\tif (!p1userid || !p2userid) continue;\n\t\t\t\tif (!p1userid.startsWith(usernameFilter) && !p2userid.startsWith(usernameFilter)) continue;\n\t\t\t}\n\t\t\trooms.push(room);\n\t\t}\n\n\t\tconst roomTable: { [roomid: string]: BattleRoomTable } = {};\n\t\tfor (let i = rooms.length - 1; i >= rooms.length - 100 && i >= 0; i--) {\n\t\t\tconst room = rooms[i];\n\t\t\tconst roomData: BattleRoomTable = {};\n\t\t\tif (room.active && room.battle) {\n\t\t\t\tif (room.battle.p1) roomData.p1 = room.battle.p1.name;\n\t\t\t\tif (room.battle.p2) roomData.p2 = room.battle.p2.name;\n\t\t\t\tif (room.tour) roomData.minElo = 'tour';\n\t\t\t\tif (room.rated) roomData.minElo = Math.floor(room.rated);\n\t\t\t}\n\t\t\tif (!roomData.p1 || !roomData.p2) continue;\n\t\t\troomTable[room.roomid] = roomData;\n\t\t}\n\t\treturn roomTable;\n\t}\n\tgetRooms(user: User) {\n\t\tconst roomsData: {\n\t\t\tchat: ChatRoomTable[],\n\t\t\tsectionTitles: string[],\n\t\t\tuserCount: number,\n\t\t\tbattleCount: number,\n\t\t} = {\n\t\t\tchat: [],\n\t\t\tsectionTitles: Object.values(RoomSections.sectionNames),\n\t\t\tuserCount: Users.onlineCount,\n\t\t\tbattleCount: this.battleCount,\n\t\t};\n\t\tfor (const room of this.chatRooms) {\n\t\t\tif (!room) continue;\n\t\t\tif (room.parent) continue;\n\t\t\tif (\n\t\t\t\troom.settings.modjoin ||\n\t\t\t\t(room.settings.isPrivate && !(['hidden', 'voice'] as any).includes(room.settings.isPrivate)) ||\n\t\t\t\t(room.settings.isPrivate === 'voice' && user.tempGroup === ' ')\n\t\t\t) continue;\n\t\t\tconst roomData: ChatRoomTable = {\n\t\t\t\ttitle: room.title,\n\t\t\t\tdesc: room.settings.desc || '',\n\t\t\t\tuserCount: room.userCount,\n\t\t\t\tsection: room.settings.section ?\n\t\t\t\t\t(RoomSections.sectionNames[room.settings.section] || room.settings.section) : undefined,\n\t\t\t\tprivacy: !room.settings.isPrivate ? undefined : room.settings.isPrivate,\n\t\t\t};\n\t\t\tconst subrooms = room.getSubRooms().map(r => r.title);\n\t\t\tif (subrooms.length) roomData.subRooms = subrooms;\n\t\t\tif (room.settings.spotlight) roomData.spotlight = room.settings.spotlight;\n\n\t\t\troomsData.chat.push(roomData);\n\t\t}\n\t\treturn roomsData;\n\t}\n\tsendAll(message: string) {\n\t\tSockets.roomBroadcast('', message);\n\t}\n\taddChatRoom(title: string) {\n\t\tconst id = toID(title) as RoomID;\n\t\tif (['battles', 'rooms', 'ladder', 'teambuilder', 'home', 'all', 'public'].includes(id)) {\n\t\t\treturn false;\n\t\t}\n\t\tif (Rooms.rooms.has(id)) return false;\n\n\t\tconst settings = {\n\t\t\ttitle,\n\t\t\tauth: {},\n\t\t\tcreationTime: Date.now(),\n\t\t};\n\t\tconst room = Rooms.createChatRoom(id, title, settings);\n\t\tif (id === 'lobby') Rooms.lobby = room;\n\t\tthis.settingsList.push(settings);\n\t\tthis.chatRooms.push(room);\n\t\tthis.writeChatRoomData();\n\t\treturn true;\n\t}\n\n\tprepBattleRoom(format: string) {\n\t\t// console.log('BATTLE START BETWEEN: ' + p1.id + ' ' + p2.id);\n\t\tconst roomPrefix = `battle-${toID(Dex.formats.get(format).name)}-`;\n\t\tlet battleNum = this.lastBattle;\n\t\tlet roomid: RoomID;\n\t\tdo {\n\t\t\troomid = `${roomPrefix}${++battleNum}` as RoomID;\n\t\t} while (Rooms.rooms.has(roomid));\n\n\t\tthis.lastBattle = battleNum;\n\t\tthis.writeNumRooms();\n\t\treturn roomid;\n\t}\n\n\tonCreateBattleRoom(players: User[], room: GameRoom, options: AnyObject) {\n\t\tfor (const player of players) {\n\t\t\tif (player.statusType === 'idle') {\n\t\t\t\tplayer.setStatusType('online');\n\t\t\t}\n\t\t}\n\t\tif (Config.reportbattles) {\n\t\t\tif (typeof Config.reportbattles === 'string') {\n\t\t\t\tConfig.reportbattles = [Config.reportbattles];\n\t\t\t} else if (Config.reportbattles === true) {\n\t\t\t\tConfig.reportbattles = ['lobby'];\n\t\t\t}\n\t\t\tfor (const roomid of Config.reportbattles) {\n\t\t\t\tconst reportRoom = Rooms.get(roomid);\n\t\t\t\tif (reportRoom) {\n\t\t\t\t\tconst reportPlayers = players.map(p => p.getIdentity()).join('|');\n\t\t\t\t\treportRoom\n\t\t\t\t\t\t.add(`|b|${room.roomid}|${reportPlayers}`)\n\t\t\t\t\t\t.update();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (Config.logladderip && options.rated) {\n\t\t\tconst ladderIpLogString = players.map(p => `${p.id}: ${p.latestIp}\\n`).join('');\n\t\t\tvoid this.ladderIpLog.write(ladderIpLogString);\n\t\t}\n\t\tfor (const player of players) {\n\t\t\tChat.runHandlers('onBattleStart', player, room);\n\t\t}\n\t}\n\n\tderegisterChatRoom(id: string) {\n\t\tid = toID(id);\n\t\tconst room = Rooms.get(id);\n\t\tif (!room) return false; // room doesn't exist\n\t\tif (!room.persist) return false; // room isn't registered\n\t\t// deregister from global settings\n\t\t// looping from the end is a pretty trivial optimization, but the\n\t\t// assumption is that more recently added rooms are more likely to\n\t\t// be deleted\n\t\tfor (let i = this.settingsList.length - 1; i >= 0; i--) {\n\t\t\tif (id === toID(this.settingsList[i].title)) {\n\t\t\t\tthis.settingsList.splice(i, 1);\n\t\t\t\tthis.writeChatRoomData();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\troom.persist = false;\n\t\treturn true;\n\t}\n\tdelistChatRoom(id: RoomID) {\n\t\tid = toID(id) as RoomID;\n\t\tif (!Rooms.rooms.has(id)) return false; // room doesn't exist\n\t\tfor (let i = this.chatRooms.length - 1; i >= 0; i--) {\n\t\t\tif (id === this.chatRooms[i].roomid) {\n\t\t\t\tthis.chatRooms.splice(i, 1);\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t}\n\tremoveChatRoom(id: string) {\n\t\tid = toID(id);\n\t\tconst room = Rooms.get(id);\n\t\tif (!room) return false; // room doesn't exist\n\t\troom.destroy();\n\t\treturn true;\n\t}\n\tautojoinRooms(user: User, connection: Connection) {\n\t\t// we only autojoin regular rooms if the client requests it with /autojoin\n\t\t// note that this restriction doesn't apply to modjoined autojoin rooms\n\t\tlet includesLobby = false;\n\t\tfor (const roomName of this.autojoinList) {\n\t\t\tuser.joinRoom(roomName, connection);\n\t\t\tif (roomName === 'lobby') includesLobby = true;\n\t\t}\n\t\tif (!includesLobby && Config.serverid !== 'showdown') user.send(`>lobby\\n|deinit`);\n\t}\n\tcheckAutojoin(user: User, connection?: Connection) {\n\t\tif (!user.named) return;\n\t\tfor (let [i, roomid] of this.modjoinedAutojoinList.entries()) {\n\t\t\tconst room = Rooms.get(roomid);\n\t\t\tif (!room) {\n\t\t\t\tthis.modjoinedAutojoinList.splice(i, 1);\n\t\t\t\ti--;\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (room.checkModjoin(user)) {\n\t\t\t\tuser.joinRoom(room.roomid, connection);\n\t\t\t}\n\t\t}\n\t\tfor (const conn of user.connections) {\n\t\t\tif (conn.autojoins) {\n\t\t\t\tconst autojoins = conn.autojoins.split(',') as RoomID[];\n\t\t\t\tfor (const roomName of autojoins) {\n\t\t\t\t\tvoid user.tryJoinRoom(roomName, conn);\n\t\t\t\t}\n\t\t\t\tconn.autojoins = '';\n\t\t\t}\n\t\t}\n\t}\n\thandleConnect(user: User, connection: Connection) {\n\t\tconnection.send(user.getUpdateuserText() + '\\n' + this.configRankList + this.formatListText);\n\t\tif (Users.users.size > this.maxUsers) {\n\t\t\tthis.maxUsers = Users.users.size;\n\t\t\tthis.maxUsersDate = Date.now();\n\t\t}\n\t}\n\tstartLockdown(err: Error | null = null, slow = false) {\n\t\tif (this.lockdown && err) return;\n\t\tconst devRoom = Rooms.get('development');\n\t\tconst stack = (err ? Utils.escapeHTML(err.stack!).split(`\\n`).slice(0, 2).join(`
`) : ``);\n\t\tfor (const [id, curRoom] of Rooms.rooms) {\n\t\t\tif (err) {\n\t\t\t\tif (id === 'staff' || id === 'development' || (!devRoom && id === 'lobby')) {\n\t\t\t\t\tcurRoom.addRaw(`
The server needs to restart because of a crash: ${stack}
Please restart the server.
`);\n\t\t\t\t\tcurRoom.addRaw(`
You will not be able to start new battles until the server restarts.
`);\n\t\t\t\t\tcurRoom.update();\n\t\t\t\t} else {\n\t\t\t\t\tcurRoom.addRaw(`
The server needs to restart because of a crash.
No new battles can be started until the server is done restarting.
`).update();\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcurRoom.addRaw(`
The server is restarting soon.
Please finish your battles quickly. No new battles can be started until the server resets in a few minutes.
`).update();\n\t\t\t}\n\t\t\tconst game = curRoom.game;\n\t\t\t// @ts-expect-error TODO: revisit when game.timer is standardized\n\t\t\tif (!slow && game?.timer && typeof game.timer.start === 'function' && !game.ended) {\n\t\t\t\t// @ts-expect-error see above\n\t\t\t\tgame.timer.start();\n\t\t\t\tif (curRoom.settings.modchat !== '+') {\n\t\t\t\t\tcurRoom.settings.modchat = '+';\n\t\t\t\t\tcurRoom.addRaw(`
Moderated chat was set to +!
Only users of rank + and higher can talk.
`).update();\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tfor (const user of Users.users.values()) {\n\t\t\tuser.send(`|pm|~|${user.tempGroup}${user.name}|/raw
The server is restarting soon.
Please finish your battles quickly. No new battles can be started until the server resets in a few minutes.
`);\n\t\t}\n\n\t\tthis.lockdown = true;\n\t\tthis.writeNumRooms();\n\t\tthis.lastReportedCrash = Date.now();\n\t}\n\tautomaticKillRequest() {\n\t\tconst notifyPlaces: RoomID[] = ['development', 'staff', 'upperstaff'];\n\t\tif (Config.autolockdown === undefined) Config.autolockdown = true; // on by default\n\n\t\tif (Config.autolockdown && Rooms.global.lockdown === true && Rooms.global.battleCount === 0) {\n\t\t\t// The server is in lockdown, the final battle has finished, and the option is set\n\t\t\t// so we will now automatically kill the server here if it is not updating.\n\t\t\tif (Monitor.updateServerLock) {\n\t\t\t\tthis.notifyRooms(\n\t\t\t\t\tnotifyPlaces,\n\t\t\t\t\t`|html|
Automatic server lockdown kill canceled.

The server tried to automatically kill itself upon the final battle finishing, but the server was updating while trying to kill itself.
`\n\t\t\t\t);\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t\t// final warning\n\t\t\tthis.notifyRooms(\n\t\t\t\tnotifyPlaces,\n\t\t\t\t`|html|
The server is about to automatically kill itself in 10 seconds.
`\n\t\t\t);\n\n\t\t\t// kill server in 10 seconds if it's still set to\n\t\t\tsetTimeout(() => {\n\t\t\t\tif (Config.autolockdown && Rooms.global.lockdown === true) {\n\t\t\t\t\t// finally kill the server\n\t\t\t\t\tprocess.exit();\n\t\t\t\t} else {\n\t\t\t\t\tthis.notifyRooms(\n\t\t\t\t\t\tnotifyPlaces,\n\t\t\t\t\t\t`|html|
Automatic server lockdown kill canceled.

In the last final seconds, the automatic lockdown was manually disabled.
`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}, 10 * 1000);\n\t\t}\n\t}\n\tnotifyRooms(rooms: RoomID[], message: string) {\n\t\tif (!rooms || !message) return;\n\t\tfor (const roomid of rooms) {\n\t\t\tconst curRoom = Rooms.get(roomid);\n\t\t\tif (curRoom) curRoom.add(message).update();\n\t\t}\n\t}\n\treportCrash(err: Error | string, crasher = \"The server\") {\n\t\tconst time = Date.now();\n\t\tif (time - this.lastReportedCrash < CRASH_REPORT_THROTTLE) {\n\t\t\treturn;\n\t\t}\n\t\tthis.lastReportedCrash = time;\n\n\t\tconst stack = typeof err === 'string' ? err : err?.stack || err?.message || err?.name || '';\n\t\tconst [stackFirst, stackRest] = Utils.splitFirst(Utils.escapeHTML(stack), `
`);\n\t\tlet fullStack = `${crasher} crashed: ` + stackFirst;\n\t\tif (stackRest) fullStack = `
${fullStack}${stackRest}
`;\n\n\t\tlet crashMessage = `|html|
${fullStack}
`;\n\t\tlet privateCrashMessage = null;\n\n\t\tconst upperStaffRoom = Rooms.get('upperstaff');\n\n\t\tlet hasPrivateTerm = stack.includes('private');\n\t\tfor (const term of (Config.privatecrashterms || [])) {\n\t\t\tif (typeof term === 'string' ? stack.includes(term) : term.test(stack)) {\n\t\t\t\thasPrivateTerm = true;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\n\t\tif (hasPrivateTerm) {\n\t\t\tif (upperStaffRoom) {\n\t\t\t\tprivateCrashMessage = crashMessage;\n\t\t\t\tcrashMessage = `|html|
${crasher} crashed in private code Read more
`;\n\t\t\t} else {\n\t\t\t\tcrashMessage = `|html|
${crasher} crashed in private code
`;\n\t\t\t}\n\t\t}\n\t\tconst devRoom = Rooms.get('development');\n\t\tif (devRoom) {\n\t\t\tdevRoom.add(crashMessage).update();\n\t\t} else {\n\t\t\tRooms.lobby?.add(crashMessage).update();\n\t\t\tRooms.get('staff')?.add(crashMessage).update();\n\t\t}\n\t\tif (privateCrashMessage) {\n\t\t\tupperStaffRoom!.add(privateCrashMessage).update();\n\t\t}\n\t}\n\t/**\n\t * Destroys personal rooms of a (punished) user\n\t * Returns a list of the user's remaining public auth\n\t */\n\tdestroyPersonalRooms(userid: ID) {\n\t\tconst roomauth = [];\n\t\tfor (const [id, curRoom] of Rooms.rooms) {\n\t\t\tif (curRoom.settings.isPersonal && curRoom.auth.get(userid) === Users.HOST_SYMBOL) {\n\t\t\t\tcurRoom.destroy();\n\t\t\t} else {\n\t\t\t\tif (curRoom.settings.isPrivate || curRoom.battle || !curRoom.persist) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tif (curRoom.auth.has(userid)) {\n\t\t\t\t\tlet oldGroup = curRoom.auth.get(userid) as string;\n\t\t\t\t\tif (oldGroup === ' ') oldGroup = 'whitelist in ';\n\t\t\t\t\troomauth.push(`${oldGroup}${id}`);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn roomauth;\n\t}\n}\n\nexport class ChatRoom extends BasicRoom {\n\t// This is not actually used, this is just a fake class to keep\n\t// TypeScript happy\n\toverride battle = null;\n\toverride active = false as const;\n\toverride type = 'chat' as const;\n}\n\nexport class GameRoom extends BasicRoom {\n\tdeclare readonly type: 'battle';\n\treadonly format: string;\n\tp1: User | null;\n\tp2: User | null;\n\tp3: User | null;\n\tp4: User | null;\n\t/**\n\t * The lower player's rating, for searching purposes.\n\t * 0 for unrated battles. 1 for unknown ratings.\n\t */\n\trated: number;\n\tdeclare battle: RoomBattle | null;\n\tdeclare bestOf: BestOfGame | null;\n\tdeclare game: RoomGame;\n\tmodchatUser: string;\n\tconstructor(roomid: RoomID, title: string, options: Partial) {\n\t\toptions.noLogTimes = true;\n\t\toptions.noAutoTruncate = true;\n\t\toptions.isMultichannel = true;\n\t\tsuper(roomid, title, options);\n\t\tthis.reportJoins = !!Config.reportbattlejoins;\n\t\tthis.settings.modchat = (Config.battlemodchat || null);\n\n\t\tthis.type = 'battle';\n\n\t\tthis.format = options.format || '';\n\t\t// console.log(\"NEW BATTLE\");\n\n\t\tthis.tour = options.tour || null;\n\t\tthis.setParent((options as any).parent || this.tour?.room || null);\n\n\t\tthis.p1 = options.players?.[0]?.user || null;\n\t\tthis.p2 = options.players?.[1]?.user || null;\n\t\tthis.p3 = options.players?.[2]?.user || null;\n\t\tthis.p4 = options.players?.[3]?.user || null;\n\n\t\tthis.rated = options.rated === true ? 1 : options.rated || 0;\n\n\t\tthis.battle = null;\n\t\tthis.bestOf = null;\n\t\tthis.game = null!;\n\n\t\tthis.modchatUser = '';\n\n\t\tthis.active = false;\n\t}\n\t/**\n\t * - logNum = 0 : spectator log (no exact HP)\n\t * - logNum = 1, 2, 3, 4 : player log (exact HP for that player)\n\t * - logNum = -1 : debug log (exact HP for all players)\n\t */\n\tgetLog(channel: -1 | 0 | 1 | 2 | 3 | 4 = 0) {\n\t\treturn this.log.getScrollback(channel);\n\t}\n\tgetLogForUser(user: User) {\n\t\tif (!(user.id in this.game.playerTable)) return this.getLog();\n\t\treturn this.getLog(this.game.playerTable[user.id].num as 0);\n\t}\n\tupdate(excludeUser: User | null = null) {\n\t\tif (!this.log.broadcastBuffer.length) return;\n\n\t\tif (this.userCount) {\n\t\t\tSockets.channelBroadcast(this.roomid, `>${this.roomid}\\n${this.log.broadcastBuffer.join('\\n')}`);\n\t\t}\n\t\tthis.log.broadcastBuffer = [];\n\n\t\tthis.pokeExpireTimer();\n\t}\n\tpokeExpireTimer() {\n\t\t// empty rooms time out after ten minutes\n\t\tif (!this.userCount) {\n\t\t\tif (this.expireTimer) clearTimeout(this.expireTimer);\n\t\t\tthis.expireTimer = setTimeout(() => this.expire(), TIMEOUT_EMPTY_DEALLOCATE);\n\t\t} else {\n\t\t\tif (this.expireTimer) clearTimeout(this.expireTimer);\n\t\t\tthis.expireTimer = setTimeout(() => this.expire(), TIMEOUT_INACTIVE_DEALLOCATE);\n\t\t}\n\t}\n\trequestModchat(user: User | null) {\n\t\tif (!user) {\n\t\t\tthis.modchatUser = '';\n\t\t} else if (!this.modchatUser || this.modchatUser === user.id || this.auth.get(user.id) !== Users.PLAYER_SYMBOL) {\n\t\t\tthis.modchatUser = user.id;\n\t\t} else {\n\t\t\treturn \"Modchat can only be changed by the user who turned it on, or by staff\";\n\t\t}\n\t}\n\tonConnect(user: User, connection: Connection) {\n\t\tthis.sendUser(connection, '|init|battle\\n|title|' + this.title + '\\n' + this.getLogForUser(user));\n\t\tthis.game?.onConnect?.(user, connection);\n\t}\n\tonJoin(user: User, connection: Connection) {\n\t\tif (!user) return false; // ???\n\t\tif (this.users[user.id]) return false;\n\n\t\tChat.runHandlers('onBeforeRoomJoin', this, user, connection);\n\t\tif (user.named) {\n\t\t\tthis.reportJoin('j', user.getIdentityWithStatus(this), user);\n\t\t}\n\n\t\tthis.users[user.id] = user;\n\t\tthis.userCount++;\n\t\tthis.checkAutoModchat(user);\n\n\t\tthis.minorActivity?.onConnect?.(user, connection);\n\t\tthis.game?.onJoin?.(user, connection);\n\t\tChat.runHandlers('onRoomJoin', this, user, connection);\n\t\treturn true;\n\t}\n\t/**\n\t * Sends this room's replay to the connection to be uploaded to the replay\n\t * server. To be clear, the replay goes:\n\t *\n\t * PS server -> user -> loginserver\n\t *\n\t * NOT: PS server -> loginserver\n\t *\n\t * That's why this function requires a connection. For details, see the top\n\t * comment inside this function.\n\t */\n\tasync uploadReplay(user?: User, connection?: Connection, options?: 'forpunishment' | 'silent' | 'auto') {\n\t\t// The reason we don't upload directly to the loginserver, unlike every\n\t\t// other interaction with the loginserver, is because it takes so much\n\t\t// bandwidth that it can get identified as a DoS attack by PHP, Apache, or\n\t\t// Cloudflare, and blocked.\n\n\t\t// While I'm sure this is configurable, it's a huge pain, and getting it\n\t\t// wrong, especially while migrating infrastructure, leads to everything\n\t\t// being unusable and panic while we figure out how to unblock our servers\n\t\t// from each other. It's just easier to \"spread out\" the bandwidth.\n\n\t\t// TODO: My ideal long-term fix would be to just have a database (probably\n\t\t// Postgres) shared between client and server, acting as both the server's\n\t\t// battle logs as well as the client's replay database, which both client\n\t\t// and server have write access to.\n\n\t\tconst battle = this.battle;\n\t\tif (!battle) return;\n\n\t\t// retrieve spectator log (0) if there are privacy concerns\n\t\tconst format = Dex.formats.get(this.format, true);\n\n\t\t// custom games always show full details\n\t\t// random-team battles show full details if the battle is ended\n\t\t// otherwise, don't show full details\n\t\tlet hideDetails = !format.id.includes('customgame');\n\t\tif (format.team && battle.ended) hideDetails = false;\n\n\t\tconst log = this.getLog(hideDetails ? 0 : -1);\n\t\tlet rating: number | undefined;\n\t\tif (battle.ended && this.rated) rating = this.rated;\n\t\tlet { id, password } = this.getReplayData();\n\t\tconst silent = options === 'forpunishment' || options === 'silent' || options === 'auto';\n\t\tif (silent) connection = undefined;\n\t\tconst isPrivate = this.settings.isPrivate || this.hideReplay;\n\t\tconst hidden = options === 'auto' ? 10 :\n\t\t\toptions === 'forpunishment' || (this as any).unlistReplay ? 2 :\n\t\t\tisPrivate ? 1 :\n\t\t\t0;\n\t\tif (isPrivate && hidden === 10) {\n\t\t\tpassword = Replays.generatePassword();\n\t\t}\n\t\tif (battle.replaySaved !== true && hidden === 10) {\n\t\t\tbattle.replaySaved = 'auto';\n\t\t} else {\n\t\t\tbattle.replaySaved = true;\n\t\t}\n\n\t\t// If we have a direct connetion to a Replays database, just upload the replay\n\t\t// directly.\n\n\t\tif (Replays.db) {\n\t\t\tconst idWithServer = Config.serverid === 'showdown' ? id : `${Config.serverid}-${id}`;\n\t\t\ttry {\n\t\t\t\tconst fullid = await Replays.add({\n\t\t\t\t\tid: idWithServer,\n\t\t\t\t\tlog,\n\t\t\t\t\tplayers: battle.players.map(p => p.name),\n\t\t\t\t\tformat: format.name,\n\t\t\t\t\trating: rating || null,\n\t\t\t\t\tprivate: hidden,\n\t\t\t\t\tpassword,\n\t\t\t\t\tinputlog: battle.inputLog?.join('\\n') || null,\n\t\t\t\t\tuploadtime: Math.trunc(Date.now() / 1000),\n\t\t\t\t});\n\t\t\t\tconst url = `https://${Config.routes.replays}/${fullid}`;\n\t\t\t\tconnection?.popup(\n\t\t\t\t\t`|html|

Your replay has been uploaded! It's available at:

` +\n\t\t\t\t\t`${url} ` +\n\t\t\t\t\t`Copy`\n\t\t\t\t);\n\t\t\t} catch (e) {\n\t\t\t\tconnection?.popup(`Your replay could not be saved: ${e}`);\n\t\t\t\tthrow e;\n\t\t\t}\n\t\t\treturn;\n\t\t}\n\n\t\t// Otherwise, (we're probably a side server), upload the replay through LoginServer\n\n\t\tconst [result] = await LoginServer.request('addreplay', {\n\t\t\tid,\n\t\t\tlog,\n\t\t\tplayers: battle.players.map(p => p.name).join(','),\n\t\t\tformat: format.name,\n\t\t\trating, // will probably do nothing\n\t\t\thidden: hidden === 0 ? '' : hidden,\n\t\t\tinputlog: battle.inputLog?.join('\\n') || undefined,\n\t\t\tpassword,\n\t\t});\n\t\tif (result?.errorip) {\n\t\t\tconnection?.popup(`This server's request IP ${result.errorip} is not a registered server.`);\n\t\t\treturn;\n\t\t}\n\n\t\tconst fullid = result?.replayid;\n\t\tconst url = `https://${Config.routes.replays}/${fullid}`;\n\t\tconnection?.popup(\n\t\t\t`|html|

Your replay has been uploaded! It's available at:

` +\n\t\t\t`${url} ` +\n\t\t\t`Copy`\n\t\t);\n\t}\n\n\tgetReplayData() {\n\t\tif (!this.roomid.endsWith('pw')) return { id: this.roomid.slice(7), password: null };\n\t\tconst end = this.roomid.length - 2;\n\t\tconst lastHyphen = this.roomid.lastIndexOf('-', end);\n\t\treturn { id: this.roomid.slice(7, lastHyphen), password: this.roomid.slice(lastHyphen + 1, end) };\n\t}\n}\n\nfunction getRoom(roomid?: string | BasicRoom) {\n\tif (typeof roomid === 'string') {\n\t\t// Accounts for private battles that were made public\n\t\tif ((roomid.startsWith('battle-') || roomid.startsWith('game-bestof')) && roomid.endsWith('pw')) {\n\t\t\tconst room = Rooms.rooms.get(roomid.slice(0, roomid.lastIndexOf('-')) as RoomID);\n\t\t\tif (room) return room;\n\t\t}\n\t\treturn Rooms.rooms.get(roomid as RoomID);\n\t}\n\treturn roomid as Room;\n}\n\nexport const Rooms = {\n\tModlog: mainModlog,\n\t/**\n\t * The main roomid:Room table. Please do not hold a reference to a\n\t * room long-term; just store the roomid and grab it from here (with\n\t * the Rooms.get(roomid) accessor) when necessary.\n\t */\n\trooms: new Map(),\n\taliases: new Map(),\n\n\tget: getRoom,\n\tsearch(name: string): Room | undefined {\n\t\treturn getRoom(name) || getRoom(toID(name)) || getRoom(Rooms.aliases.get(toID(name)));\n\t},\n\n\tcreateGameRoom(roomid: RoomID, title: string, options: Partial) {\n\t\tif (Rooms.rooms.has(roomid)) throw new Error(`Room ${roomid} already exists`);\n\t\tMonitor.debug(\"NEW BATTLE ROOM: \" + roomid);\n\t\tconst room = new GameRoom(roomid, title, options);\n\t\tRooms.rooms.set(roomid, room);\n\t\treturn room;\n\t},\n\tcreateChatRoom(roomid: RoomID, title: string, options: Partial) {\n\t\tif (Rooms.rooms.has(roomid)) throw new Error(`Room ${roomid} already exists`);\n\t\tconst room: ChatRoom = new (BasicRoom as any)(roomid, title, options);\n\t\tRooms.rooms.set(roomid, room);\n\t\treturn room;\n\t},\n\t/**\n\t * Can return null during lockdown, so make sure to handle that case.\n\t * No need for UI; this function sends popups to users.\n\t */\n\tcreateBattle(options: RoomBattleOptions & Partial) {\n\t\tconst players = options.players.map(player => player.user);\n\t\tconst format = Dex.formats.get(options.format);\n\t\tif (players.length > format.playerCount) {\n\t\t\tthrow new Error(`${players.length} players were provided, but the format is a ${format.playerCount}-player format.`);\n\t\t}\n\t\tif (new Set(players).size < players.length) {\n\t\t\tthrow new Error(`Players can't battle themselves`);\n\t\t}\n\n\t\tfor (const user of players) {\n\t\t\tLadders.cancelSearches(user);\n\t\t}\n\n\t\tconst isBestOf = Dex.formats.getRuleTable(format).valueRules.get('bestof');\n\n\t\tif (Rooms.global.lockdown === 'pre' && isBestOf && !options.isBestOfSubBattle) {\n\t\t\tfor (const user of players) {\n\t\t\t\tuser.popup(`The server will be restarting soon. Best-of-${isBestOf} battles cannot be started at this time.`);\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\t// gotta allow new bo3 child battles to start\n\t\tif (Rooms.global.lockdown === true && !options.isBestOfSubBattle) {\n\t\t\tfor (const user of players) {\n\t\t\t\tuser.popup(\"The server is restarting. Battles will be available again in a few minutes.\");\n\t\t\t}\n\t\t\treturn null;\n\t\t}\n\n\t\tconst p1Special = players.length ? players[0].battleSettings.special : undefined;\n\t\tlet mismatch = `\"${p1Special}\"`;\n\t\tfor (const user of players) {\n\t\t\tif (user.battleSettings.special !== p1Special) {\n\t\t\t\tmismatch += ` vs. \"${user.battleSettings.special}\"`;\n\t\t\t}\n\t\t\tuser.battleSettings.special = undefined;\n\t\t}\n\n\t\tif (mismatch !== `\"${p1Special}\"`) {\n\t\t\tfor (const user of players) {\n\t\t\t\tuser.popup(`Your special battle settings don't match: ${mismatch}`);\n\t\t\t}\n\t\t\treturn null;\n\t\t} else if (p1Special) {\n\t\t\toptions.ratedMessage = p1Special;\n\t\t}\n\n\t\t// options.rated is a number representing the lowest player rating, for searching purposes\n\t\t// options.rated < 0 or falsy means \"unrated\", and will be converted to 0 here\n\t\t// options.rated === true is converted to 1 (used in tests sometimes)\n\t\toptions.rated = Math.max(+options.rated! || 0, 0);\n\t\tconst p1 = players[0];\n\t\tconst p2 = players[1];\n\t\tconst p1name = p1 ? p1.name : \"Player 1\";\n\t\tconst p2name = p2 ? p2.name : \"Player 2\";\n\t\tlet roomTitle;\n\t\tlet roomid = options.roomid;\n\t\tif (format.gameType === 'multi') {\n\t\t\troomTitle = `Team ${p1name} vs. Team ${p2name}`;\n\t\t} else if (format.gameType === 'freeforall') {\n\t\t\t// p1 vs. p2 vs. p3 vs. p4 is too long of a title\n\t\t\troomTitle = `${p1name} and friends`;\n\t\t} else if (isBestOf && !options.isBestOfSubBattle) {\n\t\t\troomTitle = `${p1name} vs. ${p2name}`;\n\t\t\troomid ||= `game-bestof${isBestOf}-${format.id}-${++Rooms.global.lastBattle}` as RoomID;\n\t\t} else if (options.title) {\n\t\t\troomTitle = options.title;\n\t\t} else {\n\t\t\troomTitle = `${p1name} vs. ${p2name}`;\n\t\t}\n\t\troomid ||= Rooms.global.prepBattleRoom(options.format);\n\t\toptions.isPersonal = true;\n\t\tconst room = Rooms.createGameRoom(roomid, roomTitle, options);\n\t\tlet game: RoomBattle | BestOfGame;\n\t\tif (options.isBestOfSubBattle || !isBestOf) {\n\t\t\tgame = new RoomBattle(room, options);\n\t\t} else {\n\t\t\tgame = new BestOfGame(room, options);\n\t\t}\n\t\troom.game = game;\n\t\tif (options.isBestOfSubBattle && room.parent) {\n\t\t\troom.setPrivate(room.parent.settings.isPrivate || false);\n\t\t} else {\n\t\t\tgame.checkPrivacySettings(options);\n\t\t}\n\n\t\tfor (const p of players) {\n\t\t\tif (p) {\n\t\t\t\tp.joinRoom(room);\n\t\t\t\tMonitor.countBattle(p.latestIp, p.name);\n\t\t\t}\n\t\t}\n\n\t\treturn room;\n\t},\n\n\tglobal: null! as GlobalRoomState,\n\tlobby: null as ChatRoom | null,\n\n\tBasicRoom,\n\tGlobalRoomState,\n\tGameRoom,\n\tChatRoom: BasicRoom as typeof ChatRoom,\n\n\tRoomGame,\n\tSimpleRoomGame,\n\tRoomGamePlayer,\n\n\tMinorActivity,\n\n\tRETRY_AFTER_LOGIN,\n\n\tRoomlogs,\n\n\tRoomBattle,\n\tBestOfGame,\n\tRoomBattlePlayer,\n\tRoomBattleTimer,\n\tPM: RoomBattlePM,\n\n\tReplays,\n};\n"], "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA8BA,iBAAmC;AACnC,2BAA+C;AAI/C,yBAEO;AACP,gCAA2B;AAC3B,uBAAyD;AACzD,iCAAsD;AACtD,sBAAuC;AACvC,yBAAyB;AACzB,oBAAoD;AACpD,qBAAwB;AACxB,aAAwB;AA7CxB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBA,MAAM,WAAW,uCAAuC,MAAM,EAAE;AAEhE,MAAM,2BAA2B,KAAK,KAAK;AAC3C,MAAM,8BAA8B,KAAK,KAAK;AAC9C,MAAM,6BAA6B,KAAK,KAAK;AAC7C,MAAM,yBAAyB;AAE/B,MAAM,wBAAwB,KAAK,KAAK;AAExC,MAAM,6BAA6B;AAEnC,MAAM,oBAAoB;AAgInB,MAAe,UAAU;AAAA,EAkF/B,YAAY,QAAgB,OAAgB,UAAiC,CAAC,GAAG;AAChF,SAAK,QAAQ,uBAAO,OAAO,IAAI;AAC/B,SAAK,OAAO;AACZ,SAAK,YAAY,CAAC;AAElB,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,UAAU;AACf,SAAK,OAAO;AAEZ,SAAK,SAAS;AACd,SAAK,QAAS,SAAS;AACvB,SAAK,SAAS;AAEd,SAAK,YAAY;AAEjB,SAAK,OAAO;AACZ,SAAK,SAAS;AAEd,SAAK,YAAY;AAEjB,SAAK,aAAa;AAClB,SAAK,gBAAgB;AACrB,SAAK,oBAAoB;AAIzB,SAAK,WAAW;AAAA,MACf,OAAO,KAAK;AAAA,MACZ,MAAM,uBAAO,OAAO,IAAI;AAAA,MACxB,cAAc,KAAK,IAAI;AAAA,IACxB;AACA,SAAK,UAAU;AACf,SAAK,aAAa;AAClB,SAAK,WAAW;AAChB,SAAK,WAAW;AAChB,SAAK,kBAAkB,CAAC;AACxB,SAAK,OAAO,IAAI,4BAAS,IAAI;AAE7B,SAAK,cAAc;AACnB,SAAK,aAAa;AAClB,SAAK,sBAAsB;AAE3B,YAAQ,QAAQ,KAAK;AACrB,QAAI,QAAQ;AAAQ,cAAQ,iBAAiB;AAC7C,SAAK,cAAc,CAAC,EAAE,OAAO,eAAe,QAAQ;AACpD,SAAK,aAAa,QAAQ,aAAa,IAAI,OAAO,qBAAqB;AACvE,QAAI,CAAC,QAAQ;AAAM,cAAQ,OAAO,CAAC;AAEnC,SAAK,MAAM,yBAAS,OAAO,MAAM,OAAO;AAExC,SAAK,eAAe;AAEpB,SAAK,WAAW;AAChB,QAAI,CAAC,KAAK,SAAS;AAAc,WAAK,SAAS,eAAe,KAAK,IAAI;AACvE,SAAK,KAAK,KAAK;AAEf,QAAI,CAAC,QAAQ;AAAY,WAAK,UAAU;AAExC,SAAK,gBAAgB;AACrB,SAAK,qBAAqB;AAC1B,QAAI,QAAQ,UAAU;AACrB,WAAK,UAAU,MAAM,IAAI,QAAQ,QAAQ,KAAK,IAAI;AAAA,IACnD;AAEA,SAAK,WAAW;AAEhB,SAAK,SAAS;AACd,SAAK,YAAY;AACjB,SAAK,eAAe;AAEpB,SAAK,uBAAuB;AAC5B,SAAK,cAAc;AACnB,QAAI,OAAO,SAAS;AACnB,WAAK,QAAQ,mBAAmB,KAAK,MAAM;AAC3C,UAAI,OAAO,cAAc;AACxB,aAAK,uBAAuB,YAAY,MAAM,KAAK,aAAa,GAAG,OAAO,YAAY;AAAA,MACvF;AAAA,IACD;AAEA,SAAK,WAAW;AAChB,QAAI,KAAK,YAAY;AACpB,WAAK,WAAW,KAAK,YAAY;AAAA,IAClC;AACA,SAAK,mBAAmB;AACxB,SAAK,eAAe;AACpB,SAAK,qBAAqB,oBAAI,IAAI;AAClC,SAAK,OAAO;AACZ,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,cAAc,KAAK,OAAO,KAAK,MAAM;AAAA,EAC3C;AAAA,EAEA,WAAW;AACV,WAAO,KAAK;AAAA,EACb;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,KAAK,SAAiB;AACrB,QAAI,KAAK,WAAW;AAAS,gBAAU,MAAM,KAAK,SAAS,OAAO;AAClE,QAAI,KAAK;AAAW,cAAQ,cAAc,KAAK,QAAQ,OAAO;AAAA,EAC/D;AAAA,EACA,SAAS,MAAc;AACtB,SAAK,gBAAgB,MAAM,GAAG;AAAA,EAC/B;AAAA,EACA,gBAAgB,MAAc,UAAuB,KAAK;AACzD,QAAI,KAAK,SAAS,WAAW;AAC5B,UAAI,CAAC,KAAK;AAAK,cAAM,IAAI,MAAM,cAAc,KAAK,mBAAmB;AACrE,WAAK,IAAI,IAAI,IAAI;AACjB;AAAA,IACD;AAEA,eAAW,KAAK,KAAK,OAAO;AAC3B,YAAM,OAAO,KAAK,MAAM,CAAC;AAEzB,UAAI,KAAK,WAAW,KAAK,KAAK,QAAQ,MAAM,OAAO,GAAG;AACrD,aAAK,OAAO,MAAM,IAAI;AAAA,MACvB;AAAA,IACD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA,EAIA,SAAS,MAAyB,SAAiB;AAClD,SAAK,OAAO,MAAM,OAAO;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,IAAI,SAAiB;AACpB,SAAK,IAAI,IAAI,OAAO;AACpB,WAAO;AAAA,EACR;AAAA,EACA,QAAQ,SAAiB;AACxB,SAAK,IAAI,QAAQ,OAAO;AACxB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO,OAA2B;AACjC,UAAM,WAAW,KAAK,OAAO,GAAG,KAAK,sBAAsB,KAAK,KAAK,WAAW;AAChF,SAAK,IAAI,OAAO,OAAO,QAAQ;AAC/B,WAAO;AAAA,EACR;AAAA,EACA,YAAY,MAAc,SAAiB;AAC1C,SAAK,IAAI,YAAY,MAAM,OAAO;AAAA,EACnC;AAAA,EACA,sBAAsB,MAAY,MAAc,SAAiB;AAChE,SAAK,IAAI,sBAAsB,MAAM,MAAM,OAAO;AAAA,EACnD;AAAA,EACA,SAAS,SAAe,YAAY,GAAG,kBAA4B;AAClE,UAAM,UAAU,KAAK,IAAI,UAAU,SAAS,SAAS;AACrD,eAAW,UAAU,SAAS;AAC7B,WAAK,KAAK,cAAc,mBAAmB,WAAW,UAAU,UAAU,WAAW;AAAA,IACtF;AACA,SAAK,OAAO;AAAA,EACb;AAAA;AAAA;AAAA;AAAA,EAIA,OAAO,SAAiB;AACvB,WAAO,KAAK,IAAI,UAAU,OAAO;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,MAAY,MAAoB;AACzC,WAAO,KAAK,IAAI,QAAQ,KAAK,YAAY,IAAI,IAAI,WAAW,IAAI;AAAA,EACjE;AAAA;AAAA;AAAA;AAAA,EAIA,WAAW,MAAmB,MAAc;AAC3C,SAAK,KAAK,SAAS,OAAO,KAAK,YAAY,IAAI,IAAI,OAAO,WAAW,IAAI;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA,EAIA,eAAe,MAAY,MAAc;AACxC,SAAK,SAAS,QAAQ,KAAK,YAAY,IAAI,IAAI,WAAW,IAAI;AAAA,EAC/D;AAAA,EACA,SAAS;AACR,QAAI,CAAC,KAAK,IAAI,gBAAgB;AAAQ;AACtC,QAAI,KAAK,qBAAqB;AAC7B,oBAAc,KAAK,mBAAmB;AACtC,WAAK,sBAAsB;AAC3B,WAAK,WAAW,KAAK,YAAY;AAAA,IAClC;AACA,SAAK,KAAK,KAAK,IAAI,gBAAgB,KAAK,IAAI,CAAC;AAC7C,SAAK,IAAI,kBAAkB,CAAC;AAC5B,SAAK,IAAI,SAAS;AAElB,SAAK,gBAAgB;AAAA,EACtB;AAAA,EAEA,cAAc;AACb,QAAI,SAAS;AACb,QAAI,UAAU;AACd,eAAW,KAAK,KAAK,OAAO;AAC3B,UAAI,CAAC,KAAK,MAAM,CAAC,EAAE,OAAO;AACzB;AAAA,MACD;AACA;AACA,gBAAU,MAAM,KAAK,MAAM,CAAC,EAAE,sBAAsB,IAAI;AAAA,IACzD;AACA,UAAM,MAAM,UAAU,UAAU;AAChC,WAAO;AAAA,EACR;AAAA,EAEA,iBAAiB;AAChB,UAAM,cAAc,KAAK,SAAS,cAAc,KAAK;AACrD,SAAK,SAAS,aAAa;AAC3B,SAAK,aAAa;AAClB,WAAO;AAAA,EACR;AAAA;AAAA,EAIA,aAAa,kBAAkB,OAAO;AACrC,QAAI,mBAAmB,KAAK,WAAW;AACtC,mBAAa,KAAK,SAAS;AAC3B,WAAK,YAAY;AAAA,IAClB;AACA,QAAI,KAAK,aAAa,KAAK,UAAU,WAAW;AAAG;AAEnD,UAAM,kBAAkB,KAAK,UAAU,CAAC,EAAE,OAAO,KAAK,IAAI;AAC1D,QAAI,mBAAmB,KAAM;AAC5B,WAAK,OAAO,KAAK,UAAU,CAAC,EAAE,QAAQ,mBAAmB,KAAK,QAAQ,gBAAgB;AAEtF;AAAA,IACD;AACA,SAAK,YAAY,WAAW,MAAM;AACjC,WAAK,YAAY;AACjB,WAAK,aAAa,IAAI;AAAA,IACvB,GAAG,eAAe;AAAA,EACnB;AAAA,EACA,QAAQ,MAA4B;AACnC,QAAI,CAAC;AAAM;AACX,QAAI,KAAK,WAAW;AACnB,iBAAW,SAAS,KAAK,WAAW;AACnC,YAAI,KAAK,OAAO,MAAM,UACrB,KAAK,aAAa,MAAM,YACvB,KAAK,iBAAiB,KAAK,kBAAkB,MAAM,eAAgB;AACpE,cAAI,MAAM,OAAO,KAAK,IAAI,IAAI,GAAG;AAChC,iBAAK,OAAO,KAAK,EAAE;AACnB;AAAA,UACD,OAAO;AACN,mBAAO,MAAM;AAAA,UACd;AAAA,QACD;AAAA,MACD;AAAA,IACD;AACA,QAAI,KAAK;AAAQ,aAAO,KAAK,OAAO,QAAQ,IAAI;AAAA,EACjD;AAAA,EACA,YAAY,MAAgC;AAC3C,UAAM,SAAS,KAAK,QAAQ,IAAI;AAChC,QAAI,CAAC;AAAQ;AACb,eAAW,SAAS,KAAK,WAAW;AACnC,UAAI,WAAW,MAAM,QAAQ;AAC5B,eAAO,MAAM,OAAO,KAAK,IAAI;AAAA,MAC9B;AAAA,IACD;AACA,QAAI,KAAK;AAAQ,aAAO,KAAK,OAAO,YAAY,IAAI;AAAA,EACrD;AAAA,EACA,QAA4B,aAAwC,UAAU,OAAiB;AAE9F,QAAI,WAAW,KAAK,WAAW,KAAK,QAAQ,YAAY,SAAS,YAAY;AAAM,aAAO,KAAK;AAC/F,QAAI,KAAK,QAAQ,KAAK,KAAK,YAAY,SAAS,YAAY;AAAM,aAAO,KAAK;AAC9E,WAAO;AAAA,EACR;AAAA,EACA,iBAA0C,aAAkD;AAC3F,QAAI,KAAK,eAAe,YAAY,SAAS,YAAY;AAAM,aAAO,KAAK;AAC3E,WAAO;AAAA,EACR;AAAA,EACA,sBAAsB,WAAW,OAAmC;AACnE,UAAM,YAAY,WAAW,KAAK,SAAS,qBAAqB,KAAK;AACrE,QAAI,CAAC,WAAW;AAAQ,aAAO;AAC/B,WAAO;AAAA,EACR;AAAA,EACA,mBAAmB,UAAmC;AACrD,QAAI,CAAC,KAAK;AAAoB,WAAK,qBAAqB,CAAC;AACzD,SAAK,mBAAmB,KAAK,QAAQ;AACrC,SAAK,SAAS,qBAAqB,KAAK;AAAA,EACzC;AAAA,EACA,wBAAwB,MAAe,QAAQ,GAAG;AACjD,QAAI,CAAC,KAAK;AAAoB;AAC9B,QAAI,SAAS,QAAW;AACvB,WAAK,qBAAqB;AAC1B,aAAO,KAAK,SAAS;AACrB,WAAK,aAAa;AAAA,IACnB,OAAO;AACN,WAAK,mBAAmB,OAAO,MAAM,KAAK;AAC1C,WAAK,SAAS,qBAAqB,KAAK;AACxC,WAAK,aAAa;AAClB,UAAI,CAAC,KAAK,mBAAmB;AAAQ,aAAK,wBAAwB;AAAA,IACnE;AAAA,EACD;AAAA,EACA,iBAAiB,UAAgC,YAAY,OAAa;AACzE,SAAK,eAAe,SAAS;AAC7B,SAAK,gBAAgB;AACrB,QAAI,KAAK,eAAe;AACvB,WAAK,cAAc,KAAK;AACxB,UAAI,CAAC;AAAW,aAAK,cAAc,QAAQ;AAAA,IAC5C,OAAO;AACN,aAAO,KAAK,SAAS;AACrB,WAAK,aAAa;AAAA,IACnB;AAAA,EACD;AAAA,EACA,eAAe;AACd,QAAI,CAAC,KAAK;AAAS;AAEnB,QAAI,CAAC,MAAM;AAAQ;AAEnB,UAAM,OAAO,kBAAkB;AAAA,EAChC;AAAA,EACA,aAAa,MAAY;AACxB,QAAI,KAAK,MAAM,KAAK;AAAO,aAAO;AAClC,QAAI,CAAC,KAAK,SAAS;AAAS,aAAO;AAEnC,QAAI,KAAK,KAAK,IAAI,KAAK,EAAE;AAAG,aAAO;AAEnC,UAAM,iBAAiB,KAAK,SAAS,YAAY,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS;AAC9F,QAAI,CAAC;AAAgB,aAAO;AAC5B,QAAI,CAAC,MAAM,KAAK,YAAY,cAAc,GAAG;AAC5C,cAAQ,MAAM,8BAA8B,KAAK,WAAW,gBAAgB;AAAA,IAC7E;AACA,WACC,KAAK,KAAK,QAAQ,MAAM,cAAc,KAAK,MAAM,WAAW,QAAQ,MAAM,cAAc;AAAA,EAE1F;AAAA,EACA,KAAK,MAAY,SAAkB;AAClC,UAAM,SAAS,KAAK;AAEpB,QAAI,CAAC;AAAS,gBAAU,IAAI;AAC5B,QAAI,UAAU,KAAK;AAAO,gBAAU,KAAK;AAGzC,QAAI,KAAK,QAAQ,IAAI;AAAG,WAAK,OAAO,MAAM;AAG1C,aAAS,IAAI,GAAG,KAAK,KAAK,UAAU,QAAQ,KAAK;AAChD,YAAM,OAAO,KAAK,IAAI,IAAI;AAC1B,UAAI,MAAM,KAAK,UAAU,UAAU,OAAO,KAAK,UAAU,CAAC,EAAE,MAAM;AACjE,cAAM,QAAQ;AAAA,UACb;AAAA,UACA;AAAA,UACA,UAAU,KAAK;AAAA,UACf,eAAe,KAAK;AAAA,QACrB;AACA,aAAK,UAAU,OAAO,GAAG,GAAG,KAAK;AAGjC,YAAI,MAAM,KAAK,KAAK,WAAW;AAC9B,uBAAa,KAAK,SAAS;AAC3B,eAAK,YAAY;AAAA,QAClB;AACA;AAAA,MACD;AAAA,IACD;AACA,SAAK,aAAa;AAElB,SAAK,eAAe;AAEpB,QAAI,EAAE,KAAK,SAAS,cAAc,QAAQ,KAAK,SAAS,aAAa;AACpE,WAAK,YAAY,uBAAuB,IAAI;AAAA,IAC7C;AAEA,WAAO;AAAA,EACR;AAAA,EACA,OAAO,QAAgB,YAAqB;AAC3C,QAAI,gBAAgB;AACpB,UAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,QAAI,gBAAgB;AACpB,QAAI,MAAM;AACT,eAAS,KAAK;AACd,sBAAgB,KAAK;AAAA,IACtB;AAEA,eAAW,CAAC,GAAG,KAAK,KAAK,KAAK,UAAU,QAAQ,GAAG;AAClD,UAAI,MAAM,WAAW,UACnB,QAAQ,MAAM,aAAa,KAAK,YAChC,iBAAiB,MAAM,kBAAkB,eAAgB;AAC1D,YAAI,MAAM,GAAG;AACZ,eAAK,UAAU,OAAO,GAAG,CAAC;AAC1B,eAAK,aAAa,IAAI;AAAA,QACvB,OAAO;AACN,eAAK,UAAU,OAAO,GAAG,CAAC;AAAA,QAC3B;AACA,wBAAgB,MAAM;AACtB;AAAA,MACD;AAAA,IACD;AAEA,QAAI,QAAQ,iBAAiB,UAAU,KAAK,OAAO;AAClD,WAAK,eAAe;AACpB,UAAI;AAAY,aAAK,MAAM,UAAU;AAAA,IACtC;AACA,WAAO;AAAA,EACR;AAAA,EAEA,eAAe;AACd,QAAI,QAAQ;AACZ,QAAI,SAAS;AACb,UAAM,SAAkC,CAAC;AACzC,eAAW,SAAS,OAAO,eAAe;AACzC,aAAO,KAAK,IAAI;AAAA,IACjB;AACA,eAAW,KAAK,KAAK,OAAO;AAC3B,YAAM,OAAO,KAAK,MAAM,CAAC;AACzB,QAAE;AACF,UAAI,CAAC,KAAK,OAAO;AAChB,UAAE;AAAA,MACH;AACA,QAAE,OAAO,KAAK,KAAK,IAAI,KAAK,EAAE,CAAC;AAAA,IAChC;AACA,QAAI,QAAQ,oBAAoB,gBAAgB;AAChD,eAAW,KAAK,QAAQ;AACvB,eAAS,IAAI,KAAK,OAAO,CAAC;AAAA,IAC3B;AACA,SAAK,QAAQ,KAAK;AAAA,EACnB;AAAA,EAEA,kBAAkB;AACjB,QAAI,KAAK;AAAa,mBAAa,KAAK,WAAW;AACnD,QAAI,KAAK,SAAS,YAAY;AAC7B,WAAK,cAAc,WAAW,MAAM,KAAK,OAAO,GAAG,2BAA2B;AAAA,IAC/E,OAAO;AACN,WAAK,cAAc;AAAA,IACpB;AAAA,EACD;AAAA,EACA,SAAS;AACR,SAAK,KAAK,UAAU;AACpB,SAAK,QAAQ;AAAA,EACd;AAAA,EACA,WAAW,MAAuB,OAAe,MAAY;AAC5D,UAAM,UAAU,KAAK,KAAK,QAAQ,MAAM,KAAK,SAAS,WAAW,UAAU,KAAK,CAAC,KAAK,QAAQ,IAAI;AAClG,QAAI,KAAK,gBAAgB,WAAW,KAAK,KAAK,IAAI,KAAK,EAAE,IAAI;AAC5D,WAAK,IAAI,IAAI,QAAQ,OAAO,EAAE,OAAO;AACrC;AAAA,IACD;AACA,QAAI,SAAS;AACb,YAAQ,MAAM;AAAA,MACd,KAAK;AAAK,iBAAS;AAAK;AAAA,MACxB,KAAK;AAAK,iBAAS;AAAK;AAAA,MACxB,KAAK;AAAK,iBAAS;AAAK;AAAA,IACxB;AACA,YAAQ,IAAI,UAAU;AACtB,QAAI,KAAK,YAAY;AACpB,WAAK,IAAI,gBAAgB,KAAK,KAAK;AAEnC,UAAI,CAAC,KAAK,qBAAqB;AAC9B,aAAK,sBAAsB;AAAA,UAC1B,MAAM,KAAK,OAAO;AAAA,UAAG,KAAK;AAAA,QAC3B;AAAA,MACD;AAAA,IACD,OAAO;AACN,WAAK,KAAK,KAAK;AAAA,IAChB;AACA,SAAK,QAAQ,KAAK;AAAA,EACnB;AAAA,EACA,gBAAgB,MAAY;AAC3B,QAAI,UAAU,iBAAM,+CAA+C,KAAK;AACxE,QAAI,KAAK,SAAS,SAAS;AAC1B,iBAAW,KAAK,KAAK,SAAS;AAAA,IAC/B;AACA,QAAI,KAAK,SAAS,SAAS;AAC1B,YAAM,UAAU,KAAK,SAAS,YAAY,OAAO,KAAK,SAAS,UAAU,KAAK,SAAS;AACvF,iBAAW,KAAK;AAAA,IACjB;AACA,QAAI,KAAK,SAAS,UAAU;AAC3B,iBAAW,cAAc,KAAK,SAAS;AAAA,IACxC;AACA,eAAW;AACX,QAAI,KAAK,SAAS,cAAc;AAC/B,iBAAW;AAAA,mDAAuD,KAAK,SAAS,YAAY,aAAa,4BAA4B,QACpI,KAAK,SAAS,aAAa,QAAQ,OAAO,EAAE,IAC5C;AAAA,IACF;AACA,UAAM,aAAa,KAAK,qBAAqB,IAAI;AACjD,QAAI;AAAY,iBAAW;AAAA,EAAK;AAChC,WAAO;AAAA,EACR;AAAA,EACA,qBAAqB,MAAY;AAChC,QAAI,CAAC,KAAK,IAAI,QAAQ,MAAM,IAAI;AAAG,aAAO;AAC1C,UAAM,WAAW,CAAC;AAClB,QAAI,KAAK,SAAS,cAAc;AAC/B,eAAS,KAAK,wDACb,KAAK,SAAS,aAAa,QAAQ,OAAO,EAAE,IAC5C,QAAQ;AAAA,IACV;AACA,QAAI,KAAK,kBAAkB,MAAM;AAChC,UAAI,UAAU;AACd,iBAAW,mDAAmD,KAAK,iBAAiB;AACpF,iBAAW,CAAC,QAAQ,KAAK,KAAK,KAAK,kBAAkB;AACpD,mBAAW;AACX,mBAAW,kCAAkC;AAC7C,YAAI,MAAM,YAAY;AACrB,gBAAM,CAAC,OAAO,QAAQ,OAAO,IAAI,MAAM;AACvC,qBAAW,0CAA0C,MAAM,gBAAgB,kBAAkB;AAC7F,cAAI;AAAS,uBAAW;AAAA,QACzB,OAAO;AACN,qBAAW,yCAAyC,MAAM;AAAA,QAC3D;AACA,mBAAW,6BAA6B,MAAM,UAAU,MAAM,UAAU;AACxE,mBAAW,0DAA0D,+EACb;AACxD,mBAAW;AAAA,MACZ;AACA,iBAAW;AACX,eAAS,KAAK,OAAO;AAAA,IACtB;AACA,QACC,CAAC,KAAK,SAAS,aAAa,CAAC,KAAK,SAAS,cAC3C,KAAK,SAAS,WAAW,KAAK,SAAS,YAAY,iBAClD;AACD,eAAS,KAAK,4DAA4D,KAAK,SAAS,eAAe;AAAA,IACxG;AACA,WAAO,SAAS,KAAK,IAAI;AAAA,EAC1B;AAAA,EACA,YAAY,gBAAgB,OAAO;AAClC,QAAI,CAAC,KAAK;AAAU,aAAO,CAAC;AAC5B,WAAO,CAAC,GAAG,KAAK,SAAS,OAAO,CAAC,EAAE;AAAA,MAClC,UAAQ,gBAAgB,OAAO,CAAC,KAAK,SAAS,aAAa,CAAC,KAAK,SAAS;AAAA,IAC3E;AAAA,EACD;AAAA,EACA,cAAc,UAAkB,OAAgB,OAAgB;AAC/D,QAAI,CAAC;AAAO,cAAQ,KAAK,QAAQ;AAIjC,QAAI,SAAS,SAAS,GAAG,KAAK,SAAS,SAAS,GAAG,GAAG;AACrD,YAAM,IAAI,KAAK,aAAa,eAAe,oCAAoC;AAAA,IAChF;AACA,SAAK,CAAC,MAAM,SAAS,GAAG,KAAK,MAAM,WAAW,YAAY,MAAM,SAAS,SAAS,GAAG,GAAG;AACvF,YAAM,IAAI,KAAK,aAAa,eAAe,2BAA2B;AAAA,IACvE;AACA,QAAI,MAAM,SAAS;AAAwB,YAAM,IAAI,KAAK,aAAa,mCAAmC;AAC1G,QAAI,UAAU,SAAS,MAAM,OAAO,QAAQ;AAAG,YAAM,IAAI,KAAK,aAAa,aAAa,2BAA2B;AAAA,EACpH;AAAA,EACA,UAAU,MAAmB;AAC5B,QAAI,KAAK,WAAW;AAAM;AAE1B,QAAI,KAAK,QAAQ;AAChB,MAAC,KAAK,OAAO,SAAiB,OAAO,KAAK,MAAM;AAChD,UAAI,CAAC,KAAK,OAAO,SAAU,MAAM;AAChC,QAAC,KAAK,OAAO,WAAmB;AAAA,MACjC;AAAA,IACD;AACA,IAAC,KAAa,SAAS;AACvB,QAAI,MAAM;AACT,UAAI,CAAC,KAAK,UAAU;AACnB,QAAC,KAAa,WAAW,oBAAI,IAAI;AAAA,MAClC;AACA,MAAC,KAAa,SAAS,IAAI,KAAK,QAAQ,IAAI;AAC5C,WAAK,SAAS,WAAW,KAAK;AAAA,IAC/B,OAAO;AACN,aAAO,KAAK,SAAS;AAAA,IACtB;AAEA,SAAK,aAAa;AAElB,eAAW,UAAU,KAAK,OAAO;AAChC,WAAK,MAAM,MAAM,EAAE,eAAe,KAAK,MAAM;AAAA,IAC9C;AAAA,EACD;AAAA,EACA,gBAAgB;AACf,QAAI,CAAC,KAAK;AAAU;AACpB,eAAW,QAAQ,KAAK,SAAS,OAAO,GAAG;AAC1C,MAAC,KAAa,SAAS;AAAA,IACxB;AACA,IAAC,KAAa,WAAW;AAAA,EAI1B;AAAA,EACA,WAAW,SAAyB;AACnC,SAAK,SAAS,YAAY;AAC1B,SAAK,aAAa;AAElB,QAAI,SAAS;AACZ,iBAAW,QAAQ,OAAO,OAAO,KAAK,KAAK,GAAG;AAC7C,YAAI,CAAC,KAAK,OAAO;AAChB,eAAK,UAAU,KAAK,MAAM;AAC1B,eAAK,MAAM,cAAc,KAAK,yEAAyE;AAAA,QACxG;AAAA,MACD;AAAA,IACD;AAEA,QAAI,KAAK,UAAU,KAAK,QAAQ;AAC/B,UAAI,SAAS;AACZ,YAAI,KAAK,OAAO,SAAS,IAAI;AAAG,iBAAO;AAIvC,YAAI,WAAW;AACf,iBAAS,IAAI,GAAG,IAAI,IAAI;AAAK,sBAAY,SAAS,OAAO,UAAU,GAAG,SAAS,SAAS,CAAC,CAAC;AAE1F,aAAK,OAAO,KAAK,OAAO,GAAG,KAAK,UAAU,cAAwB,IAAI;AAAA,MACvE,OAAO;AACN,YAAI,CAAC,KAAK,OAAO,SAAS,IAAI;AAAG,iBAAO;AAExC,cAAM,gBAAgB,KAAK,OAAO,YAAY,GAAG;AACjD,YAAI,gBAAgB;AAAG,gBAAM,IAAI,MAAM,qBAAqB,KAAK,QAAQ;AAEzE,aAAK,OAAO,KAAK,OAAO,KAAK,OAAO,MAAM,GAAG,aAAa,CAAW;AAAA,MACtE;AAAA,IACD;AACA,SAAK,QAAQ,kBAAkB,OAAO;AAEtC,QAAI,KAAK,MAAM;AACd,iBAAW,UAAU,KAAK,KAAK,SAAS;AACvC,eAAO,QAAQ,GAAG,aAAa;AAAA,MAChC;AAAA,IACD;AAAA,EACD;AAAA,EACA,gBAAgB,SAAiB;AAChC,UAAM,SAAS,KAAK,OAAO;AAC3B,QAAI,CAAC,kCAAa,SAAS,SAAS,MAAa,GAAG;AACnD,YAAM,IAAI,KAAK,aAAa,IAAI,kEAAkE,kCAAa,SAAS,KAAK,IAAI,GAAG;AAAA,IACrI;AACA,WAAO;AAAA,EACR;AAAA,EACA,WAAW,SAAkB;AAC5B,QAAI,CAAC,KAAK,SAAS;AAClB,YAAM,IAAI,KAAK,aAAa,mDAAmD;AAAA,IAChF;AACA,QAAI,SAAS;AACZ,YAAM,mBAAmB,KAAK,gBAAgB,OAAO;AACrD,UAAI,KAAK,SAAS,aAAa,CAAC,MAAM,QAAQ,EAAE,SAAS,KAAK,SAAS,SAAS,GAAG;AAClF,cAAM,IAAI,KAAK,aAAa,6CAA6C;AAAA,MAC1E;AACA,YAAM,aAAa,KAAK,SAAS;AACjC,UAAI,eAAe,SAAS;AAC3B,cAAM,IAAI,KAAK,aAAa,GAAG,KAAK,2CAA2C,kCAAa,aAAa,UAAU,KAAK;AAAA,MACzH;AACA,WAAK,SAAS,UAAU;AACxB,WAAK,aAAa;AAClB,aAAO;AAAA,IACR;AACA,WAAO,KAAK,SAAS;AACrB,SAAK,aAAa;AAClB,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,iBAAiB,SAAiB;AACjC,UAAM,SAAS,OAAO,OAAO,KAAK,KAAK,EAAE,OAAO,OAAK,CAAC,EAAE,IAAI,MAAM,CAAC;AACnE,eAAW,QAAQ,QAAQ;AAC1B,WAAK,MAAM,UAAU,SAAS;AAAA,IAC/B;AACA,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,UAAkB,OAAgB,SAAmB;AAC3D,QAAI,CAAC;AAAO,cAAQ,KAAK,QAAQ;AACjC,UAAM,QAAQ,KAAK;AACnB,SAAK,cAAc,UAAU,OAAO,KAAK;AACzC,QAAI,KAAK,SAAS,UAAU,KAAK,MAAM;AACtC,YAAM,IAAI,KAAK,aAAa,4BAA4B,KAAK,KAAK,0BAA0B,KAAK,SAAS;AAAA,IAC3G;AACA,IAAC,KAAa,SAAS;AACvB,SAAK,QAAQ,KAAK,SAAS,QAAQ;AACnC,SAAK,aAAa;AAClB,QAAI,UAAU,OAAO;AACpB,iBAAW,QAAQ,OAAO,OAAO,KAAK,KAAK,GAAG;AAC7C,aAAK,OAAO,MAAM,UAAU,UAAU;AAAA,MACvC;AACA;AAAA,IACD;AAEA,UAAM,MAAM,OAAO,KAAK;AACxB,UAAM,MAAM,IAAI,OAAO,IAAY;AACnC,QAAI,KAAK,UAAU,OAAO;AACzB,iBAAW,UAAU,KAAK,OAAO,SAAS;AACzC,YAAI,OAAO,QAAQ;AAClB,gBAAM,QAAQ,QAAQ,WAAW,aAAa,OAAO,QAAQ,KAAK;AAClE,cAAI;AAAO,kBAAM,SAAS,KAAK;AAAA,QAChC;AAAA,MACD;AAAA,IACD;AAEA,QAAI,UAAU,SAAS;AACtB,YAAM,QAAQ;AAAA,IACf,WAAW,UAAU,SAAS;AAC7B,YAAM,QAAQ;AAAA,IACf;AAEA,QAAI,CAAC,SAAS;AACb,iBAAW,CAAC,OAAO,MAAM,KAAK,MAAM,QAAQ,QAAQ,GAAG;AACtD,YAAI,WAAW,OAAO;AACrB,gBAAM,QAAQ,IAAI,OAAO,KAAK;AAAA,QAC/B;AAAA,MACD;AAGA,YAAM,QAAQ,IAAI,OAAO,KAAK;AAC9B,UAAI,CAAC,KAAK,SAAS;AAAS,aAAK,SAAS,UAAU,CAAC;AAErD,UAAI,CAAC,KAAK,SAAS,QAAQ,SAAS,KAAK;AAAG,aAAK,SAAS,QAAQ,KAAK,KAAK;AAAA,IAC7E,OAAO;AAEN,iBAAW,CAAC,OAAO,MAAM,KAAK,MAAM,QAAQ,QAAQ,GAAG;AACtD,YAAI,WAAW,OAAO;AACrB,gBAAM,QAAQ,OAAO,KAAK;AAAA,QAC3B;AAAA,MACD;AACA,WAAK,SAAS,UAAU;AAAA,IACzB;AAEA,SAAK,MAAM,WAAW,KAAK;AAE3B,eAAW,QAAQ,OAAO,OAAO,KAAK,KAAK,GAAG;AAC7C,WAAK,gBAAgB,OAAO,KAAK;AACjC,WAAK,KAAK,IAAI;AAAA,iBAAyB,SAAS,UAAU;AAAA,IAC3D;AAEA,QAAI,KAAK,QAAQ,UAAU;AAC1B,MAAC,KAAa,OAAO,SAAS,OAAO,KAAK;AAC1C,MAAC,KAAa,OAAO,SAAS,IAAI,OAAO,IAAgB;AAAA,IAC1D;AACA,QAAI,KAAK,UAAU;AAClB,iBAAW,WAAW,KAAK,SAAS,OAAO,GAAG;AAC7C,QAAC,QAAgB,SAAS;AAC1B,gBAAQ,SAAS,WAAW;AAAA,MAC7B;AAAA,IACD;AAEA,SAAK,aAAa;AAElB,gBAAY,WAAW,OAAO,KAAK;AAEnC,SAAK,KAAK,IAAI,OAAO,KAAK;AAAA,EAC3B;AAAA,EAEA,UAAU,MAAY,YAAwB;AAC7C,UAAM,WAAW,KAAK,WAAW,KAAK,WAAW,KAAK,YAAY;AAClE,SAAK;AAAA,MACJ;AAAA,MACA,wBAAwB,KAAK,QAAQ,OAAO,WAAW,OAAO,KAAK,IAAI,cAAc,IAAI,KAAK,gBAAgB,IAAI;AAAA,IACnH;AACA,SAAK,eAAe,YAAY,MAAM,UAAU;AAChD,SAAK,MAAM,YAAY,MAAM,UAAU;AAAA,EACxC;AAAA,EACA,OAAO,MAAY,YAAwB;AAC1C,QAAI,CAAC;AAAM,aAAO;AAClB,QAAI,KAAK,MAAM,KAAK,EAAE;AAAG,aAAO;AAEhC,SAAK,YAAY,oBAAoB,MAAM,MAAM,UAAU;AAC3D,QAAI,KAAK,OAAO;AACf,WAAK,WAAW,KAAK,KAAK,sBAAsB,IAAI,GAAG,IAAI;AAAA,IAC5D;AAEA,UAAM,aAAa,KAAK,qBAAqB,IAAI;AACjD,QAAI;AAAY,WAAK,SAAS,MAAM,UAAU;AAE9C,SAAK,MAAM,KAAK,EAAE,IAAI;AACtB,SAAK;AACL,SAAK,iBAAiB,IAAI;AAE1B,SAAK,MAAM,SAAS,MAAM,UAAU;AACpC,SAAK,YAAY,cAAc,MAAM,MAAM,UAAU;AACrD,WAAO;AAAA,EACR;AAAA,EACA,SAAS,MAAY,OAAW,SAAkB;AACjD,QAAI,KAAK,OAAO,OAAO;AACtB,aAAO,KAAK,iBAAiB,IAAI;AAAA,IAClC;AACA,QAAI,CAAC,KAAK,MAAM,KAAK,GAAG;AACvB,cAAQ,SAAS,IAAI,MAAM,QAAQ,qBAAqB,KAAK,QAAQ,CAAC;AAAA,IACvE;AACA,QAAI,KAAK,MAAM,KAAK,EAAE,GAAG;AACxB,cAAQ,SAAS,IAAI,MAAM,QAAQ,KAAK,sBAAsB,KAAK,QAAQ,CAAC;AAAA,IAC7E;AACA,WAAO,KAAK,MAAM,KAAK;AACvB,SAAK,MAAM,KAAK,EAAE,IAAI;AACtB,QAAI,SAAS;AACZ,WAAK,WAAW,KAAK,KAAK,sBAAsB,IAAI,GAAG,IAAI;AAC3D,YAAM,aAAa,KAAK,qBAAqB,IAAI;AACjD,UAAI;AAAY,aAAK,SAAS,MAAM,UAAU;AAAA,IAC/C,WAAW,CAAC,KAAK,OAAO;AACvB,WAAK,WAAW,KAAK,MAAM,OAAO,IAAI;AAAA,IACvC,OAAO;AACN,WAAK,WAAW,KAAK,KAAK,sBAAsB,IAAI,IAAI,MAAM,OAAO,IAAI;AAAA,IAC1E;AACA,SAAK,eAAe,WAAW,MAAM,OAAO,OAAO;AACnD,SAAK,iBAAiB,IAAI;AAC1B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA,EAIA,iBAAiB,MAAY;AAC5B,QAAI,MAAM,WAAW;AACpB,UAAI,CAAC,KAAK,MAAM,KAAK,EAAE;AAAG,eAAO;AACjC,UAAI,KAAK,OAAO;AACf,aAAK,WAAW,KAAK,KAAK,sBAAsB,IAAI,IAAI,MAAM,KAAK,IAAI,IAAI;AAAA,MAC5E;AAAA,IACD;AACA,WAAO;AAAA,EACR;AAAA,EACA,QAAQ,MAAY;AACnB,QAAI,CAAC;AAAM,aAAO;AAElB,QAAI,EAAE,KAAK,MAAM,KAAK,QAAQ;AAC7B,cAAQ,SAAS,IAAI,MAAM,QAAQ,KAAK,iBAAiB,CAAC;AAC1D,aAAO;AAAA,IACR;AACA,WAAO,KAAK,MAAM,KAAK,EAAE;AACzB,SAAK;AAEL,QAAI,KAAK,OAAO;AACf,WAAK,WAAW,KAAK,KAAK,YAAY,IAAI,GAAG,IAAI;AAAA,IAClD;AACA,SAAK,MAAM,UAAU,IAAI;AACzB,SAAK,eAAe;AAEpB,WAAO;AAAA,EACR;AAAA,EAEA,iBAAiB;AAChB,QAAI,CAAC,KAAK,SAAS,eAAe,KAAK,SAAS,YAAY;AAAQ;AAEpE,UAAM,QAAQ,OAAO,OAAO,KAAK,KAAK,EAAE,OAAO,OAAK,KAAK,KAAK,QAAQ,GAAG,GAAG,CAAC;AAC7E,QAAI,CAAC,MAAM,QAAQ;AAClB,YAAM,EAAE,KAAK,IAAI,KAAK,SAAS;AAC/B,UAAI,CAAC,QAAQ,OAAO,GAAG;AACtB,cAAM,IAAI,MAAM,yCAAyC,iBAAM,UAAU,KAAK,SAAS,WAAW,IAAI;AAAA,MACvG;AACA,UAAI,KAAK;AAAc;AACvB,WAAK,eAAe,WAAW,MAAM;AACpC,YAAI,CAAC,KAAK,SAAS;AAAa;AAChC,cAAM,EAAE,KAAK,IAAI,KAAK,SAAS;AAC/B,cAAM,aAAa,KAAK,SAAS;AACjC,aAAK,SAAS,UAAU;AACxB,aAAK;AAAA;AAAA,UAEJ,kFAAkF,4CACnD;AAAA,QAChC,EAAE,OAAO;AACT,aAAK,OAAO;AAAA,UACX,QAAQ;AAAA,QACT,CAAC;AAED,aAAK,SAAS,YAAY,SAAS,cAAc;AACjD,aAAK,aAAa;AAClB,aAAK,eAAe;AAAA,MACrB,GAAG,OAAO,KAAK,GAAI;AAAA,IACpB;AAAA,EACD;AAAA,EAEA,iBAAiB,MAAY;AAC5B,QAAI,KAAK,IAAI,QAAQ,MAAM,MAAM,SAAS,GAAG;AAC5C,UAAI,KAAK,cAAc;AACtB,qBAAa,KAAK,YAAY;AAAA,MAC/B;AACA,UAAI,KAAK,SAAS,aAAa,QAAQ;AACtC,cAAM,aAAa,KAAK,SAAS,YAAY;AAC7C,YAAI,OAAO,eAAe,UAAU;AACnC,eAAK,SAAS,UAAU;AAAA,QACzB,OAAO;AACN,iBAAO,KAAK,SAAS;AAAA,QACtB;AACA,aAAK,SAAS,YAAY,SAAS;AACnC,aAAK,aAAa;AAAA,MACnB;AAAA,IACD;AAAA,EACD;AAAA,EAEA,UAAgB;AAGf,QAAI,KAAK,MAAM;AACd,WAAK,KAAK,QAAQ;AAClB,WAAK,OAAO;AACZ,WAAK,SAAS;AACd,WAAK,OAAO;AAAA,IACb;AAGA,eAAW,KAAK,KAAK,OAAO;AAC3B,WAAK,MAAM,CAAC,EAAE,UAAU,MAAc,IAAI;AAC1C,aAAO,KAAK,MAAM,CAAC;AAAA,IACpB;AAEA,SAAK,UAAU,IAAI;AACnB,SAAK,cAAc;AAEnB,SAAK,YAAY,iBAAiB,KAAK,MAAM;AAE7C,UAAM,OAAO,mBAAmB,KAAK,MAAM;AAC3C,UAAM,OAAO,eAAe,KAAK,MAAM;AAEvC,QAAI,KAAK,SAAS,SAAS;AAC1B,iBAAW,SAAS,KAAK,SAAS,SAAS;AAC1C,cAAM,QAAQ,OAAO,KAAK;AAAA,MAC3B;AAAA,IACD;AAEA,SAAK,SAAS;AAGd,SAAK,OAAO;AAGZ,QAAI,KAAK,WAAW;AACnB,mBAAa,KAAK,SAAS;AAC3B,WAAK,YAAY;AAAA,IAClB;AACA,QAAI,KAAK,aAAa;AACrB,mBAAa,KAAK,WAAW;AAC7B,WAAK,cAAc;AAAA,IACpB;AACA,QAAI,KAAK,qBAAqB;AAC7B,oBAAc,KAAK,mBAAmB;AAAA,IACvC;AACA,SAAK,sBAAsB;AAC3B,QAAI,KAAK,sBAAsB;AAC9B,oBAAc,KAAK,oBAAoB;AAAA,IACxC;AACA,SAAK,uBAAuB;AAE5B,SAAK,KAAK,IAAI,QAAQ;AAEtB,UAAM,MAAM,OAAO,KAAK,MAAM;AAC9B,QAAI,KAAK,WAAW;AAAS,YAAM,QAAQ;AAAA,EAC5C;AAAA,EACA,GAAG,YAA2C,MAAa;AAC1D,WAAO,KAAK,GAAG,KAAK,SAAS,YAAY,WAAiB,SAAS,GAAG,IAAI;AAAA,EAC3E;AACD;AAEO,MAAM,gBAAgB;AAAA,EAsB5B,cAAc;AAmKd,0BAAiB;AAlKhB,SAAK,eAAe,CAAC;AACrB,QAAI;AACH,WAAK,eAAe,YAAQ,eAAG,uBAAuB,EAAE,IAAI;AAC5D,UAAI,CAAC,MAAM,QAAQ,KAAK,YAAY;AAAG,aAAK,eAAe,CAAC;AAAA,IAC7D,QAAE;AAAA,IAAO;AAET,QAAI,CAAC,KAAK,aAAa,QAAQ;AAC9B,WAAK,eAAe,CAAC;AAAA,QACpB,OAAO;AAAA,QACP,MAAM,CAAC;AAAA,QACP,cAAc,KAAK,IAAI;AAAA,QACvB,UAAU;AAAA,QACV,SAAS;AAAA,MACV,GAAG;AAAA,QACF,OAAO;AAAA,QACP,MAAM,CAAC;AAAA,QACP,cAAc,KAAK,IAAI;AAAA,QACvB,WAAW;AAAA,QACX,SAAS;AAAA,QACT,UAAU;AAAA,MACX,CAAC;AAAA,IACF;AAEA,SAAK,YAAY,CAAC;AAElB,SAAK,eAAe,CAAC;AACrB,SAAK,wBAAwB,CAAC;AAC9B,eAAW,CAAC,GAAG,QAAQ,KAAK,KAAK,aAAa,QAAQ,GAAG;AACxD,UAAI,CAAC,UAAU,OAAO;AACrB,gBAAQ,KAAK,sBAAsB,wCAAwC;AAC3E;AAAA,MACD;AACA,UAAK,SAAiB,eAAe;AAEpC,eAAQ,SAAiB;AACzB,QAAC,SAAiB,WAAW;AAC7B,YAAI,CAAC,SAAS;AAAS,mBAAS,UAAU;AAC1C,YAAI,SAAS,cAAc;AAAM,mBAAS,YAAY;AAAA,MACvD;AAMA,YAAM,KAAK,KAAK,SAAS,KAAK;AAC9B,cAAQ,OAAO,uBAAuB,EAAE;AACxC,YAAM,OAAO,MAAM,eAAe,IAAI,SAAS,OAAO,QAAQ;AAC9D,UAAI,KAAK,SAAS,SAAS;AAC1B,mBAAW,SAAS,KAAK,SAAS,SAAS;AAC1C,gBAAM,QAAQ,IAAI,OAAO,EAAE;AAAA,QAC5B;AAAA,MACD;AAEA,WAAK,UAAU,KAAK,IAAI;AACxB,UAAI,KAAK,SAAS,UAAU;AAC3B,YAAI,KAAK,SAAS,SAAS;AAC1B,eAAK,sBAAsB,KAAK,EAAE;AAAA,QACnC,OAAO;AACN,eAAK,aAAa,KAAK,EAAE;AAAA,QAC1B;AAAA,MACD;AAAA,IACD;AACA,UAAM,QAAQ,MAAM,MAAM,IAAI,OAAO;AAGrC,QAAI,OAAO,aAAa;AACvB,WAAK,cAAc,QAAQ,QAAQ,uBAAuB,EAAE,mBAAmB;AAAA,IAChF,OAAO;AAGN,WAAK,cAAc,IAAI,mBAAQ,YAAY,EAAE,QAAQ;AAAE,eAAO;AAAA,MAAW,EAAE,CAAC;AAAA,IAC7E;AAEA,SAAK,0BAA0B;AAAA,MAC9B,MAAM,KAAK,gBAAgB;AAAA,MAC3B;AAAA,IACD;AAGA,SAAK,WAAW;AAChB,SAAK,eAAe;AACpB,SAAK,WAAW;AAEhB,SAAK,cAAc;AACnB,SAAK,oBAAoB;AAEzB,SAAK,aAAa;AAElB,QAAI;AACJ,QAAI;AACH,mBAAa,QAAQ,QAAQ,gBAAgB,EAAE,SAAS,MAAM;AAAA,IAC/D,QAAE;AAAA,IAAO;AACT,SAAK,aAAa,OAAO,UAAU,KAAK;AACxC,SAAK,oBAAoB,KAAK;AAC9B,SAAK,KAAK,YAAY;AAAA,EACvB;AAAA,EAEA,MAAM,oBAAoB,MAAY;AACrC,QAAI,CAAC,KAAK,UAAU,KAAK,OAAO;AAAO,aAAO;AAC9C,SAAK,OAAO,SAAS;AACrB,UAAM,MAAM,MAAM,KAAK,OAAO,OAAO;AACrC,UAAM,UAAU,KAAK,OAAO,QAAQ,IAAI,OAAK,EAAE,EAAE,EAAE,OAAO,OAAO;AACjE,QAAI,CAAC,QAAQ,UAAU,CAAC,KAAK;AAAQ,aAAO;AAE5C,WAAO;AAAA,MACN,QAAQ,KAAK;AAAA,MACb,UAAU,IAAI,KAAK,IAAI;AAAA,MACvB;AAAA,MACA,OAAO,KAAK;AAAA,MACZ,OAAO,KAAK,OAAO;AAAA,MACnB,OAAO;AAAA,QACN,GAAG,KAAK,OAAO,MAAM;AAAA,QACrB,QAAQ,CAAC,CAAC,KAAK,OAAO,MAAM,SAAS;AAAA,MACtC;AAAA,IACD;AAAA,EACD;AAAA,EACA,sBAAsB,QAAkF;AACvG,UAAM,EAAE,UAAU,SAAS,QAAQ,OAAO,OAAO,MAAM,IAAI;AAC3D,UAAM,CAAC,EAAE,QAAQ,IAAI,OAAO,MAAM,GAAG;AACrC,UAAM,OAAO,MAAM,aAAa;AAAA,MAC/B,QAAQ;AAAA,MACR;AAAA,MACA;AAAA,MACA;AAAA,MACA,OAAO,OAAO,KAAK;AAAA,MACnB,SAAS,CAAC;AAAA,MACV,cAAc,MAAM;AAAA,IACrB,CAAC;AACD,QAAI,CAAC,MAAM;AAAQ,aAAO;AAC1B,QAAI,OAAO;AACV,aAAO,OAAO,KAAK,OAAO,MAAM,UAAU,KAAK;AAAA,IAChD;AACA,eAAW,CAAC,GAAG,QAAQ,KAAK,QAAQ,QAAQ,GAAG;AAC9C,WAAK,KAAK,IAAI,UAAU,MAAM,aAAa;AAC3C,YAAM,SAAS,KAAK,OAAO,QAAQ,CAAC;AACpC,MAAC,OAAO,KAAgB;AACxB,WAAK,OAAO,YAAY,QAAQ,IAAI;AACpC,aAAO,UAAU;AACjB,YAAM,OAAO,MAAM,SAAS,QAAQ;AACpC,aAAO,OAAO,MAAM,QAAQ;AAC5B,YAAM,SAAS,IAAI;AAAA,IACpB;AACA,WAAO;AAAA,EACR;AAAA,EAEA,MAAM,cAAc;AACnB,QAAI,QAAQ;AACZ,UAAM,MAAM,QAAQ,QAAQ,wBAAwB,EAAE,mBAAmB;AACzE,eAAW,QAAQ,MAAM,MAAM,OAAO,GAAG;AACxC,UAAI,CAAC,KAAK,UAAU,KAAK,OAAO;AAAO;AACvC,WAAK,OAAO,SAAS;AACrB,WAAK,OAAO,MAAM,KAAK;AACvB,YAAM,IAAI,MAAM,KAAK,oBAAoB,IAAI;AAC7C,UAAI,CAAC;AAAG;AACR,YAAM,IAAI,UAAU,KAAK,UAAU,CAAC,CAAC;AACrC;AAAA,IACD;AACA,UAAM,IAAI,SAAS;AACnB,UAAM,QAAQ,QAAQ,wBAAwB,EAAE,OAAO,QAAQ,QAAQ,eAAe,EAAE,IAAI;AAC5F,WAAO;AAAA,EACR;AAAA,EAGA,MAAM,cAAc;AACnB,SAAK,iBAAiB;AACtB,eAAW,KAAK,MAAM,MAAM,OAAO,GAAG;AACrC,QAAE;AAAA,QACD,SAAS,EAAE,YAAY;AAAA,MAExB;AAAA,IACD;AACA,UAAM,YAAY,KAAK,IAAI;AAC3B,QAAI,QAAQ;AACZ,QAAI;AACJ,QAAI;AACH,YAAM,SAAS,QAAQ,QAAQ,eAAe,EAAE,iBAAiB;AACjE,YAAM,OAAO;AACb,cAAQ,OAAO,OAAO;AAAA,IACvB,QAAE;AACD;AAAA,IACD;AACA,qBAAiB,QAAQ,OAAO;AAC/B,UAAI,CAAC;AAAM;AACX,UAAI,KAAK,sBAAsB,KAAK,MAAM,IAAI,CAAC;AAAG;AAAA,IACnD;AACA,eAAW,KAAK,MAAM,MAAM,OAAO,GAAG;AACrC,QAAE,KAAK,SAAS,EAAE,YAAY,4BAA4B;AAAA,IAC3D;AACA,UAAM,QAAQ,QAAQ,eAAe,EAAE,eAAe;AACtD,YAAQ,OAAO,UAAU,oBAAoB,KAAK,IAAI,IAAI,aAAa;AACvE,SAAK,iBAAiB;AAAA,EACvB;AAAA,EAEA,YAAY,MAAY;AACvB,eAAW,QAAQ,MAAM,MAAM,OAAO,GAAG;AACxC,YAAM,SAAS,KAAK,QAAQ,CAAC,KAAK,KAAK,SAAS,KAAK,KAAK,YAAY,KAAK,EAAE;AAC7E,UAAI,CAAC;AAAQ;AAEb,UAAI,OAAO;AAAW;AACtB,WAAK,MAAM,IAAI,KAAK,MAAM;AAC1B,aAAO,OAAO,KAAK;AACnB,WAAK,SAAS,KAAK,MAAM;AAAA,IAC1B;AAAA,EACD;AAAA,EAEA,OAAO,OAA2B,YAAqB;AACtD,SAAK,MAAM,OAAO,MAAM,UAAU,OAAO,UAAU;AAAA,EACpD;AAAA,EAEA,oBAAoB;AACnB,uBAAG,uBAAuB,EAAE,YAAY,MACvC,KAAK,UAAU,KAAK,YAAY,EAC9B,QAAQ,eAAe,aAAa,EACpC,QAAQ,OAAO,KAAK,GACpB,EAAE,UAAU,IAAK,CAAC;AAAA,EACtB;AAAA,EAEA,gBAAgB;AACf,QAAI,KAAK,UAAU;AAClB,UAAI,KAAK,eAAe,KAAK;AAAmB;AAChD,WAAK,oBAAoB,KAAK;AAAA,IAC/B,OAAO;AAIN,UAAI,KAAK,aAAa,KAAK;AAAmB;AAC9C,WAAK,oBAAoB,KAAK,aAAa;AAAA,IAC5C;AACA,YAAQ,QAAQ,gBAAgB,EAAE;AAAA,MACjC,MAAM,GAAG,KAAK;AAAA,IACf;AAAA,EACD;AAAA,EAEA,kBAAkB;AACjB,QAAI,KAAK,cAAc;AACtB,WAAK,YAAY,QAAQ,mBAAmB;AAAA,QAC3C,MAAM,KAAK;AAAA,QACX,OAAO,KAAK;AAAA,MACb,CAAC;AACD,WAAK,eAAe;AAAA,IACrB;AACA,SAAK,YAAY,QAAQ,mBAAmB;AAAA,MAC3C,MAAM,KAAK,IAAI;AAAA,MACf,OAAO,MAAM;AAAA,IACd,CAAC;AAAA,EACF;AAAA,EAEA,IAAI,iBAAiB;AACpB,QAAI,KAAK,YAAY;AACpB,aAAO,KAAK;AAAA,IACb;AACA,SAAK,aAAa,WAAW,QAAQ,qBAAqB;AAC1D,QAAI,UAAU;AACd,QAAI,cAAc;AAClB,QAAI,YAAY;AAChB,eAAW,UAAU,IAAI,QAAQ,IAAI,GAAG;AACvC,UAAI,OAAO;AAAS,kBAAU,OAAO;AACrC,UAAI,OAAO;AAAQ,oBAAY,OAAO;AACtC,UAAI,CAAC,OAAO;AAAM;AAClB,UAAI,CAAC,OAAO,iBAAiB,CAAC,OAAO,cAAc,CAAC,OAAO;AAAgB;AAE3E,UAAI,YAAY,aAAa;AAC5B,sBAAc;AACd,aAAK,cAAc,KAAK,aAAa;AAAA,MACtC;AACA,WAAK,cAAc,IAAI,OAAO;AAC9B,UAAI,cAAc;AAClB,UAAI,OAAO;AAAM,uBAAe;AAChC,UAAI,OAAO;AAAY,uBAAe;AACtC,UAAI,OAAO;AAAe,uBAAe;AACzC,UAAI,OAAO;AAAgB,uBAAe;AAC1C,YAAM,YAAY,IAAI,QAAQ,aAAa,MAAM;AACjD,YAAM,QAAQ,UAAU,eAAe,UAAU,mBAAmB,UAAU;AAC9E,UAAI,UAAU;AAAI,uBAAe;AAEjC,UAAI,OAAO;AAAe,uBAAe;AACzC,UAAI,OAAO;AAAoB,uBAAe;AAC9C,WAAK,cAAc,MAAM,YAAY,SAAS,EAAE;AAAA,IACjD;AACA,WAAO,KAAK;AAAA,EACb;AAAA,EACA,IAAI,iBAAiB;AACpB,QAAI,OAAO;AAAmB,aAAO;AAGrC,QAAI,OAAO,UAAU;AACpB,aAAO,OAAO;AAAA,IACf;AACA,UAAM,WAAW,CAAC;AAElB,eAAW,QAAQ,OAAO,QAAQ;AACjC,UAAI,CAAC,OAAO,OAAO,IAAI,KAAK,CAAC;AAAM;AAEnC,YAAM,WAAW,OAAO,OAAO,IAAI;AACnC,YAAM,YAAY,SAAS,OAAO,SAAU,CAAC,SAAS,QAAQ,CAAC,SAAS,OACvE,WAAY,SAAS,QAAQ,SAAS,UAAW,eAAe;AAEjE,eAAS,KAAK;AAAA,QACb,QAAQ;AAAA,QACR,MAAO,OAAO,OAAO,IAAI,EAAE,QAAQ;AAAA,QACnC,MAAM;AAAA,MAAU,CAAC;AAAA,IACnB;AAEA,UAAM,YAAY,CAAC,cAAc,UAAU,SAAS,YAAY;AAEhE,qBAAM,OAAO,UAAU,UAAQ,CAAC,UAAU,QAAQ,KAAK,IAAI,CAAC;AAG5D,eAAW,QAAQ,OAAO,cAAc;AACvC,eAAS,KAAK,EAAE,QAAQ,OAAO,aAAa,IAAI,EAAE,QAAQ,MAAM,OAAO,aAAa,IAAI,EAAE,MAAM,MAAM,aAAa,CAAC;AAAA,IACrH;AAEA,WAAO,WAAW,mBAAmB,KAAK,UAAU,QAAQ,IAAI;AAChE,WAAO,OAAO;AAAA,EACf;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,QAAgB;AAC1B,UAAM,QAAoB,CAAC;AAC3B,UAAM,CAAC,cAAc,iBAAiB,cAAc,IAAI,OAAO,MAAM,GAAG;AACxE,UAAM,YAAY,CAAC;AACnB,eAAW,QAAQ,MAAM,MAAM,OAAO,GAAG;AACxC,UAAI,CAAC,MAAM,UAAU,KAAK,SAAS;AAAW;AAC9C,UAAI,KAAK,SAAS;AAAU;AAC5B,UAAI,gBAAgB,iBAAiB,KAAK;AAAQ;AAClD,UAAI,cAAc,CAAC,KAAK,SAAS,KAAK,QAAQ;AAAY;AAC1D,UAAI,kBAAkB,KAAK,QAAQ;AAClC,cAAM,WAAW,KAAK,OAAO,GAAG;AAChC,cAAM,WAAW,KAAK,OAAO,GAAG;AAChC,YAAI,CAAC,YAAY,CAAC;AAAU;AAC5B,YAAI,CAAC,SAAS,WAAW,cAAc,KAAK,CAAC,SAAS,WAAW,cAAc;AAAG;AAAA,MACnF;AACA,YAAM,KAAK,IAAI;AAAA,IAChB;AAEA,UAAM,YAAmD,CAAC;AAC1D,aAAS,IAAI,MAAM,SAAS,GAAG,KAAK,MAAM,SAAS,OAAO,KAAK,GAAG,KAAK;AACtE,YAAM,OAAO,MAAM,CAAC;AACpB,YAAM,WAA4B,CAAC;AACnC,UAAI,KAAK,UAAU,KAAK,QAAQ;AAC/B,YAAI,KAAK,OAAO;AAAI,mBAAS,KAAK,KAAK,OAAO,GAAG;AACjD,YAAI,KAAK,OAAO;AAAI,mBAAS,KAAK,KAAK,OAAO,GAAG;AACjD,YAAI,KAAK;AAAM,mBAAS,SAAS;AACjC,YAAI,KAAK;AAAO,mBAAS,SAAS,KAAK,MAAM,KAAK,KAAK;AAAA,MACxD;AACA,UAAI,CAAC,SAAS,MAAM,CAAC,SAAS;AAAI;AAClC,gBAAU,KAAK,MAAM,IAAI;AAAA,IAC1B;AACA,WAAO;AAAA,EACR;AAAA,EACA,SAAS,MAAY;AACpB,UAAM,YAKF;AAAA,MACH,MAAM,CAAC;AAAA,MACP,eAAe,OAAO,OAAO,kCAAa,YAAY;AAAA,MACtD,WAAW,MAAM;AAAA,MACjB,aAAa,KAAK;AAAA,IACnB;AACA,eAAW,QAAQ,KAAK,WAAW;AAClC,UAAI,CAAC;AAAM;AACX,UAAI,KAAK;AAAQ;AACjB,UACC,KAAK,SAAS,WACb,KAAK,SAAS,aAAa,CAAE,CAAC,UAAU,OAAO,EAAU,SAAS,KAAK,SAAS,SAAS,KACzF,KAAK,SAAS,cAAc,WAAW,KAAK,cAAc;AAC1D;AACF,YAAM,WAA0B;AAAA,QAC/B,OAAO,KAAK;AAAA,QACZ,MAAM,KAAK,SAAS,QAAQ;AAAA,QAC5B,WAAW,KAAK;AAAA,QAChB,SAAS,KAAK,SAAS,UACrB,kCAAa,aAAa,KAAK,SAAS,OAAO,KAAK,KAAK,SAAS,UAAW;AAAA,QAC/E,SAAS,CAAC,KAAK,SAAS,YAAY,SAAY,KAAK,SAAS;AAAA,MAC/D;AACA,YAAM,WAAW,KAAK,YAAY,EAAE,IAAI,OAAK,EAAE,KAAK;AACpD,UAAI,SAAS;AAAQ,iBAAS,WAAW;AACzC,UAAI,KAAK,SAAS;AAAW,iBAAS,YAAY,KAAK,SAAS;AAEhE,gBAAU,KAAK,KAAK,QAAQ;AAAA,IAC7B;AACA,WAAO;AAAA,EACR;AAAA,EACA,QAAQ,SAAiB;AACxB,YAAQ,cAAc,IAAI,OAAO;AAAA,EAClC;AAAA,EACA,YAAY,OAAe;AAC1B,UAAM,KAAK,KAAK,KAAK;AACrB,QAAI,CAAC,WAAW,SAAS,UAAU,eAAe,QAAQ,OAAO,QAAQ,EAAE,SAAS,EAAE,GAAG;AACxF,aAAO;AAAA,IACR;AACA,QAAI,MAAM,MAAM,IAAI,EAAE;AAAG,aAAO;AAEhC,UAAM,WAAW;AAAA,MAChB;AAAA,MACA,MAAM,CAAC;AAAA,MACP,cAAc,KAAK,IAAI;AAAA,IACxB;AACA,UAAM,OAAO,MAAM,eAAe,IAAI,OAAO,QAAQ;AACrD,QAAI,OAAO;AAAS,YAAM,QAAQ;AAClC,SAAK,aAAa,KAAK,QAAQ;AAC/B,SAAK,UAAU,KAAK,IAAI;AACxB,SAAK,kBAAkB;AACvB,WAAO;AAAA,EACR;AAAA,EAEA,eAAe,QAAgB;AAE9B,UAAM,aAAa,UAAU,KAAK,IAAI,QAAQ,IAAI,MAAM,EAAE,IAAI;AAC9D,QAAI,YAAY,KAAK;AACrB,QAAI;AACJ,OAAG;AACF,eAAS,GAAG,aAAa,EAAE;AAAA,IAC5B,SAAS,MAAM,MAAM,IAAI,MAAM;AAE/B,SAAK,aAAa;AAClB,SAAK,cAAc;AACnB,WAAO;AAAA,EACR;AAAA,EAEA,mBAAmB,SAAiB,MAAgB,SAAoB;AACvE,eAAW,UAAU,SAAS;AAC7B,UAAI,OAAO,eAAe,QAAQ;AACjC,eAAO,cAAc,QAAQ;AAAA,MAC9B;AAAA,IACD;AACA,QAAI,OAAO,eAAe;AACzB,UAAI,OAAO,OAAO,kBAAkB,UAAU;AAC7C,eAAO,gBAAgB,CAAC,OAAO,aAAa;AAAA,MAC7C,WAAW,OAAO,kBAAkB,MAAM;AACzC,eAAO,gBAAgB,CAAC,OAAO;AAAA,MAChC;AACA,iBAAW,UAAU,OAAO,eAAe;AAC1C,cAAM,aAAa,MAAM,IAAI,MAAM;AACnC,YAAI,YAAY;AACf,gBAAM,gBAAgB,QAAQ,IAAI,OAAK,EAAE,YAAY,CAAC,EAAE,KAAK,GAAG;AAChE,qBACE,IAAI,MAAM,KAAK,UAAU,eAAe,EACxC,OAAO;AAAA,QACV;AAAA,MACD;AAAA,IACD;AACA,QAAI,OAAO,eAAe,QAAQ,OAAO;AACxC,YAAM,oBAAoB,QAAQ,IAAI,OAAK,GAAG,EAAE,OAAO,EAAE;AAAA,CAAY,EAAE,KAAK,EAAE;AAC9E,WAAK,KAAK,YAAY,MAAM,iBAAiB;AAAA,IAC9C;AACA,eAAW,UAAU,SAAS;AAC7B,WAAK,YAAY,iBAAiB,QAAQ,IAAI;AAAA,IAC/C;AAAA,EACD;AAAA,EAEA,mBAAmB,IAAY;AAC9B,SAAK,KAAK,EAAE;AACZ,UAAM,OAAO,MAAM,IAAI,EAAE;AACzB,QAAI,CAAC;AAAM,aAAO;AAClB,QAAI,CAAC,KAAK;AAAS,aAAO;AAK1B,aAAS,IAAI,KAAK,aAAa,SAAS,GAAG,KAAK,GAAG,KAAK;AACvD,UAAI,OAAO,KAAK,KAAK,aAAa,CAAC,EAAE,KAAK,GAAG;AAC5C,aAAK,aAAa,OAAO,GAAG,CAAC;AAC7B,aAAK,kBAAkB;AACvB;AAAA,MACD;AAAA,IACD;AACA,SAAK,UAAU;AACf,WAAO;AAAA,EACR;AAAA,EACA,eAAe,IAAY;AAC1B,SAAK,KAAK,EAAE;AACZ,QAAI,CAAC,MAAM,MAAM,IAAI,EAAE;AAAG,aAAO;AACjC,aAAS,IAAI,KAAK,UAAU,SAAS,GAAG,KAAK,GAAG,KAAK;AACpD,UAAI,OAAO,KAAK,UAAU,CAAC,EAAE,QAAQ;AACpC,aAAK,UAAU,OAAO,GAAG,CAAC;AAC1B;AAAA,MACD;AAAA,IACD;AAAA,EACD;AAAA,EACA,eAAe,IAAY;AAC1B,SAAK,KAAK,EAAE;AACZ,UAAM,OAAO,MAAM,IAAI,EAAE;AACzB,QAAI,CAAC;AAAM,aAAO;AAClB,SAAK,QAAQ;AACb,WAAO;AAAA,EACR;AAAA,EACA,cAAc,MAAY,YAAwB;AAGjD,QAAI,gBAAgB;AACpB,eAAW,YAAY,KAAK,cAAc;AACzC,WAAK,SAAS,UAAU,UAAU;AAClC,UAAI,aAAa;AAAS,wBAAgB;AAAA,IAC3C;AACA,QAAI,CAAC,iBAAiB,OAAO,aAAa;AAAY,WAAK,KAAK;AAAA,QAAiB;AAAA,EAClF;AAAA,EACA,cAAc,MAAY,YAAyB;AAClD,QAAI,CAAC,KAAK;AAAO;AACjB,aAAS,CAAC,GAAG,MAAM,KAAK,KAAK,sBAAsB,QAAQ,GAAG;AAC7D,YAAM,OAAO,MAAM,IAAI,MAAM;AAC7B,UAAI,CAAC,MAAM;AACV,aAAK,sBAAsB,OAAO,GAAG,CAAC;AACtC;AACA;AAAA,MACD;AACA,UAAI,KAAK,aAAa,IAAI,GAAG;AAC5B,aAAK,SAAS,KAAK,QAAQ,UAAU;AAAA,MACtC;AAAA,IACD;AACA,eAAW,QAAQ,KAAK,aAAa;AACpC,UAAI,KAAK,WAAW;AACnB,cAAM,YAAY,KAAK,UAAU,MAAM,GAAG;AAC1C,mBAAW,YAAY,WAAW;AACjC,eAAK,KAAK,YAAY,UAAU,IAAI;AAAA,QACrC;AACA,aAAK,YAAY;AAAA,MAClB;AAAA,IACD;AAAA,EACD;AAAA,EACA,cAAc,MAAY,YAAwB;AACjD,eAAW,KAAK,KAAK,kBAAkB,IAAI,OAAO,KAAK,iBAAiB,KAAK,cAAc;AAC3F,QAAI,MAAM,MAAM,OAAO,KAAK,UAAU;AACrC,WAAK,WAAW,MAAM,MAAM;AAC5B,WAAK,eAAe,KAAK,IAAI;AAAA,IAC9B;AAAA,EACD;AAAA,EACA,cAAc,MAAoB,MAAM,OAAO,OAAO;AACrD,QAAI,KAAK,YAAY;AAAK;AAC1B,UAAM,UAAU,MAAM,IAAI,aAAa;AACvC,UAAM,QAAS,MAAM,iBAAM,WAAW,IAAI,KAAM,EAAE,MAAM;AAAA,CAAI,EAAE,MAAM,GAAG,CAAC,EAAE,KAAK,QAAQ,IAAI;AAC3F,eAAW,CAAC,IAAI,OAAO,KAAK,MAAM,OAAO;AACxC,UAAI,KAAK;AACR,YAAI,OAAO,WAAW,OAAO,iBAAkB,CAAC,WAAW,OAAO,SAAU;AAC3E,kBAAQ,OAAO,qFAAqF,6CAA6C;AACjJ,kBAAQ,OAAO,uGAAuG;AACtH,kBAAQ,OAAO;AAAA,QAChB,OAAO;AACN,kBAAQ,OAAO,iKAAiK,EAAE,OAAO;AAAA,QAC1L;AAAA,MACD,OAAO;AACN,gBAAQ,OAAO,yLAAyL,EAAE,OAAO;AAAA,MAClN;AACA,YAAM,OAAO,QAAQ;AAErB,UAAI,CAAC,QAAQ,MAAM,SAAS,OAAO,KAAK,MAAM,UAAU,cAAc,CAAC,KAAK,OAAO;AAElF,aAAK,MAAM,MAAM;AACjB,YAAI,QAAQ,SAAS,YAAY,KAAK;AACrC,kBAAQ,SAAS,UAAU;AAC3B,kBAAQ,OAAO,qHAAqH,EAAE,OAAO;AAAA,QAC9I;AAAA,MACD;AAAA,IACD;AACA,eAAW,QAAQ,MAAM,MAAM,OAAO,GAAG;AACxC,WAAK,KAAK,SAAS,KAAK,YAAY,KAAK,mMAAmM;AAAA,IAC7O;AAEA,SAAK,WAAW;AAChB,SAAK,cAAc;AACnB,SAAK,oBAAoB,KAAK,IAAI;AAAA,EACnC;AAAA,EACA,uBAAuB;AACtB,UAAM,eAAyB,CAAC,eAAe,SAAS,YAAY;AACpE,QAAI,OAAO,iBAAiB;AAAW,aAAO,eAAe;AAE7D,QAAI,OAAO,gBAAgB,MAAM,OAAO,aAAa,QAAQ,MAAM,OAAO,gBAAgB,GAAG;AAG5F,UAAI,QAAQ,kBAAkB;AAC7B,aAAK;AAAA,UACJ;AAAA,UACA;AAAA,QACD;AACA;AAAA,MACD;AAGA,WAAK;AAAA,QACJ;AAAA,QACA;AAAA,MACD;AAGA,iBAAW,MAAM;AAChB,YAAI,OAAO,gBAAgB,MAAM,OAAO,aAAa,MAAM;AAE1D,kBAAQ,KAAK;AAAA,QACd,OAAO;AACN,eAAK;AAAA,YACJ;AAAA,YACA;AAAA,UACD;AAAA,QACD;AAAA,MACD,GAAG,KAAK,GAAI;AAAA,IACb;AAAA,EACD;AAAA,EACA,YAAY,OAAiB,SAAiB;AAC7C,QAAI,CAAC,SAAS,CAAC;AAAS;AACxB,eAAW,UAAU,OAAO;AAC3B,YAAM,UAAU,MAAM,IAAI,MAAM;AAChC,UAAI;AAAS,gBAAQ,IAAI,OAAO,EAAE,OAAO;AAAA,IAC1C;AAAA,EACD;AAAA,EACA,YAAY,KAAqB,UAAU,cAAc;AACxD,UAAM,OAAO,KAAK,IAAI;AACtB,QAAI,OAAO,KAAK,oBAAoB,uBAAuB;AAC1D;AAAA,IACD;AACA,SAAK,oBAAoB;AAEzB,UAAM,QAAQ,OAAO,QAAQ,WAAW,MAAM,KAAK,SAAS,KAAK,WAAW,KAAK,QAAQ;AACzF,UAAM,CAAC,YAAY,SAAS,IAAI,iBAAM,WAAW,iBAAM,WAAW,KAAK,GAAG,QAAQ;AAClF,QAAI,YAAY,MAAM,0BAA0B;AAChD,QAAI;AAAW,kBAAY,sCAAsC,sBAAsB;AAEvF,QAAI,eAAe,oCAAoC;AACvD,QAAI,sBAAsB;AAE1B,UAAM,iBAAiB,MAAM,IAAI,YAAY;AAE7C,QAAI,iBAAiB,MAAM,SAAS,SAAS;AAC7C,eAAW,QAAS,OAAO,qBAAqB,CAAC,GAAI;AACpD,UAAI,OAAO,SAAS,WAAW,MAAM,SAAS,IAAI,IAAI,KAAK,KAAK,KAAK,GAAG;AACvE,yBAAiB;AACjB;AAAA,MACD;AAAA,IACD;AAEA,QAAI,gBAAgB;AACnB,UAAI,gBAAgB;AACnB,8BAAsB;AACtB,uBAAe,uCAAuC;AAAA,MACvD,OAAO;AACN,uBAAe,uCAAuC;AAAA,MACvD;AAAA,IACD;AACA,UAAM,UAAU,MAAM,IAAI,aAAa;AACvC,QAAI,SAAS;AACZ,cAAQ,IAAI,YAAY,EAAE,OAAO;AAAA,IAClC,OAAO;AACN,YAAM,OAAO,IAAI,YAAY,EAAE,OAAO;AACtC,YAAM,IAAI,OAAO,GAAG,IAAI,YAAY,EAAE,OAAO;AAAA,IAC9C;AACA,QAAI,qBAAqB;AACxB,qBAAgB,IAAI,mBAAmB,EAAE,OAAO;AAAA,IACjD;AAAA,EACD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,qBAAqB,QAAY;AAChC,UAAM,WAAW,CAAC;AAClB,eAAW,CAAC,IAAI,OAAO,KAAK,MAAM,OAAO;AACxC,UAAI,QAAQ,SAAS,cAAc,QAAQ,KAAK,IAAI,MAAM,MAAM,MAAM,aAAa;AAClF,gBAAQ,QAAQ;AAAA,MACjB,OAAO;AACN,YAAI,QAAQ,SAAS,aAAa,QAAQ,UAAU,CAAC,QAAQ,SAAS;AACrE;AAAA,QACD;AAEA,YAAI,QAAQ,KAAK,IAAI,MAAM,GAAG;AAC7B,cAAI,WAAW,QAAQ,KAAK,IAAI,MAAM;AACtC,cAAI,aAAa;AAAK,uBAAW;AACjC,mBAAS,KAAK,GAAG,WAAW,IAAI;AAAA,QACjC;AAAA,MACD;AAAA,IACD;AACA,WAAO;AAAA,EACR;AACD;AAEO,MAAM,iBAAiB,UAAU;AAAA,EAAjC;AAAA;AAGN;AAAA;AAAA,SAAS,SAAS;AAClB,SAAS,SAAS;AAClB,SAAS,OAAO;AAAA;AACjB;AAEO,MAAM,iBAAiB,UAAU;AAAA,EAgBvC,YAAY,QAAgB,OAAe,SAAoD;AAC9F,YAAQ,aAAa;AACrB,YAAQ,iBAAiB;AACzB,YAAQ,iBAAiB;AACzB,UAAM,QAAQ,OAAO,OAAO;AAC5B,SAAK,cAAc,CAAC,CAAC,OAAO;AAC5B,SAAK,SAAS,UAAW,OAAO,iBAAiB;AAEjD,SAAK,OAAO;AAEZ,SAAK,SAAS,QAAQ,UAAU;AAGhC,SAAK,OAAO,QAAQ,QAAQ;AAC5B,SAAK,UAAW,QAAgB,UAAU,KAAK,MAAM,QAAQ,IAAI;AAEjE,SAAK,KAAK,QAAQ,UAAU,CAAC,GAAG,QAAQ;AACxC,SAAK,KAAK,QAAQ,UAAU,CAAC,GAAG,QAAQ;AACxC,SAAK,KAAK,QAAQ,UAAU,CAAC,GAAG,QAAQ;AACxC,SAAK,KAAK,QAAQ,UAAU,CAAC,GAAG,QAAQ;AAExC,SAAK,QAAQ,QAAQ,UAAU,OAAO,IAAI,QAAQ,SAAS;AAE3D,SAAK,SAAS;AACd,SAAK,SAAS;AACd,SAAK,OAAO;AAEZ,SAAK,cAAc;AAEnB,SAAK,SAAS;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO,UAAkC,GAAG;AAC3C,WAAO,KAAK,IAAI,cAAc,OAAO;AAAA,EACtC;AAAA,EACA,cAAc,MAAY;AACzB,QAAI,EAAE,KAAK,MAAM,KAAK,KAAK;AAAc,aAAO,KAAK,OAAO;AAC5D,WAAO,KAAK,OAAO,KAAK,KAAK,YAAY,KAAK,EAAE,EAAE,GAAQ;AAAA,EAC3D;AAAA,EACA,OAAO,cAA2B,MAAM;AACvC,QAAI,CAAC,KAAK,IAAI,gBAAgB;AAAQ;AAEtC,QAAI,KAAK,WAAW;AACnB,cAAQ,iBAAiB,KAAK,QAAQ,IAAI,KAAK;AAAA,EAAW,KAAK,IAAI,gBAAgB,KAAK,IAAI,GAAG;AAAA,IAChG;AACA,SAAK,IAAI,kBAAkB,CAAC;AAE5B,SAAK,gBAAgB;AAAA,EACtB;AAAA,EACA,kBAAkB;AAEjB,QAAI,CAAC,KAAK,WAAW;AACpB,UAAI,KAAK;AAAa,qBAAa,KAAK,WAAW;AACnD,WAAK,cAAc,WAAW,MAAM,KAAK,OAAO,GAAG,wBAAwB;AAAA,IAC5E,OAAO;AACN,UAAI,KAAK;AAAa,qBAAa,KAAK,WAAW;AACnD,WAAK,cAAc,WAAW,MAAM,KAAK,OAAO,GAAG,2BAA2B;AAAA,IAC/E;AAAA,EACD;AAAA,EACA,eAAe,MAAmB;AACjC,QAAI,CAAC,MAAM;AACV,WAAK,cAAc;AAAA,IACpB,WAAW,CAAC,KAAK,eAAe,KAAK,gBAAgB,KAAK,MAAM,KAAK,KAAK,IAAI,KAAK,EAAE,MAAM,MAAM,eAAe;AAC/G,WAAK,cAAc,KAAK;AAAA,IACzB,OAAO;AACN,aAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA,UAAU,MAAY,YAAwB;AAC7C,SAAK,SAAS,YAAY,0BAA0B,KAAK,QAAQ,OAAO,KAAK,cAAc,IAAI,CAAC;AAChG,SAAK,MAAM,YAAY,MAAM,UAAU;AAAA,EACxC;AAAA,EACA,OAAO,MAAY,YAAwB;AAC1C,QAAI,CAAC;AAAM,aAAO;AAClB,QAAI,KAAK,MAAM,KAAK,EAAE;AAAG,aAAO;AAEhC,SAAK,YAAY,oBAAoB,MAAM,MAAM,UAAU;AAC3D,QAAI,KAAK,OAAO;AACf,WAAK,WAAW,KAAK,KAAK,sBAAsB,IAAI,GAAG,IAAI;AAAA,IAC5D;AAEA,SAAK,MAAM,KAAK,EAAE,IAAI;AACtB,SAAK;AACL,SAAK,iBAAiB,IAAI;AAE1B,SAAK,eAAe,YAAY,MAAM,UAAU;AAChD,SAAK,MAAM,SAAS,MAAM,UAAU;AACpC,SAAK,YAAY,cAAc,MAAM,MAAM,UAAU;AACrD,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,aAAa,MAAa,YAAyB,SAA+C;AAgBvG,UAAM,SAAS,KAAK;AACpB,QAAI,CAAC;AAAQ;AAGb,UAAM,SAAS,IAAI,QAAQ,IAAI,KAAK,QAAQ,IAAI;AAKhD,QAAI,cAAc,CAAC,OAAO,GAAG,SAAS,YAAY;AAClD,QAAI,OAAO,QAAQ,OAAO;AAAO,oBAAc;AAE/C,UAAM,MAAM,KAAK,OAAO,cAAc,IAAI,EAAE;AAC5C,QAAI;AACJ,QAAI,OAAO,SAAS,KAAK;AAAO,eAAS,KAAK;AAC9C,QAAI,EAAE,IAAI,SAAS,IAAI,KAAK,cAAc;AAC1C,UAAM,SAAS,YAAY,mBAAmB,YAAY,YAAY,YAAY;AAClF,QAAI;AAAQ,mBAAa;AACzB,UAAM,YAAY,KAAK,SAAS,aAAa,KAAK;AAClD,UAAM,SAAS,YAAY,SAAS,KACnC,YAAY,mBAAoB,KAAa,eAAe,IAC5D,YAAY,IACZ;AACD,QAAI,aAAa,WAAW,IAAI;AAC/B,iBAAW,uBAAQ,iBAAiB;AAAA,IACrC;AACA,QAAI,OAAO,gBAAgB,QAAQ,WAAW,IAAI;AACjD,aAAO,cAAc;AAAA,IACtB,OAAO;AACN,aAAO,cAAc;AAAA,IACtB;AAKA,QAAI,uBAAQ,IAAI;AACf,YAAM,eAAe,OAAO,aAAa,aAAa,KAAK,GAAG,OAAO,YAAY;AACjF,UAAI;AACH,cAAMA,UAAS,MAAM,uBAAQ,IAAI;AAAA,UAChC,IAAI;AAAA,UACJ;AAAA,UACA,SAAS,OAAO,QAAQ,IAAI,OAAK,EAAE,IAAI;AAAA,UACvC,QAAQ,OAAO;AAAA,UACf,QAAQ,UAAU;AAAA,UAClB,SAAS;AAAA,UACT;AAAA,UACA,UAAU,OAAO,UAAU,KAAK,IAAI,KAAK;AAAA,UACzC,YAAY,KAAK,MAAM,KAAK,IAAI,IAAI,GAAI;AAAA,QACzC,CAAC;AACD,cAAMC,OAAM,WAAW,OAAO,OAAO,WAAWD;AAChD,oBAAY;AAAA,UACX,yGACuCC,yBAAwBA,6BAC3CA;AAAA,QACrB;AAAA,MACD,SAAS,GAAP;AACD,oBAAY,MAAM,mCAAmC,GAAG;AACxD,cAAM;AAAA,MACP;AACA;AAAA,IACD;AAIA,UAAM,CAAC,MAAM,IAAI,MAAM,YAAY,QAAQ,aAAa;AAAA,MACvD;AAAA,MACA;AAAA,MACA,SAAS,OAAO,QAAQ,IAAI,OAAK,EAAE,IAAI,EAAE,KAAK,GAAG;AAAA,MACjD,QAAQ,OAAO;AAAA,MACf;AAAA;AAAA,MACA,QAAQ,WAAW,IAAI,KAAK;AAAA,MAC5B,UAAU,OAAO,UAAU,KAAK,IAAI,KAAK;AAAA,MACzC;AAAA,IACD,CAAC;AACD,QAAI,QAAQ,SAAS;AACpB,kBAAY,MAAM,4BAA4B,OAAO,qCAAqC;AAC1F;AAAA,IACD;AAEA,UAAM,SAAS,QAAQ;AACvB,UAAM,MAAM,WAAW,OAAO,OAAO,WAAW;AAChD,gBAAY;AAAA,MACX,yGACuC,wBAAwB,4BAC3C;AAAA,IACrB;AAAA,EACD;AAAA,EAEA,gBAAgB;AACf,QAAI,CAAC,KAAK,OAAO,SAAS,IAAI;AAAG,aAAO,EAAE,IAAI,KAAK,OAAO,MAAM,CAAC,GAAG,UAAU,KAAK;AACnF,UAAM,MAAM,KAAK,OAAO,SAAS;AACjC,UAAM,aAAa,KAAK,OAAO,YAAY,KAAK,GAAG;AACnD,WAAO,EAAE,IAAI,KAAK,OAAO,MAAM,GAAG,UAAU,GAAG,UAAU,KAAK,OAAO,MAAM,aAAa,GAAG,GAAG,EAAE;AAAA,EACjG;AACD;AAEA,SAAS,QAAQ,QAA6B;AAC7C,MAAI,OAAO,WAAW,UAAU;AAE/B,SAAK,OAAO,WAAW,SAAS,KAAK,OAAO,WAAW,aAAa,MAAM,OAAO,SAAS,IAAI,GAAG;AAChG,YAAM,OAAO,MAAM,MAAM,IAAI,OAAO,MAAM,GAAG,OAAO,YAAY,GAAG,CAAC,CAAW;AAC/E,UAAI;AAAM,eAAO;AAAA,IAClB;AACA,WAAO,MAAM,MAAM,IAAI,MAAgB;AAAA,EACxC;AACA,SAAO;AACR;AAEO,MAAM,QAAQ;AAAA,EACpB,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMR,OAAO,oBAAI,IAAkB;AAAA,EAC7B,SAAS,oBAAI,IAAoB;AAAA,EAEjC,KAAK;AAAA,EACL,OAAO,MAAgC;AACtC,WAAO,QAAQ,IAAI,KAAK,QAAQ,KAAK,IAAI,CAAC,KAAK,QAAQ,MAAM,QAAQ,IAAI,KAAK,IAAI,CAAC,CAAC;AAAA,EACrF;AAAA,EAEA,eAAe,QAAgB,OAAe,SAAoD;AACjG,QAAI,MAAM,MAAM,IAAI,MAAM;AAAG,YAAM,IAAI,MAAM,QAAQ,uBAAuB;AAC5E,YAAQ,MAAM,sBAAsB,MAAM;AAC1C,UAAM,OAAO,IAAI,SAAS,QAAQ,OAAO,OAAO;AAChD,UAAM,MAAM,IAAI,QAAQ,IAAI;AAC5B,WAAO;AAAA,EACR;AAAA,EACA,eAAe,QAAgB,OAAe,SAAgC;AAC7E,QAAI,MAAM,MAAM,IAAI,MAAM;AAAG,YAAM,IAAI,MAAM,QAAQ,uBAAuB;AAC5E,UAAM,OAAiB,IAAK,UAAkB,QAAQ,OAAO,OAAO;AACpE,UAAM,MAAM,IAAI,QAAQ,IAAI;AAC5B,WAAO;AAAA,EACR;AAAA;AAAA;AAAA;AAAA;AAAA,EAKA,aAAa,SAAoD;AAChE,UAAM,UAAU,QAAQ,QAAQ,IAAI,YAAU,OAAO,IAAI;AACzD,UAAM,SAAS,IAAI,QAAQ,IAAI,QAAQ,MAAM;AAC7C,QAAI,QAAQ,SAAS,OAAO,aAAa;AACxC,YAAM,IAAI,MAAM,GAAG,QAAQ,qDAAqD,OAAO,4BAA4B;AAAA,IACpH;AACA,QAAI,IAAI,IAAI,OAAO,EAAE,OAAO,QAAQ,QAAQ;AAC3C,YAAM,IAAI,MAAM,iCAAiC;AAAA,IAClD;AAEA,eAAW,QAAQ,SAAS;AAC3B,cAAQ,eAAe,IAAI;AAAA,IAC5B;AAEA,UAAM,WAAW,IAAI,QAAQ,aAAa,MAAM,EAAE,WAAW,IAAI,QAAQ;AAEzE,QAAI,MAAM,OAAO,aAAa,SAAS,YAAY,CAAC,QAAQ,mBAAmB;AAC9E,iBAAW,QAAQ,SAAS;AAC3B,aAAK,MAAM,+CAA+C,kDAAkD;AAAA,MAC7G;AACA,aAAO;AAAA,IACR;AAGA,QAAI,MAAM,OAAO,aAAa,QAAQ,CAAC,QAAQ,mBAAmB;AACjE,iBAAW,QAAQ,SAAS;AAC3B,aAAK,MAAM,6EAA6E;AAAA,MACzF;AACA,aAAO;AAAA,IACR;AAEA,UAAM,YAAY,QAAQ,SAAS,QAAQ,CAAC,EAAE,eAAe,UAAU;AACvE,QAAI,WAAW,IAAI;AACnB,eAAW,QAAQ,SAAS;AAC3B,UAAI,KAAK,eAAe,YAAY,WAAW;AAC9C,oBAAY,SAAS,KAAK,eAAe;AAAA,MAC1C;AACA,WAAK,eAAe,UAAU;AAAA,IAC/B;AAEA,QAAI,aAAa,IAAI,cAAc;AAClC,iBAAW,QAAQ,SAAS;AAC3B,aAAK,MAAM,6CAA6C,UAAU;AAAA,MACnE;AACA,aAAO;AAAA,IACR,WAAW,WAAW;AACrB,cAAQ,eAAe;AAAA,IACxB;AAKA,YAAQ,QAAQ,KAAK,IAAI,CAAC,QAAQ,SAAU,GAAG,CAAC;AAChD,UAAM,KAAK,QAAQ,CAAC;AACpB,UAAM,KAAK,QAAQ,CAAC;AACpB,UAAM,SAAS,KAAK,GAAG,OAAO;AAC9B,UAAM,SAAS,KAAK,GAAG,OAAO;AAC9B,QAAI;AACJ,QAAI,SAAS,QAAQ;AACrB,QAAI,OAAO,aAAa,SAAS;AAChC,kBAAY,QAAQ,mBAAmB;AAAA,IACxC,WAAW,OAAO,aAAa,cAAc;AAE5C,kBAAY,GAAG;AAAA,IAChB,WAAW,YAAY,CAAC,QAAQ,mBAAmB;AAClD,kBAAY,GAAG,cAAc;AAC7B,0BAAW,cAAc,YAAY,OAAO,MAAM,EAAE,MAAM,OAAO;AAAA,IAClE,WAAW,QAAQ,OAAO;AACzB,kBAAY,QAAQ;AAAA,IACrB,OAAO;AACN,kBAAY,GAAG,cAAc;AAAA,IAC9B;AACA,wBAAW,MAAM,OAAO,eAAe,QAAQ,MAAM;AACrD,YAAQ,aAAa;AACrB,UAAM,OAAO,MAAM,eAAe,QAAQ,WAAW,OAAO;AAC5D,QAAI;AACJ,QAAI,QAAQ,qBAAqB,CAAC,UAAU;AAC3C,aAAO,IAAI,8BAAW,MAAM,OAAO;AAAA,IACpC,OAAO;AACN,aAAO,IAAI,qCAAW,MAAM,OAAO;AAAA,IACpC;AACA,SAAK,OAAO;AACZ,QAAI,QAAQ,qBAAqB,KAAK,QAAQ;AAC7C,WAAK,WAAW,KAAK,OAAO,SAAS,aAAa,KAAK;AAAA,IACxD,OAAO;AACN,WAAK,qBAAqB,OAAO;AAAA,IAClC;AAEA,eAAW,KAAK,SAAS;AACxB,UAAI,GAAG;AACN,UAAE,SAAS,IAAI;AACf,gBAAQ,YAAY,EAAE,UAAU,EAAE,IAAI;AAAA,MACvC;AAAA,IACD;AAEA,WAAO;AAAA,EACR;AAAA,EAEA,QAAQ;AAAA,EACR,OAAO;AAAA,EAEP;AAAA,EACA;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EAEV;AAAA,EACA;AAAA,EACA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,IAAI,mBAAAC;AAAA,EAEJ;AACD;", "names": ["fullid", "url", "RoomBattlePM"] }