Pokemon_server / dist /server /chat-plugins /abuse-monitor.js.map
Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
{
"version": 3,
"sources": ["../../../server/chat-plugins/abuse-monitor.ts"],
"sourcesContent": ["/**\n * Neural net chat'filters'.\n * These are in a separate file so that they don't crash the other filters.\n\t * (issues with globals, etc)\n * We use Google's Perspective API to classify messages.\n * @see https://perspectiveapi.com/\n * by Mia.\n * @author mia-pi-git\n */\nimport * as Artemis from '../artemis';\nimport { FS, Utils } from '../../lib';\nimport { Config } from '../config-loader';\nimport { toID } from '../../sim/dex-data';\nimport { getBattleLog, getBattleLinks, HelpTicket } from './helptickets';\nimport type { GlobalPermission } from '../user-groups';\n\nconst WHITELIST = [\"mia\"];\nconst MUTE_DURATION = 7 * 60 * 1000;\nconst DAY = 24 * 60 * 60 * 1000;\nconst STAFF_NOTIF_INTERVAL = 10 * 60 * 1000;\nconst MAX_MODLOG_TIME = 2 * 365 * DAY;\nconst NON_PUNISHMENTS = ['MUTE', 'REPORT'];\nconst NOJOIN_COMMAND_WHITELIST: { [k: string]: string } = {\n\t'lock': '/lock',\n\t'weeklock': '/weeklock',\n\t'warn': '/warn',\n\t'forcerename': '/fr',\n\t'namelock': '/nl',\n\t'weeknamelock': '/wnl',\n};\n\nexport let migrated = global.Chat?.oldPlugins['abuse-monitor']?.migrated || false;\n\nexport const cache: {\n\t[roomid: string]: {\n\t\tusers: Record<string, number>,\n\t\t// can be a string and not string[] if it was added to the object before this patch was done.\n\t\t// todo: move this to just ID[]\n\t\tstaffNotified?: ID | ID[],\n\t\tclaimed?: ID,\n\t\trecommended?: Record<string, { type: string, reason: string }>,\n\t},\n} = (() => {\n\tconst plugin = global.Chat?.oldPlugins['abuse-monitor'];\n\tif (!plugin?.cache) return {};\n\tif (plugin.migrated) return plugin.cache;\n\tfor (const k in plugin.cache) {\n\t\tconst cur = plugin.cache[k];\n\t\tif (typeof cur.recommended?.type === 'string') { // would be object if it was the new entry\n\t\t\t// we cannot feasibly determine who it was (but it __is__ logged in <<abuselog>>, so staff can)\n\t\t\tdelete cur.recommended;\n\t\t}\n\t}\n\tmigrated = true;\n\treturn plugin.cache;\n})();\n\nexport const muted = Chat.oldPlugins['abuse-monitor']?.muted || new WeakMap<Room, WeakMap<User, number>>();\n\nconst defaults: FilterSettings = {\n\tthreshold: 4,\n\tthresholdIncrement: null,\n\tminScore: 0.65,\n\tspecials: {\n\t\tTHREAT: { 0.96: 'MAXIMUM' },\n\t\tIDENTITY_ATTACK: { 0.8: 2 },\n\t\tSEVERE_TOXICITY: { 0.8: 2 },\n\t},\n\treplacements: {},\n\trecommendOnly: true,\n\tpunishments: [\n\t\t{ certainty: 0.93, type: 'IDENTITY_ATTACK', punishment: 'WARN', count: 2 },\n\t],\n};\n\nexport const settings: FilterSettings = (() => {\n\ttry {\n\t\t// accounting for data changes -\n\t\t// make sure we do have the default data in case it's not in the stored data\n\t\treturn { ...defaults, ...JSON.parse(FS('config/chat-plugins/nf.json').readSync()) };\n\t} catch (e: any) {\n\t\tif (e.code !== \"ENOENT\") throw e;\n\t\treturn defaults;\n\t}\n})();\n\nexport const reviews: Record<string, ReviewRequest[]> = (() => {\n\ttry {\n\t\treturn JSON.parse(FS(`config/chat-plugins/artemis-reviews.json`).readSync());\n\t} catch {\n\t\treturn {};\n\t}\n})();\n\n/**\n * Non-core settings - ones that shouldn't be included in /am backups/backup rollbacks/etc.\n * They should stay unless changed via specific command.\n */\nexport const metadata: MetaSettings = (() => {\n\ttry {\n\t\treturn JSON.parse(FS('config/chat-plugins/artemis-metadata.json').readSync());\n\t} catch {\n\t\treturn {};\n\t}\n})();\n\ninterface PunishmentSettings {\n\tcount?: number;\n\tcertainty?: number;\n\ttype?: string;\n\tpunishment: typeof PUNISHMENTS[number];\n\tmodlogCount?: number;\n\tmodlogActions?: string[];\n\t/** Other types of a given certainty needed beyond the primary */\n\tsecondaryTypes?: Record<string, number>;\n\t/** Requires another punishment given to activate. */\n\trequiresPunishment?: boolean;\n}\n\ninterface FilterSettings {\n\tdisabled?: boolean;\n\tthresholdIncrement: { turns: number, amount: number, minTurns?: number } | null;\n\tthreshold: number;\n\tminScore: number;\n\tspecials: { [k: string]: { [k: number]: number | \"MAXIMUM\" } };\n\t/** Replaces [key] with [value] before processing the string. */\n\treplacements: Record<string, string>;\n\tpunishments: PunishmentSettings[];\n\t/** Should it make recommendations, or punish? */\n\trecommendOnly?: boolean;\n}\n\ninterface MetaSettings {\n\t/** {[userid]: entries to ignore[] OR ignore entries after date [string]} */\n\tmodlogIgnores?: Record<string, string | number[]>;\n}\n\ninterface ReviewRequest {\n\tstaff: string;\n\troom: string;\n\tdetails: string;\n\ttime: number;\n\tresolved?: { by: string, time: number, details: string, result: number };\n}\n\n// stolen from chatlog. necessary here, but importing chatlog sucks.\nfunction nextMonth(month: string) {\n\tconst next = new Date(new Date(`${month}-15`).getTime() + 30 * 24 * 60 * 60 * 1000);\n\treturn next.toISOString().slice(0, 7);\n}\n\nfunction isFlaggedUserid(name: string, room: RoomID) {\n\tconst id = toID(name);\n\tconst entry = cache[room]?.staffNotified;\n\tif (!entry) return false;\n\treturn typeof entry === 'string' ? entry === id : entry.includes(id);\n}\n\nfunction visualizePunishmentKey(punishment: PunishmentSettings, key: keyof PunishmentSettings) {\n\tif (key === 'secondaryTypes') {\n\t\tif (!punishment.secondaryTypes) return '';\n\t\tconst keys = Utils.sortBy(Object.keys(punishment.secondaryTypes));\n\t\treturn `${keys.map(k => `${k}: ${punishment.secondaryTypes![k]}`).join(', ')}`;\n\t}\n\treturn punishment[key]?.toString() || \"\";\n}\n\nfunction visualizePunishment(punishment: PunishmentSettings) {\n\treturn Utils\n\t\t.sortBy(Object.keys(punishment))\n\t\t.map(k => `${k}: ${visualizePunishmentKey(punishment, k as keyof PunishmentSettings)}`)\n\t\t.join(', ');\n}\n\nfunction displayResolved(review: ReviewRequest, justSubmitted = false) {\n\tconst user = Users.get(review.staff);\n\tif (!user) return;\n\tconst resolved = review.resolved;\n\tif (!resolved) return;\n\tconst prefix = `|pm|~|${user.getIdentity()}|`;\n\tuser.send(\n\t\tprefix +\n\t\t`Your Artemis review for <<${review.room}>> was resolved by ${resolved.by}` +\n\t\t(justSubmitted ? \".\" : `, ${Chat.toDurationString(Date.now() - resolved.time)} ago.`)\n\t);\n\tif (resolved.details) user.send(prefix + `The response was: \"${resolved.details}\"`);\n\tconst idx = reviews[review.staff].findIndex(r => r.room === review.room);\n\tif (idx > -1) reviews[review.staff].splice(idx, 1);\n\tif (!reviews[review.staff].length) {\n\t\tdelete reviews[review.staff];\n\t}\n\tsaveReviews();\n}\n\nexport const punishmentCache: WeakMap<User, Record<string, number>> = (\n\tChat.oldPlugins['abuse-monitor']?.punishmentCache || new WeakMap()\n);\n\nexport async function searchModlog(\n\tquery: { user: ID, ip?: string | string[], actions?: string[] }\n) {\n\tconst userObj = Users.get(query.user);\n\tif (userObj) {\n\t\tconst data = punishmentCache.get(userObj);\n\t\tif (data) {\n\t\t\tlet sum = 0;\n\t\t\tfor (const action of (query.actions || Object.keys(data))) {\n\t\t\t\tsum += (data[action] || 0);\n\t\t\t}\n\t\t\treturn sum;\n\t\t}\n\t}\n\tconst search: import('../modlog').ModlogSearch = {\n\t\tuser: [],\n\t\tip: [],\n\t\tnote: [],\n\t\tactionTaker: [],\n\t\taction: [],\n\t};\n\tif (query.user) search.user.push({ search: query.user, isExact: true });\n\tif (query.ip) {\n\t\tif (!Array.isArray(query.ip)) query.ip = [query.ip];\n\t\tfor (const ip of query.ip) {\n\t\t\tsearch.ip.push({ search: ip });\n\t\t}\n\t}\n\tconst modlog = await Rooms.Modlog.search('global', search);\n\tif (!modlog) return 0;\n\tconst ignores = metadata.modlogIgnores?.[query.user];\n\tif (userObj) {\n\t\tconst validTypes = Array.from(Punishments.punishmentTypes.keys());\n\t\tconst cacheEntry: Record<string, number> = {};\n\t\tfor (const entry of modlog.results) {\n\t\t\tif ((Date.now() - entry.time) > MAX_MODLOG_TIME) continue;\n\t\t\tif (!validTypes.some(k => entry.action.endsWith(k))) continue;\n\t\t\tif (!cacheEntry[entry.action]) cacheEntry[entry.action] = 0;\n\t\t\tif (ignores) {\n\t\t\t\tif (\n\t\t\t\t\ttypeof ignores === 'string' &&\n\t\t\t\t\tnew Date(ignores).getTime() < new Date(entry.time).getTime()\n\t\t\t\t) {\n\t\t\t\t\tcontinue;\n\t\t\t\t} else if (Array.isArray(ignores) && ignores.includes(entry.entryID)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcacheEntry[entry.action]++;\n\t\t}\n\t\tpunishmentCache.set(userObj, cacheEntry);\n\t\tlet sum = 0;\n\t\tfor (const action of (query.actions || Object.keys(cacheEntry))) {\n\t\t\tsum += (cacheEntry[action] || 0);\n\t\t}\n\t\treturn sum;\n\t}\n\tif (query.actions) {\n\t\t// have to do this because using actions in the search treats it like\n\t\t// AND action = foo AND action = bar\n\t\tfor (const [i, entry] of modlog.results.entries()) {\n\t\t\tif (!query.actions.includes(entry.action)) {\n\t\t\t\tmodlog.results.splice(i, 1);\n\t\t\t}\n\t\t}\n\t}\n\treturn modlog.results.length;\n}\n\nexport const classifier = new Artemis.RemoteClassifier();\n\nexport async function runActions(user: User, room: GameRoom, message: string, response: Record<string, number>) {\n\tconst keys = Utils.sortBy(Object.keys(response), k => -response[k]);\n\tconst recommended: [string, string, boolean][] = [];\n\tconst roomRecord = cache[room.roomid];\n\tconst prevRecommend = roomRecord?.recommended?.[user.id];\n\tfor (const punishment of settings.punishments) {\n\t\tif (prevRecommend?.type) { // avoid making extra db queries by frontloading this check\n\t\t\tif (PUNISHMENTS.indexOf(punishment.punishment) <= PUNISHMENTS.indexOf(prevRecommend?.type)) continue;\n\t\t}\n\t\tfor (const type of keys) {\n\t\t\tconst num = response[type];\n\t\t\tif (punishment.type && punishment.type !== type) continue;\n\t\t\tif (punishment.certainty && punishment.certainty > num) continue;\n\t\t\tif (punishment.modlogCount) {\n\t\t\t\t// todo: support configuration for ip searches\n\t\t\t\tconst modlog = await searchModlog({\n\t\t\t\t\tuser: user.id,\n\t\t\t\t\tactions: punishment.modlogActions,\n\t\t\t\t});\n\t\t\t\tif (modlog < punishment.modlogCount) continue;\n\t\t\t}\n\t\t\tif (punishment.secondaryTypes) {\n\t\t\t\tlet matches = 0;\n\t\t\t\tfor (const curType in punishment.secondaryTypes) {\n\t\t\t\t\tif (response[curType] >= punishment.secondaryTypes[curType]) matches++;\n\t\t\t\t}\n\t\t\t\tif (matches < Object.keys(punishment.secondaryTypes).length) continue;\n\t\t\t}\n\t\t\tif (punishment.count) {\n\t\t\t\tlet hits = await Chat.database.all(\n\t\t\t\t\t`SELECT * FROM perspective_flags WHERE userid = ? AND type = ? AND certainty >= ?`,\n\t\t\t\t\t[user.id, type, num]\n\t\t\t\t);\n\t\t\t\t// filtering out old hits. 5-17-2022 perspective did an update that seriously changed scoring\n\t\t\t\t// so old hits are unreliable.\n\t\t\t\t// yes i know this is horrible but i'm not writing a framework for this because\n\t\t\t\t// i should never need to do it again\n\t\t\t\thits = hits.filter(f => {\n\t\t\t\t\tconst date = new Date(f.time);\n\t\t\t\t\tif (date.getFullYear() < 2022) return false;\n\t\t\t\t\treturn !(date.getFullYear() === 2022 && date.getMonth() <= 4 && date.getDate() <= 17);\n\t\t\t\t});\n\t\t\t\tif (hits.length < punishment.count) continue;\n\t\t\t}\n\t\t\trecommended.push([punishment.punishment, type, !!punishment.requiresPunishment]);\n\t\t}\n\t}\n\tif (recommended.length) {\n\t\tUtils.sortBy(recommended, ([punishment]) => -PUNISHMENTS.indexOf(punishment));\n\t\tif (recommended.filter(k => !NON_PUNISHMENTS.includes(k[1])).every(k => k[2])) {\n\t\t\t// requiresPunishment is for upgrading. if every one is an upgrade and\n\t\t\t// there's no independent punishment, do not upgrade it\n\t\t\treturn;\n\t\t}\n\t\t// go by most severe\n\t\tconst [punishment, reason] = recommended[0];\n\t\tif (roomRecord) {\n\t\t\tif (!roomRecord.recommended) roomRecord.recommended = {};\n\t\t\troomRecord.recommended[user.id] = { type: punishment, reason: reason.replace(/_/g, ' ').toLowerCase() };\n\t\t}\n\t\tif (user.trusted) {\n\t\t\t// force just logging for any sort of punishment. requested by staff\n\t\t\tRooms.get('staff')?.add(\n\t\t\t\t`|c|~|/log [Artemis] ${getViewLink(room.roomid)} ${punishment} recommended for trusted user ${user.id}` +\n\t\t\t\t`${user.trusted !== user.id ? ` [${user.trusted}]` : ''} `\n\t\t\t).update();\n\t\t\treturn; // we want nothing else to be executed. staff want trusted users to be reviewed manually for now\n\t\t}\n\n\t\tconst result = await punishmentHandlers[toID(punishment)]?.(user, room, response, message);\n\t\twriteStats('punishments', {\n\t\t\tpunishment,\n\t\t\tuserid: user.id,\n\t\t\troomid: room.roomid,\n\t\t\ttimestamp: Date.now(),\n\t\t});\n\t\tif (result !== false) {\n\t\t\t// returning false means not to close the 'ticket'\n\t\t\tconst notified = roomRecord?.staffNotified;\n\t\t\tif (notified) {\n\t\t\t\tif (typeof notified === 'string') {\n\t\t\t\t\tif (notified === user.id) delete roomRecord.staffNotified;\n\t\t\t\t} else {\n\t\t\t\t\tnotified.splice(notified.indexOf(user.id), 1);\n\t\t\t\t\tif (!notified.length) {\n\t\t\t\t\t\tdelete cache[room.roomid].staffNotified;\n\t\t\t\t\t\tvoid Chat.database.run(\n\t\t\t\t\t\t\t`INSERT INTO perspective_stats (staff, roomid, result, timestamp) VALUES ($staff, $roomid, $result, $timestamp) ` +\n\t\t\t\t\t\t\t`ON CONFLICT (roomid) DO UPDATE SET result = $result, timestamp = $timestamp`,\n\t\t\t\t\t\t\t// todo: maybe use 3 to indicate punishment?\n\t\t\t\t\t\t\t{ staff: '', roomid: room.roomid, result: 1, timestamp: Date.now() }\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tdelete roomRecord?.users[user.id]; // user has been punished, reset their counter\n\t\t\t// keep the cache object only if there are other users in it, since they still need to be monitored\n\t\t\tif (roomRecord && !Object.keys(roomRecord.users).length) {\n\t\t\t\tdelete cache[room.roomid];\n\t\t\t}\n\t\t\tnotifyStaff();\n\t\t}\n\t}\n}\n\nfunction globalModlog(\n\taction: string, user: User | ID | null, note: string, roomid?: string | GameRoom\n) {\n\tif (typeof roomid === 'object') roomid = roomid.roomid;\n\tuser = Users.get(user) || user;\n\tvoid Rooms.Modlog.write(roomid || 'global', {\n\t\tisGlobal: true,\n\t\taction,\n\t\tip: user && typeof user === 'object' ? user.latestIp : undefined,\n\t\tuserid: toID(user) || undefined,\n\t\tloggedBy: 'artemis' as ID,\n\t\tnote,\n\t});\n}\n\nconst getViewLink = (roomid: RoomID) => `<<view-battlechat-${roomid.replace('battle-', '')}>>`;\n\nfunction addGlobalModAction(message: string, room: GameRoom) {\n\troom.add(`|c|~|/log ${message}`).update();\n\tRooms.get(`staff`)?.add(`|c|~|/log ${getViewLink(room.roomid)} ${message}`).update();\n}\n\nconst DISCLAIMER = (\n\t'<small>This action was done automatically.' +\n\t' Want to learn more about the AI? ' +\n\t'<a href=\"https://www.smogon.com/forums/threads/3570628/#post-9056769\">Visit the information thread</a>.</small>'\n);\n\nexport async function lock(user: User, room: GameRoom, reason: string, isWeek?: boolean) {\n\tif (settings.recommendOnly) {\n\t\tRooms.get('staff')?.add(\n\t\t\t`|c|~|/log [Artemis] ${getViewLink(room.roomid)} ${isWeek ? \"WEEK\" : \"\"}LOCK recommended for ${user.id}`\n\t\t).update();\n\t\troom.hideText([user.id], undefined, true);\n\t\treturn false;\n\t}\n\tconst affected = await Punishments.lock(\n\t\tuser,\n\t\tisWeek ? Date.now() + 7 * 24 * 60 * 60 * 1000 : null,\n\t\tuser.id,\n\t\tfalse,\n\t\treason,\n\t\tfalse,\n\t\t['#artemis'],\n\t);\n\tglobalModlog(`${isWeek ? 'WEEK' : ''}LOCK`, user, reason, room);\n\taddGlobalModAction(`${user.name} was locked from talking by Artemis${isWeek ? ' for a week. ' : \". \"}(${reason})`, room);\n\tif (affected.length > 1) {\n\t\tRooms.get('staff')?.add(\n\t\t\t`|c|~|/log (${user.id}'s ` +\n\t\t\t`locked alts: ${affected.slice(1).map(curUser => curUser.getLastName()).join(\", \")})`\n\t\t);\n\t}\n\troom.add(`|c|~|/raw ${DISCLAIMER}`).update();\n\troom.hideText(affected.map(f => f.id), undefined, true);\n\tlet message = `|popup||html|Artemis has locked you from talking in chats, battles, and PMing regular users`;\n\tmessage += ` ${!isWeek ? \"for two days\" : \"for a week\"}`;\n\tmessage += `\\n\\nReason: ${reason}`;\n\tlet appeal = '';\n\tif (Chat.pages.help) {\n\t\tappeal += `<a href=\"view-help-request--appeal\"><button class=\"button\"><strong>Appeal your punishment</strong></button></a>`;\n\t} else if (Config.appealurl) {\n\t\tappeal += `appeal: <a href=\"${Config.appealurl}\">${Config.appealurl}</a>`;\n\t}\n\n\tif (appeal) message += `\\n\\nIf you feel that your lock was unjustified, you can ${appeal}.`;\n\tmessage += `\\n\\nYour lock will expire in a few days.`;\n\tuser.send(message);\n\n\tconst roomauth = Rooms.global.destroyPersonalRooms(user.id);\n\tif (roomauth.length) {\n\t\tMonitor.log(\n\t\t\t`[CrisisMonitor] Locked user ${user.name} ` +\n\t\t\t`has public roomauth (${roomauth.join(', ')}), and should probably be demoted.`\n\t\t);\n\t}\n}\n\ntype PunishmentHandler = (\n\tuser: User, room: GameRoom, response: Record<string, number>, message: string,\n) => void | boolean | Promise<void | boolean>;\n\n/** Keep this in descending order of severity */\nconst punishmentHandlers: Record<string, PunishmentHandler> = {\n\treport(user, room) {\n\t\tfor (const k in room.users) {\n\t\t\tif (k === user.id) continue;\n\t\t\tconst u = room.users[k];\n\t\t\tif (room.auth.get(u) !== Users.PLAYER_SYMBOL) continue;\n\t\t\tu.sendTo(\n\t\t\t\troom.roomid,\n\t\t\t\t`|c|~|/uhtml report,` +\n\t\t\t\t`Toxicity has been automatically detected in this battle, ` +\n\t\t\t\t`please click below if you would like to report it.<br />` +\n\t\t\t\t`<a class=\"button notifying\" href=\"/view-help-request\">Make a report</a>`\n\t\t\t);\n\t\t}\n\t},\n\tmute(user, room) {\n\t\tconst roomMutes = muted.get(room) || new WeakMap();\n\t\tif (!user.trusted) {\n\t\t\tmuted.set(room, roomMutes);\n\t\t\troomMutes.set(user, Date.now() + MUTE_DURATION);\n\t\t}\n\t},\n\twarn(user, room, response, message) {\n\t\tconst reason = `${Users.PLAYER_SYMBOL}${user.name}: ${message}`;\n\t\tif (!user.connected) {\n\t\t\tPunishments.offlineWarns.set(user.id, reason);\n\t\t} else {\n\t\t\tuser.send(`|c|~|/warn ${reason}`);\n\t\t}\n\t\tglobalModlog('WARN', user, reason, room);\n\t\taddGlobalModAction(`${user.name} was warned by Artemis (${reason})`, room);\n\t\tconst punishments = punishmentCache.get(user) || {};\n\t\tif (!punishments['WARN']) punishments['WARN'] = 0;\n\t\tpunishments['WARN']++;\n\t\tpunishmentCache.set(user, punishments);\n\n\t\troom.add(`|c|~|/raw ${DISCLAIMER}`).update();\n\t\troom.hideText([user.id], undefined, true);\n\t},\n\tlock(user, room, response, message) {\n\t\treturn lock(user, room, `${Users.PLAYER_SYMBOL}${user.name}: ${message}`);\n\t},\n\tweeklock(user, room, response, message) {\n\t\treturn lock(user, room, `${Users.PLAYER_SYMBOL}${user.name}: ${message}`, true);\n\t},\n};\n// autogenerated for QOL\nconst PUNISHMENTS = Object.keys(punishmentHandlers).map(f => f.toUpperCase());\n\nfunction makeScore(roomid: RoomID, result: Record<string, number>) {\n\tlet score = 0;\n\tlet main = '';\n\tconst flags = new Set<string>();\n\tfor (const type in result) {\n\t\tconst data = result[type];\n\t\tif (settings.minScore && data < settings.minScore) continue;\n\t\tconst curScore = score;\n\t\tif (settings.specials[type]) {\n\t\t\tfor (const k in settings.specials[type]) {\n\t\t\t\tif (data < Number(k)) continue;\n\t\t\t\tconst num = settings.specials[type][k];\n\t\t\t\tif (num === 'MAXIMUM') {\n\t\t\t\t\tscore = calcThreshold(roomid);\n\t\t\t\t\tmain = type;\n\t\t\t\t} else {\n\t\t\t\t\tif (num > score) {\n\t\t\t\t\t\tscore = num;\n\t\t\t\t\t\tmain = type;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tif (settings.minScore) {\n\t\t\t// min score ensures that if a category is above that minimum score, they will get\n\t\t\t// at least a point.\n\t\t\t// we previously ensured that this was above minScore if set, so this is fine\n\t\t\tif (score < 1) {\n\t\t\t\tscore = 1;\n\t\t\t\tmain = type;\n\t\t\t}\n\t\t}\n\t\tif (score !== curScore) flags.add(type);\n\t}\n\treturn { score, flags: [...flags], main };\n}\n\nexport const chatfilter: Chat.ChatFilter = function (message, user, room) {\n\t// 2 lines to not hit max-len\n\tif (!room?.battle || !['rated', 'unrated'].includes(room.battle.challengeType)) return;\n\tconst mutes = muted.get(room);\n\tconst muteEntry = mutes?.get(user);\n\tif (muteEntry) {\n\t\tif (Date.now() > muteEntry) {\n\t\t\tmutes.delete(user);\n\t\t\tif (!mutes.size) {\n\t\t\t\tmuted.delete(room);\n\t\t\t}\n\t\t} else {\n\t\t\tthis.sendReply(\n\t\t\t\t`|c|~|/raw <div class=\"message-error\">` +\n\t\t\t\t`Your behavior in this battle has been automatically identified as breaking ` +\n\t\t\t\t`<a href=\"https://${Config.routes.root}/rules\">Pokemon Showdown's global rules.</a> ` +\n\t\t\t\t`Repeated instances of misbehavior may incur harsher punishment.</div>`\n\t\t\t);\n\t\t\treturn false;\n\t\t}\n\t}\n\tif (settings.disabled) return;\n\t// startsWith('!') - broadcasting command, ignore it.\n\tif (!Config.perspectiveKey || message.startsWith('!')) return;\n\n\tconst roomid = room.roomid;\n\tvoid (async () => {\n\t\tmessage = message.trim();\n\t\tmessage = message.replace(pokemonRegex, '[[Pokemon]]');\n\n\t\tfor (const k in settings.replacements) {\n\t\t\tmessage = message.replace(new RegExp(k, 'gi'), settings.replacements[k]);\n\t\t}\n\n\t\tconst response = await classifier.classify(message);\n\t\tconst { score, flags, main } = makeScore(roomid, response || {});\n\t\tif (score) {\n\t\t\tif (!cache[roomid]) cache[roomid] = { users: {} };\n\t\t\tif (!cache[roomid].users[user.id]) cache[roomid].users[user.id] = 0;\n\t\t\tcache[roomid].users[user.id] += score;\n\t\t\tlet hitThreshold = 0;\n\t\t\tif (cache[roomid].users[user.id] >= calcThreshold(roomid)) {\n\t\t\t\tlet notified = cache[roomid].staffNotified;\n\t\t\t\tif (notified) {\n\t\t\t\t\tif (!Array.isArray(notified)) {\n\t\t\t\t\t\tcache[roomid].staffNotified = notified = [notified];\n\t\t\t\t\t}\n\t\t\t\t\tif (!notified.includes(user.id)) {\n\t\t\t\t\t\tnotified.push(user.id);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\tcache[roomid].staffNotified = [user.id];\n\t\t\t\t}\n\t\t\t\tnotifyStaff();\n\t\t\t\thitThreshold = 1;\n\t\t\t\tvoid room?.uploadReplay?.(user, this.connection, \"forpunishment\");\n\t\t\t\tawait Chat.database.run(\n\t\t\t\t\t`INSERT INTO perspective_flags (userid, score, certainty, type, roomid, time) VALUES (?, ?, ?, ?, ?, ?)`,\n\t\t\t\t\t// response exists if we got this far\n\t\t\t\t\t[user.id, score, response![main], main, room.roomid, Date.now()]\n\t\t\t\t);\n\t\t\t\tvoid runActions(user, room, message, response || {});\n\t\t\t}\n\t\t\tawait Chat.database.run(\n\t\t\t\t'INSERT INTO perspective_logs (userid, message, score, flags, roomid, time, hit_threshold) VALUES (?, ?, ?, ?, ?, ?, ?)',\n\t\t\t\t[user.id, message, score, Utils.sortBy(flags).join(','), roomid, Date.now(), hitThreshold]\n\t\t\t);\n\t\t}\n\t})();\n};\n// to avoid conflicts with other filters\nchatfilter.priority = -100;\n\nexport const loginfilter: Chat.LoginFilter = user => {\n\tif (reviews[user.id]?.length) {\n\t\tfor (const r of reviews[user.id]) {\n\t\t\tdisplayResolved(r);\n\t\t}\n\t}\n};\n\nfunction calcThreshold(roomid: RoomID) {\n\tconst incr = settings.thresholdIncrement;\n\tlet num = settings.threshold;\n\tconst room = Rooms.get(roomid);\n\tif (!room?.battle || !incr) return num;\n\tif (!incr.minTurns || room.battle.turn >= incr.minTurns) {\n\t\tnum += (Math.floor(room.battle.turn / incr.turns) * incr.amount);\n\t}\n\treturn num;\n}\n\nexport const handlers: Chat.Handlers = {\n\tonRoomDestroy(roomid) {\n\t\tconst entry = cache[roomid];\n\t\tif (entry) {\n\t\t\tdelete cache[roomid];\n\t\t\tif (entry.staffNotified) {\n\t\t\t\tnotifyStaff();\n\t\t\t\tvoid Chat.database.run(\n\t\t\t\t\t`INSERT INTO perspective_stats (staff, roomid, result, timestamp) VALUES ($staff, $roomid, $result, $timestamp) ` +\n\t\t\t\t\t`ON CONFLICT (roomid) DO UPDATE SET result = $result, timestamp = $timestamp`,\n\t\t\t\t\t// 2 means dead\n\t\t\t\t\t{ staff: '', roomid, result: 2, timestamp: Date.now() }\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t},\n\tonRoomClose(roomid, user) {\n\t\tif (!roomid.startsWith('view-abusemonitor-view')) return;\n\t\tconst targetId = roomid.slice('view-abusemonitor-view-'.length);\n\t\tif (cache[targetId]?.claimed === user.id) {\n\t\t\tdelete cache[targetId].claimed;\n\t\t\tnotifyStaff();\n\t\t}\n\t},\n\tonRenameRoom(oldId, newId, room) {\n\t\tif (cache[oldId]) {\n\t\t\tcache[newId] = cache[oldId];\n\t\t\tdelete cache[oldId];\n\t\t\tnotifyStaff();\n\t\t}\n\t},\n};\n\nfunction getFlaggedRooms() {\n\treturn Object.keys(cache).filter(roomid => cache[roomid].staffNotified);\n}\n\nexport function writeStats(type: string, entry: AnyObject) {\n\tconst path = `artemis/${type}/${Chat.toTimestamp(new Date()).split(' ')[0].slice(0, -3)}.jsonl`;\n\ttry {\n\t\tMonitor.logPath(path).parentDir().mkdirpSync();\n\t} catch {}\n\tvoid Monitor.logPath(path).append(JSON.stringify(entry) + \"\\n\");\n}\n\nfunction saveSettings(path?: string) {\n\tif (!path) path = 'nf';\n\tFS(`config/chat-plugins/${path}.json`).writeUpdate(() => JSON.stringify(settings));\n}\n\nfunction saveReviews() {\n\tFS(`config/chat-plugins/artemis-reviews.json`).writeUpdate(() => JSON.stringify(reviews));\n}\n\nfunction saveMetadata() {\n\tFS('config/chat-plugins/artemis-metadata.json').writeUpdate(() => JSON.stringify(metadata));\n}\n\nexport const pokemonRegex = new RegExp( // we want only base formes and existent stuff\n\t`\\\\b(${Dex.species.all().filter(s => !s.forme && s.num > 0).map(f => f.id).join('|')})\\\\b`, 'gi'\n);\n\nexport let lastLogTime: number = Chat.oldPlugins['abuse-monitor']?.lastLogTime || 0;\n\nexport function notifyStaff() {\n\tconst staffRoom = Rooms.get('staff');\n\tif (staffRoom) {\n\t\tconst flagged = getFlaggedRooms();\n\t\tlet buf = '';\n\t\tif (flagged.length) {\n\t\t\tbuf = `<button class=\"button\" name=\"send\" value=\"/am\">Flagged battles need review</button>`;\n\t\t} else {\n\t\t\tbuf = 'No battles flagged.';\n\t\t}\n\t\t// if it's been 10m, or if there are no flagged battles currently, update the box\n\t\tif ((lastLogTime + STAFF_NOTIF_INTERVAL) < Date.now() || !flagged.length) {\n\t\t\tstaffRoom.send(`|uhtml|abusemonitor|<div class=\"infobox\">${buf}</div>`);\n\t\t\t// if there are none, don't update the time - no point\n\t\t\tif (flagged.length) {\n\t\t\t\tlastLogTime = Date.now();\n\t\t\t} else {\n\t\t\t\tlastLogTime = 0;\n\t\t\t}\n\t\t}\n\t\t// always update flags\n\t\tChat.refreshPageFor('abusemonitor-flagged', staffRoom);\n\t}\n}\n\nfunction checkAccess(context: Chat.CommandContext | Chat.PageContext, perm: GlobalPermission = 'bypassall') {\n\tconst user = context.user;\n\tif (!(WHITELIST.includes(user.id) || user.previousIDs.some(id => WHITELIST.includes(id)))) {\n\t\tcontext.checkCan(perm);\n\t}\n}\n\nexport const commands: Chat.ChatCommands = {\n\tam: 'abusemonitor',\n\tabusemonitor: {\n\t\t''() {\n\t\t\treturn this.parse('/join view-abusemonitor-flagged');\n\t\t},\n\t\tasync test(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst text = target;\n\t\t\tif (!text) return this.parse(`/help abusemonitor`);\n\t\t\tthis.runBroadcast();\n\t\t\tlet response = await classifier.classify(text);\n\t\t\tif (!response) response = {};\n\t\t\tfor (const k in settings.replacements) {\n\t\t\t\ttarget = target.replace(new RegExp(k, 'gi'), settings.replacements[k]);\n\t\t\t}\n\t\t\t// intentionally hardcoded to staff to ensure threshold is never altered.\n\t\t\tconst { score, flags } = makeScore('staff', response);\n\t\t\tlet buf = `<strong>Score for \"${text}\"${target === text ? '' : ` (alt: \"${target}\")`}:</strong> ${score}<br />`;\n\t\t\tbuf += `<strong>Flags:</strong> ${flags.join(', ')}<br />`;\n\t\t\tconst punishments: { punishment: PunishmentSettings, desc: string[], index: number }[] = [];\n\t\t\tfor (const [i, p] of settings.punishments.entries()) {\n\t\t\t\tconst matches = [];\n\t\t\t\tfor (const k in response) {\n\t\t\t\t\tconst descriptors = [];\n\t\t\t\t\tif (p.type) {\n\t\t\t\t\t\tif (p.type !== k) continue;\n\t\t\t\t\t\tdescriptors.push('type');\n\t\t\t\t\t}\n\t\t\t\t\tif (p.certainty) {\n\t\t\t\t\t\tif (response[k] < p.certainty) continue;\n\t\t\t\t\t\tdescriptors.push('certainty');\n\t\t\t\t\t}\n\t\t\t\t\tconst secondaries = Object.entries(p.secondaryTypes || {});\n\t\t\t\t\tif (secondaries.length) {\n\t\t\t\t\t\tif (!secondaries.every(([sK, sV]) => response[sK] >= sV)) continue;\n\t\t\t\t\t\tdescriptors.push('secondary');\n\t\t\t\t\t}\n\t\t\t\t\tif (descriptors.length) { // ignore modlog / flag -only based actions\n\t\t\t\t\t\tmatches.push(`${k} (${descriptors.map(f => `${f} match`).join(', ')})`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (matches.length) {\n\t\t\t\t\tpunishments.push({\n\t\t\t\t\t\tpunishment: p,\n\t\t\t\t\t\tdesc: matches,\n\t\t\t\t\t\tindex: i,\n\t\t\t\t\t});\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (punishments.length) {\n\t\t\t\tbuf += `<strong>Punishments:</strong><br />`;\n\t\t\t\tbuf += punishments.map(p => (\n\t\t\t\t\t`&bull; ${p.index + 1}: <code>${visualizePunishment(p.punishment)}</code>: ${p.desc.join(', ')}`\n\t\t\t\t)).join('<br />');\n\t\t\t\tbuf += `<br />`;\n\t\t\t}\n\t\t\tbuf += `<strong>Score breakdown:</strong><br />`;\n\t\t\tfor (const k in response) {\n\t\t\t\tbuf += `&bull; ${k}: ${response[k]}<br />`;\n\t\t\t}\n\t\t\tthis.sendReplyBox(buf);\n\t\t},\n\t\tcm: 'compare',\n\t\tasync compare(target) {\n\t\t\tcheckAccess(this);\n\t\t\tconst [base, against] = Utils.splitFirst(target, ',').map(f => f.trim());\n\t\t\tif (!(base && against)) return this.parse(`/help abusemonitor`);\n\t\t\tconst colors: Record<string, string> = {\n\t\t\t\t'0': 'Purple',\n\t\t\t\t'1': 'DodgerBlue',\n\t\t\t\t'2': 'Red',\n\t\t\t};\n\t\t\tconst baseResponse = await classifier.classify(base) || {};\n\t\t\tconst againstResponse = await new Promise<Record<string, number> | null>(resolve => {\n\t\t\t\t// bit of a hack, but this has to be done so rate limits don't get hit\n\t\t\t\tsetTimeout(() => {\n\t\t\t\t\tresolve(classifier.classify(against));\n\t\t\t\t}, 500);\n\t\t\t}) || {};\n\t\t\tlet buf = Utils.html`<strong>Compared scores for \"${base}\" `;\n\t\t\tbuf += `(<strong style=\"color: ${colors['1']}\">1</strong>) `;\n\t\t\tbuf += Utils.html`and \"${against}\" (<strong style=\"color: ${colors['2']}\">2</strong>): </strong><br />`;\n\t\t\tfor (const [k, val] of Object.entries(baseResponse)) {\n\t\t\t\tconst max = Math.max(val, againstResponse[k]);\n\t\t\t\tconst num = val === againstResponse[k] ? '0' : max === val ? '1' : '2';\n\t\t\t\tbuf += `&bull; ${k}: <strong style=\"color: ${colors[num]}\">${num}</strong> `;\n\t\t\t\tif (num === '0') {\n\t\t\t\t\tbuf += `(${max})`;\n\t\t\t\t} else {\n\t\t\t\t\tbuf += `(${max} vs ${(max === val ? againstResponse : baseResponse)[k]})`;\n\t\t\t\t}\n\t\t\t\tbuf += `<br />`;\n\t\t\t}\n\t\t\tthis.runBroadcast();\n\t\t\treturn this.sendReplyBox(buf);\n\t\t},\n\t\tasync score(target) {\n\t\t\tcheckAccess(this);\n\t\t\ttarget = target.trim();\n\t\t\tif (!target) return this.parse(`/help abusemonitor`);\n\t\t\tconst [text, scoreText] = Utils.splitFirst(target, ',').map(f => f.trim());\n\t\t\tconst args = Chat.parseArguments(scoreText, ',', { useIDs: false });\n\t\t\tconst scores: Record<string, number> = {};\n\t\t\tfor (let k in args) {\n\t\t\t\tconst vals = args[k];\n\t\t\t\tif (vals.length > 1) {\n\t\t\t\t\treturn this.errorReply(`Too many values for ${k}`);\n\t\t\t\t}\n\t\t\t\tk = k.toUpperCase().replace(/\\s/g, '_');\n\t\t\t\tif (!(k in Artemis.RemoteClassifier.ATTRIBUTES)) {\n\t\t\t\t\treturn this.errorReply(`Invalid attribute: ${k}`);\n\t\t\t\t}\n\t\t\t\tconst val = parseFloat(vals[0]);\n\t\t\t\tif (isNaN(val)) {\n\t\t\t\t\treturn this.errorReply(`Invalid value for ${k}: ${vals[0]}`);\n\t\t\t\t}\n\t\t\t\tscores[k] = val;\n\t\t\t}\n\t\t\tfor (const k in Artemis.RemoteClassifier.ATTRIBUTES) {\n\t\t\t\tif (!(k in scores)) scores[k] = 0;\n\t\t\t}\n\t\t\tconst response = await classifier.suggestScore(text, scores);\n\t\t\tif (response.error) throw new Chat.ErrorMessage(response.error);\n\t\t\tthis.sendReply(`Recommendation successfully sent.`);\n\t\t\tRooms.get('abuselog')?.roomlog(`${this.user.name} used /am score ${target}`);\n\t\t},\n\t\ttoggle(target) {\n\t\t\tcheckAccess(this);\n\t\t\tif (this.meansYes(target)) {\n\t\t\t\tif (!settings.disabled) return this.errorReply(`The abuse monitor is already enabled.`);\n\t\t\t\tsettings.disabled = false;\n\t\t\t} else if (this.meansNo(target)) {\n\t\t\t\tif (settings.disabled) return this.errorReply(`The abuse monitor is already disabled.`);\n\t\t\t\tsettings.disabled = true;\n\t\t\t} else {\n\t\t\t\treturn this.errorReply(`Invalid setting. Must be 'on' or 'off'.`);\n\t\t\t}\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${this.user.name} ${!settings.disabled ? 'enabled' : 'disabled'} the abuse monitor.`);\n\t\t\tthis.globalModlog('ABUSEMONITOR', null, !settings.disabled ? 'enable' : 'disable');\n\t\t},\n\t\tthreshold(target) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!target) {\n\t\t\t\treturn this.sendReply(`The current abuse monitor threshold is ${settings.threshold}.`);\n\t\t\t}\n\t\t\tconst num = parseInt(target);\n\t\t\tif (isNaN(num)) {\n\t\t\t\tthis.errorReply(`Invalid number: ${target}`);\n\t\t\t\treturn this.parse(`/help abusemonitor`);\n\t\t\t}\n\t\t\tif (settings.threshold === num) {\n\t\t\t\treturn this.errorReply(`The abuse monitor threshold is already ${num}.`);\n\t\t\t}\n\t\t\tsettings.threshold = num;\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${this.user.name} set the abuse monitor trigger threshold to ${num}.`);\n\t\t\tthis.globalModlog('ABUSEMONITOR THRESHOLD', null, `${num}`);\n\t\t\tthis.sendReply(\n\t\t\t\t`|html|Remember to use <code>/am respawn</code> to deploy the settings to the child process.`\n\t\t\t);\n\t\t},\n\t\tasync resolve(target) {\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = target.toLowerCase().trim().replace(/ +/g, '');\n\t\t\tlet [roomid, rawResult] = Utils.splitFirst(target, ',').map(f => f.trim());\n\t\t\tconst tarRoom = Rooms.get(roomid);\n\t\t\tif (!tarRoom || !cache[tarRoom.roomid] || !cache[tarRoom.roomid]?.staffNotified) {\n\t\t\t\treturn this.popupReply(`That room has not been flagged by the abuse monitor.`);\n\t\t\t}\n\t\t\tif (roomid.includes('-') && roomid.endsWith('pw')) {\n\t\t\t\t// cut off passwords\n\t\t\t\troomid = roomid.split('-').slice(0, -1).join('-');\n\t\t\t}\n\t\t\tlet result = toID(rawResult) === 'success' ? 1 : toID(rawResult) === 'failure' ? 0 : null;\n\t\t\tif (result === null) return this.popupReply(`Invalid result - must be 'success' or 'failure'.`);\n\t\t\tconst inserted = await Chat.database.get(`SELECT result FROM perspective_stats WHERE roomid = ?`, [roomid]);\n\t\t\tif (inserted?.result === 1) { // (hardcode on 1 because 2 is dead)\n\t\t\t\t// has already been logged as accurate - ensure if one success is logged it's still a success if it's hit again\n\t\t\t\t// (even if it's a failure now, it was a success before - that's what's relevant.)\n\t\t\t\tresult = inserted.result;\n\t\t\t}\n\t\t\t// we delete the cache because if more stuff happens in it\n\t\t\t// post punishment, we want to know about it\n\t\t\tdelete cache[tarRoom.roomid];\n\t\t\tnotifyStaff();\n\t\t\tthis.closePage(`abusemonitor-view-${tarRoom.roomid}`);\n\t\t\t// bring the listing page to the front - need to close and reopen\n\t\t\tthis.closePage(`abusemonitor-flagged`);\n\t\t\tawait Chat.database.run(\n\t\t\t\t`INSERT INTO perspective_stats (staff, roomid, result, timestamp) VALUES ($staff, $roomid, $result, $timestamp) ` +\n\t\t\t\t// on conflict in case it's re-triggered later.\n\t\t\t\t// (we want it to be updated to success if it is now a success where it was previously inaccurate)\n\t\t\t\t`ON CONFLICT (roomid) DO UPDATE SET result = $result, timestamp = $timestamp`,\n\t\t\t\t{ staff: this.user.id, roomid, result, timestamp: Date.now() }\n\t\t\t);\n\t\t\treturn this.parse(`/j view-abusemonitor-flagged`);\n\t\t},\n\t\tunmute(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\troom = this.requireRoom();\n\t\t\ttarget = toID(target);\n\t\t\tif (!target) {\n\t\t\t\treturn this.parse(`/help am`);\n\t\t\t}\n\t\t\tconst roomMutes = muted.get(room);\n\t\t\tif (!roomMutes) {\n\t\t\t\treturn this.errorReply(`No users have Artemis mutes in this room.`);\n\t\t\t}\n\t\t\tconst targetUser = Users.get(target);\n\t\t\tif (!targetUser) {\n\t\t\t\treturn this.errorReply(`User '${target}' not found.`);\n\t\t\t}\n\t\t\tif (!roomMutes.has(targetUser)) {\n\t\t\t\treturn this.errorReply(`That user does not have an Artemis mute in this room.`);\n\t\t\t}\n\t\t\troomMutes.delete(targetUser);\n\t\t\tthis.modlog(`ABUSEMONITOR UNMUTE`, targetUser);\n\t\t\tthis.privateModAction(`${user.name} removed ${targetUser.name}'s Artemis mute.`);\n\t\t},\n\t\tasync nojoinpunish(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst [roomid, type, rest] = Utils.splitFirst(target, ',', 2).map(f => f.trim());\n\t\t\tconst tarRoom = Rooms.get(roomid);\n\t\t\tif (!tarRoom) return this.popupReply(`The room \"${roomid}\" does not exist.`);\n\t\t\tconst cmd = NOJOIN_COMMAND_WHITELIST[toID(type)];\n\t\t\tif (!cmd) {\n\t\t\t\treturn this.errorReply(\n\t\t\t\t\t`Invalid punishment given. ` +\n\t\t\t\t\t`Must be one of ${Object.keys(NOJOIN_COMMAND_WHITELIST).join(', ')}.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.room = tarRoom;\n\t\t\tthis.room.reportJoin('j', user.getIdentityWithStatus(this.room), user);\n\t\t\tconst result = await this.parse(`${cmd} ${rest}`, { bypassRoomCheck: true });\n\t\t\tif (result) { // command succeeded - send followup\n\t\t\t\tthis.add(\n\t\t\t\t\t'|c|~|/raw If you have questions about this action, please contact staff ' +\n\t\t\t\t\t'by making a <a href=\"view-help-request\" class=\"button\">help ticket</a>'\n\t\t\t\t);\n\t\t\t}\n\t\t\tthis.room.reportJoin('l', user.getIdentityWithStatus(this.room), user);\n\t\t},\n\t\tview(target, room, user) {\n\t\t\ttarget = target.toLowerCase().trim();\n\t\t\tif (!target) return this.parse(`/help am`);\n\t\t\treturn this.parse(`/j view-abusemonitor-view-${target}`);\n\t\t},\n\t\tlogs(target) {\n\t\t\tcheckAccess(this);\n\t\t\tconst [count, userid] = Utils.splitFirst(target, ',').map(toID);\n\t\t\tthis.parse(`/join view-abusemonitor-logs-${count || '200'}${userid ? `-${userid}` : \"\"}`);\n\t\t},\n\t\tul: 'userlogs',\n\t\tuserlogs(target) {\n\t\t\tcheckAccess(this, 'lock');\n\t\t\treturn this.parse(`/join view-abusemonitor-userlogs-${toID(target)}`);\n\t\t},\n\t\tstats(target) {\n\t\t\tcheckAccess(this);\n\t\t\treturn this.parse(`/join view-abusemonitor-stats${target ? `-${target}` : ''}`);\n\t\t},\n\t\tasync respawn(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tthis.sendReply(`Respawning...`);\n\t\t\tconst unspawned = await classifier.respawn();\n\t\t\tthis.sendReply(`DONE. ${Chat.count(unspawned, 'processes', 'process')} unspawned.`);\n\t\t\tthis.addGlobalModAction(`${user.name} used /abusemonitor respawn`);\n\t\t},\n\t\tasync rescale(target, room, user) {\n\t\t\t// people should NOT be fucking with this unless they know what they are doing\n\t\t\tif (!WHITELIST.includes(user.id)) this.canUseConsole();\n\t\t\tconst examples = target.split(',').filter(Boolean);\n\t\t\tconst type = examples.shift()?.toUpperCase().replace(/\\s/g, '_') || \"\";\n\t\t\tif (!(type in Artemis.RemoteClassifier.ATTRIBUTES)) {\n\t\t\t\treturn this.errorReply(`Invalid type: ${type}`);\n\t\t\t}\n\t\t\tif (examples.length < 3) {\n\t\t\t\treturn this.errorReply(`At least 3 examples are needed.`);\n\t\t\t}\n\t\t\tconst scales = [];\n\t\t\tconst oldScales = [];\n\t\t\tfor (const chunk of examples) {\n\t\t\t\tconst [message, rawNum] = chunk.split('|');\n\t\t\t\tif (!(message && rawNum)) {\n\t\t\t\t\treturn this.errorReply(`Invalid example: \"${chunk}\". Must be in \\`\\`message|num\\`\\` format.`);\n\t\t\t\t}\n\t\t\t\tconst num = parseFloat(rawNum);\n\t\t\t\tif (isNaN(num)) {\n\t\t\t\t\treturn this.errorReply(`Invalid number in example '${chunk}'.`);\n\t\t\t\t}\n\t\t\t\tconst data = await classifier.classify(message);\n\t\t\t\tif (!data) {\n\t\t\t\t\treturn this.errorReply(`No results found. Try again in a minute?`);\n\t\t\t\t}\n\t\t\t\toldScales.push(num);\n\t\t\t\tscales.push(data[type]);\n\t\t\t\t// take a bit to dodge rate limits\n\t\t\t\tawait Utils.waitUntil(Date.now() + 1000);\n\t\t\t}\n\t\t\tconst newAverage = scales.reduce((a, b) => a + b) / scales.length;\n\t\t\tconst oldAverage = oldScales.reduce((a, b) => a + b) / oldScales.length;\n\t\t\tconst round = (num: number) => Number(num.toFixed(4));\n\t\t\tconst change = newAverage / oldAverage;\n\n\t\t\tthis.sendReply(`Change average: ${change}`);\n\t\t\tawait this.parse(`/am bs prescale`);\n\n\t\t\tfor (const p of settings.punishments) {\n\t\t\t\tif (p.type !== type) continue;\n\t\t\t\tif (p.certainty) p.certainty = round(p.certainty * change);\n\t\t\t\tif (p.secondaryTypes) {\n\t\t\t\t\tfor (const k in p.secondaryTypes) {\n\t\t\t\t\t\tp.secondaryTypes[k] = round(p.secondaryTypes[k] * change);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (type in settings.specials) {\n\t\t\t\tfor (const n in settings.specials[type]) {\n\t\t\t\t\tconst num = settings.specials[type][n];\n\t\t\t\t\tdelete settings.specials[type][n];\n\t\t\t\t\tsettings.specials[type][round(parseFloat(n) * change)] = num;\n\t\t\t\t}\n\t\t\t}\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.addGlobalModAction(\n\t\t\t\t`${user.name} used /abusemonitor rescale ${type.toLowerCase().replace('_', '')}`\n\t\t\t);\n\t\t\tthis.globalModlog(`ABUSEMONITOR RESCALE`, null, `${type}: ${examples.join(', ')}`);\n\t\t},\n\t\tasync userclear(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst { targetUsername, rest } = this.splitUser(target);\n\t\t\tconst targetId = toID(targetUsername);\n\t\t\tif (!targetId) return this.parse(`/help abusemonitor`);\n\t\t\tif (user.lastCommand !== `am userclear ${targetId}`) {\n\t\t\t\tuser.lastCommand = `am userclear ${targetId}`;\n\t\t\t\tthis.errorReply(`Are you sure you want to clear abuse monitor database records for ${targetId}?`);\n\t\t\t\tthis.errorReply(`Retype the command if you're sure.`);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tuser.lastCommand = '';\n\t\t\tconst results = await Chat.database.run(\n\t\t\t\t'DELETE FROM perspective_logs WHERE userid = ?', [targetId]\n\t\t\t);\n\t\t\tif (!results.changes) {\n\t\t\t\treturn this.errorReply(`No logs for ${targetUsername} found.`);\n\t\t\t}\n\t\t\tthis.sendReply(`${results.changes} log(s) cleared for ${targetId}.`);\n\t\t\tthis.privateGlobalModAction(`${user.name} cleared abuse monitor logs for ${targetUsername}${rest ? ` (${rest})` : \"\"}.`);\n\t\t\tthis.globalModlog('ABUSEMONITOR CLEAR', targetId, rest);\n\t\t},\n\t\tasync deletelog(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\ttarget = toID(target);\n\t\t\tif (!target) return this.parse(`/help abusemonitor`);\n\t\t\tconst num = parseInt(target);\n\t\t\tif (isNaN(num)) {\n\t\t\t\treturn this.errorReply(`Invalid log number: ${target}`);\n\t\t\t}\n\t\t\tconst row = await Chat.database.get(\n\t\t\t\t'SELECT * FROM perspective_logs WHERE rowid = ?', [num]\n\t\t\t);\n\t\t\tif (!row) {\n\t\t\t\treturn this.errorReply(`No log with ID ${num} found.`);\n\t\t\t}\n\t\t\tawait Chat.database.run( // my kingdom for RETURNING * in sqlite :(\n\t\t\t\t'DELETE FROM perspective_logs WHERE rowid = ?', [num]\n\t\t\t);\n\t\t\tthis.sendReply(`Log ${num} deleted.`);\n\t\t\tthis.privateGlobalModAction(`${user.name} deleted an abuse monitor log for the user ${row.userid}.`);\n\t\t\tthis.stafflog(\n\t\t\t\t`Message: \"${row.message}\", room: ${row.roomid}, time: ${Chat.toTimestamp(new Date(row.time))}`\n\t\t\t);\n\t\t\tthis.globalModlog(\"ABUSEMONITOR DELETELOG\", row.userid, `${num}`);\n\t\t\tChat.refreshPageFor('abusemonitor-logs', 'staff', true);\n\t\t},\n\t\tes: 'editspecial',\n\t\teditspecial(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!toID(target)) return this.parse(`/help abusemonitor`);\n\t\t\tlet [rawType, rawPercent, rawScore] = target.split(',');\n\t\t\tconst type = rawType.toUpperCase().replace(/\\s/g, '_');\n\t\t\trawScore = toID(rawScore);\n\t\t\tconst types = { ...Artemis.RemoteClassifier.ATTRIBUTES, \"ALL\": {} };\n\t\t\tif (!(type in types)) {\n\t\t\t\treturn this.errorReply(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);\n\t\t\t}\n\t\t\tconst percent = parseFloat(rawPercent);\n\t\t\tif (isNaN(percent) || percent > 1 || percent < 0) {\n\t\t\t\treturn this.errorReply(`Invalid percent: ${percent}. Must be between 0 and 1.`);\n\t\t\t}\n\t\t\tconst score = parseInt(rawScore) || toID(rawScore).toUpperCase() as 'MAXIMUM';\n\t\t\tswitch (typeof score) {\n\t\t\tcase 'string':\n\t\t\t\tif (score !== 'MAXIMUM') {\n\t\t\t\t\treturn this.errorReply(`Invalid score. Must be a number or \"MAXIMUM\".`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\tcase 'number':\n\t\t\t\tif (isNaN(score) || score < 0) {\n\t\t\t\t\treturn this.errorReply(`Invalid score. Must be a number or \"MAXIMUM\".`);\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (settings.specials[type]?.[percent] && !this.cmd.includes('f')) {\n\t\t\t\treturn this.errorReply(`That special case already exists. Use /am forceeditspecial to change it.`);\n\t\t\t}\n\t\t\tif (!settings.specials[type]) settings.specials[type] = {};\n\t\t\t// checked above to ensure it's a valid number or MAXIMUM\n\t\t\tsettings.specials[type][percent] = score;\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} set the abuse monitor special case for ${type} at ${percent}% to ${score}.`);\n\t\t\tthis.globalModlog(\"ABUSEMONITOR SPECIAL\", type, `${percent}% to ${score}`);\n\t\t\tthis.sendReply(`|html|Remember to use <code>/am respawn</code> to deploy the settings to the child processes.`);\n\t\t},\n\t\tds: 'deletespecial',\n\t\tdeletespecial(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst [rawType, rawPercent] = target.split(',');\n\t\t\tconst type = rawType.toUpperCase().replace(/\\s/g, '_');\n\t\t\tconst types = { ...Artemis.RemoteClassifier.ATTRIBUTES, \"ALL\": {} };\n\t\t\tif (!(type in types)) {\n\t\t\t\treturn this.errorReply(`Invalid type: ${type}. Valid types: ${Object.keys(types).join(', ')}.`);\n\t\t\t}\n\t\t\tconst percent = parseFloat(rawPercent);\n\t\t\tif (isNaN(percent) || percent > 1 || percent < 0) {\n\t\t\t\treturn this.errorReply(`Invalid percent: ${percent}. Must be between 0 and 1.`);\n\t\t\t}\n\t\t\tif (!settings.specials[type]?.[percent]) {\n\t\t\t\treturn this.errorReply(`That special case does not exist.`);\n\t\t\t}\n\t\t\tdelete settings.specials[type][percent];\n\t\t\tif (!Object.keys(settings.specials[type]).length) {\n\t\t\t\tdelete settings.specials[type];\n\t\t\t}\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} deleted the abuse monitor special case for ${type} at ${percent}%.`);\n\t\t\tthis.globalModlog(\"ABUSEMONITOR DELETESPECIAL\", type, `${percent}%`);\n\t\t\tthis.sendReply(`|html|Remember to use <code>/am respawn</code> to deploy the settings to the child processes.`);\n\t\t},\n\t\tem: 'editmin',\n\t\teditmin(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst num = parseFloat(target);\n\t\t\tif (isNaN(num) || num < 0 || num > 1) {\n\t\t\t\treturn this.errorReply(`Invalid minimum score: ${num}. Must be a positive integer.`);\n\t\t\t}\n\t\t\tsettings.minScore = num;\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} set the abuse monitor minimum score to ${num}.`);\n\t\t\tthis.globalModlog(\"ABUSEMONITOR MIN\", null, `${num}`);\n\t\t\tthis.sendReply(`|html|Remember to use <code>/am respawn</code> to deploy the settings to the child processes.`);\n\t\t},\n\t\tex: 'exportpunishment',\n\t\texportpunishment(target) {\n\t\t\tcheckAccess(this);\n\t\t\tconst num = parseInt(target) - 1;\n\t\t\tif (isNaN(num)) {\n\t\t\t\treturn this.errorReply(`Invalid punishment number: ${num + 1}.`);\n\t\t\t}\n\t\t\tconst punishment = settings.punishments[num];\n\t\t\tif (!punishment) {\n\t\t\t\treturn this.errorReply(`Punishment ${num + 1} does not exist.`);\n\t\t\t}\n\t\t\tthis.sendReply(\n\t\t\t\t`|html|Punishment ${num + 1}: <code>` +\n\t\t\t\t`${visualizePunishment(punishment).replace(/: /g, ' = ')}</code>`\n\t\t\t);\n\t\t},\n\t\tchangeall(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst [to, from] = target.split(',').map(f => toID(f));\n\t\t\tif (!(to && from)) {\n\t\t\t\treturn this.errorReply(`Specify a type to change and a type to change to.`);\n\t\t\t}\n\t\t\tif (![to, from].every(f => punishmentHandlers[f])) {\n\t\t\t\treturn this.errorReply(\n\t\t\t\t\t`Invalid types given. Valid types: ${Object.keys(punishmentHandlers).join(', ')}.`\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst changed = [];\n\t\t\tfor (const [i, punishment] of settings.punishments.entries()) {\n\t\t\t\tif (toID(punishment.type) === to) {\n\t\t\t\t\tpunishment.type = from.toUpperCase();\n\t\t\t\t\tchanged.push(i + 1);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!changed.length) {\n\t\t\t\treturn this.errorReply(`No punishments of type '${to}' found.`);\n\t\t\t}\n\t\t\tthis.sendReply(`Updated punishment(s) ${changed.join(', ')}`);\n\t\t\tthis.privateGlobalModAction(`${user.name} updated all abuse-monitor punishments of type ${to} to type ${from}`);\n\t\t\tsaveSettings();\n\t\t\tthis.globalModlog(`ABUSEMONITOR CHANGEALL`, null, `${to} to ${from}`);\n\t\t},\n\t\tep: 'exportpunishments', // exports punishment settings to something easily copy/pastable\n\t\texportpunishments() {\n\t\t\tcheckAccess(this);\n\t\t\tlet buf = settings.punishments.map(punishment => {\n\t\t\t\tconst line = [];\n\t\t\t\tif ('modlogCount' in punishment) line.push(`mlc=${punishment.modlogCount}`);\n\t\t\t\tif (punishment.modlogActions) line.push(`${punishment.modlogActions.map(f => `mla=${f}`).join(', ')}`);\n\t\t\t\tline.push(`p=${punishment.punishment}`);\n\t\t\t\tif ('type' in punishment) line.push(`t=${punishment.type}`);\n\t\t\t\tif ('count' in punishment) line.push(`c=${punishment.count}`);\n\t\t\t\tif ('certainty' in punishment) line.push(`ct=${punishment.certainty}`);\n\t\t\t\tif ('secondaryTypes' in punishment) {\n\t\t\t\t\tfor (const type in punishment.secondaryTypes) {\n\t\t\t\t\t\tline.push(`st=${type}|${punishment.secondaryTypes[type]}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn line.join(', ');\n\t\t\t}).join('<br />');\n\t\t\tif (!buf) buf = 'None found';\n\t\t\tthis.sendReplyBox(buf);\n\t\t},\n\t\tap: 'addpunishment',\n\t\taddpunishment(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!toID(target)) return this.parse(`/help am`);\n\t\t\tconst targets = target.split(',').map(f => f.trim());\n\t\t\tconst punishment: Partial<PunishmentSettings> = {};\n\t\t\tfor (const cur of targets) {\n\t\t\t\tlet [key, value] = Utils.splitFirst(cur, '=').map(f => f.trim());\n\t\t\t\tkey = toID(key);\n\t\t\t\tif (!key || !value) { // sent from the page, val wasn't sent.\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tswitch (key) {\n\t\t\t\tcase 'punishment': case 'p':\n\t\t\t\t\tif (punishment.punishment) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate punishment values.`);\n\t\t\t\t\t}\n\t\t\t\t\tvalue = toID(value).toUpperCase();\n\t\t\t\t\tif (!PUNISHMENTS.includes(value)) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid punishment: ${value}. Valid punishments: ${PUNISHMENTS.join(', ')}.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.punishment = value;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'count': case 'num': case 'c':\n\t\t\t\t\tif (punishment.count) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate count values.`);\n\t\t\t\t\t}\n\t\t\t\t\tconst num = parseInt(value);\n\t\t\t\t\tif (isNaN(num)) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid count '${value}'. Must be a number.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.count = num;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'type': case 't':\n\t\t\t\t\tif (punishment.type) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate type values.`);\n\t\t\t\t\t}\n\t\t\t\t\tvalue = value.replace(/\\s/g, '_').toUpperCase();\n\t\t\t\t\tif (!Artemis.RemoteClassifier.ATTRIBUTES[value as keyof typeof Artemis.RemoteClassifier.ATTRIBUTES]) {\n\t\t\t\t\t\treturn this.errorReply(\n\t\t\t\t\t\t\t`Invalid attribute: ${value}. ` +\n\t\t\t\t\t\t\t`Valid attributes: ${Object.keys(Artemis.RemoteClassifier.ATTRIBUTES).join(', ')}.`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.type = value;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'certainty': case 'ct':\n\t\t\t\t\tif (punishment.certainty) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate certainty values.`);\n\t\t\t\t\t}\n\t\t\t\t\tconst certainty = parseFloat(value);\n\t\t\t\t\tif (isNaN(certainty) || certainty > 1 || certainty < 0) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid certainty '${value}'. Must be a number above 0 and below 1.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.certainty = certainty;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'mla': case 'modlogaction':\n\t\t\t\t\tvalue = value.toUpperCase();\n\t\t\t\t\tif (!punishment.modlogActions) {\n\t\t\t\t\t\tpunishment.modlogActions = [];\n\t\t\t\t\t}\n\t\t\t\t\tif (punishment.modlogActions.includes(value)) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate modlog action values - '${value}'.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.modlogActions.push(value);\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'mlc': case 'modlogcount':\n\t\t\t\t\tif (punishment.modlogCount) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate modlog count values.`);\n\t\t\t\t\t}\n\t\t\t\t\tconst count = parseInt(value);\n\t\t\t\t\tif (isNaN(count)) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid modlog count.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.modlogCount = count;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'st': case 's': case 'secondary':\n\t\t\t\t\tlet [sType, sValue] = Utils.splitFirst(value, '|').map(f => f.trim());\n\t\t\t\t\tif (!sType || !sValue) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid secondary type/certainty.`);\n\t\t\t\t\t}\n\t\t\t\t\tsType = sType.replace(/\\s/g, '_').toUpperCase();\n\t\t\t\t\tif (!Artemis.RemoteClassifier.ATTRIBUTES[sType as keyof typeof Artemis.RemoteClassifier.ATTRIBUTES]) {\n\t\t\t\t\t\treturn this.errorReply(\n\t\t\t\t\t\t\t`Invalid secondary attribute: ${sType}. ` +\n\t\t\t\t\t\t\t`Valid attributes: ${Object.keys(Artemis.RemoteClassifier.ATTRIBUTES).join(', ')}.`\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tconst sCertainty = parseFloat(sValue);\n\t\t\t\t\tif (isNaN(sCertainty) || sCertainty > 1 || sCertainty < 0) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid secondary certainty '${sValue}'. Must be a number above 0 and below 1.`);\n\t\t\t\t\t}\n\t\t\t\t\tif (!punishment.secondaryTypes) {\n\t\t\t\t\t\tpunishment.secondaryTypes = {};\n\t\t\t\t\t}\n\t\t\t\t\tif (punishment.secondaryTypes[sType]) {\n\t\t\t\t\t\treturn this.errorReply(`Duplicate secondary type.`);\n\t\t\t\t\t}\n\t\t\t\t\tpunishment.secondaryTypes[sType] = sCertainty;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'requirepunishment': case 'rp':\n\t\t\t\t\tpunishment.requiresPunishment = true;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tthis.errorReply(`Invalid key: ${key}`);\n\t\t\t\t\treturn this.parse(`/help am`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!punishment.punishment) {\n\t\t\t\treturn this.errorReply(`A punishment type must be specified.`);\n\t\t\t}\n\t\t\tfor (const [i, p] of settings.punishments.entries()) {\n\t\t\t\tlet matches = 0;\n\t\t\t\tfor (const k in p) {\n\t\t\t\t\tconst key = k as keyof PunishmentSettings;\n\t\t\t\t\tconst val = visualizePunishmentKey(punishment as PunishmentSettings, key);\n\t\t\t\t\tif (val && val === visualizePunishmentKey(p, key)) matches++;\n\t\t\t\t}\n\t\t\t\tif (matches === Object.keys(p).length) {\n\t\t\t\t\treturn this.errorReply(`This punishment is already stored at ${i + 1}.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tsettings.punishments.push(punishment as PunishmentSettings);\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} added a ${punishment.punishment} abuse-monitor punishment.`);\n\t\t\tconst str = visualizePunishment(punishment as PunishmentSettings);\n\t\t\tthis.stafflog(`Info: ${str}`);\n\t\t\tthis.globalModlog(`ABUSEMONITOR ADDPUNISHMENT`, null, str);\n\t\t},\n\t\tdp: 'deletepunishment',\n\t\tdeletepunishment(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst idx = parseInt(target) - 1;\n\t\t\tif (isNaN(idx)) return this.errorReply(`Invalid number.`);\n\t\t\tconst punishment = settings.punishments[idx];\n\t\t\tif (!punishment) {\n\t\t\t\treturn this.errorReply(`No punishments exist at index ${idx + 1}.`);\n\t\t\t}\n\t\t\tsettings.punishments.splice(idx, 1);\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} removed the abuse-monitor punishment indexed at ${idx + 1}.`);\n\t\t\tthis.stafflog(\n\t\t\t\t`Punishment: ` +\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-base-to-string\n\t\t\t\t`${Object.keys(punishment).map(f => `${f}: ${punishment[f as keyof PunishmentSettings]}`).join(', ')}`\n\t\t\t);\n\t\t\tthis.globalModlog(`ABUSEMONITOR REMOVEPUNISHMENT`, null, `${idx + 1}`);\n\t\t},\n\t\tvs: 'viewsettings',\n\t\tsettings: 'viewsettings',\n\t\tviewsettings() {\n\t\t\tcheckAccess(this);\n\t\t\treturn this.parse(`/join view-abusemonitor-settings`);\n\t\t},\n\t\tti: 'thresholdincrement',\n\t\tthresholdincrement(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!toID(target)) {\n\t\t\t\treturn this.parse(`/help am`);\n\t\t\t}\n\t\t\tconst [rawTurns, rawIncrement, rawMin] = Utils.splitFirst(target, ',', 2).map(toID);\n\t\t\tconst turns = parseInt(rawTurns);\n\t\t\tif (isNaN(turns) || turns < 0) {\n\t\t\t\treturn this.errorReply(`Turns must be a number above 0.`);\n\t\t\t}\n\t\t\tconst increment = parseInt(rawIncrement);\n\t\t\tif (isNaN(increment) || increment < 0) {\n\t\t\t\treturn this.errorReply(`The increment must be a number above 0.`);\n\t\t\t}\n\t\t\tconst min = parseInt(rawMin);\n\t\t\tif (rawMin && isNaN(min)) {\n\t\t\t\treturn this.errorReply(`Invalid minimum (must be a number).`);\n\t\t\t}\n\t\t\tsettings.thresholdIncrement = { amount: increment, turns };\n\t\t\tif (min) {\n\t\t\t\tsettings.thresholdIncrement.minTurns = min;\n\t\t\t}\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(\n\t\t\t\t`${user.name} set the abuse-monitor threshold increment ${increment} every ${Chat.count(turns, 'turns')}` +\n\t\t\t\t`${min ? ` after ${Chat.count(min, 'turns')}` : \"\"}`\n\t\t\t);\n\t\t\tthis.globalModlog(\n\t\t\t\t`ABUSEMONITOR INCREMENT`, null, `${increment} every ${turns} turn(s)${min ? ` after ${min} turn(s)` : \"\"}`\n\t\t\t);\n\t\t},\n\t\tdi: 'deleteincrement',\n\t\tdeleteincrement(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!settings.thresholdIncrement) return this.errorReply(`The threshold increment is already disabled.`);\n\t\t\tsettings.thresholdIncrement = null;\n\t\t\tsaveSettings();\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t\tthis.privateGlobalModAction(`${user.name} disabled the abuse-monitor threshold increment.`);\n\t\t\tthis.globalModlog(`ABUSEMONITOR DISABLEINCREMENT`);\n\t\t},\n\t\tasync failures(target) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!toID(target)) {\n\t\t\t\ttarget = Chat.toTimestamp(new Date()).split(' ')[0];\n\t\t\t}\n\t\t\tconst timeNum = new Date(target).getTime();\n\t\t\tif (isNaN(timeNum)) {\n\t\t\t\treturn this.errorReply(`Invalid date.`);\n\t\t\t}\n\t\t\tlet logs = await Chat.database.all(\n\t\t\t\t'SELECT * FROM perspective_stats WHERE result = 0 AND timestamp > ? AND timestamp < ?',\n\t\t\t\t[timeNum, timeNum + 24 * 60 * 60 * 1000]\n\t\t\t);\n\t\t\tlogs = logs.filter(log => ( // proofing against node's stupid date lib\n\t\t\t\tChat.toTimestamp(new Date(log.timestamp)).split(' ')[0] === target\n\t\t\t));\n\t\t\tif (!logs.length) {\n\t\t\t\treturn this.errorReply(`No logs found for that date.`);\n\t\t\t}\n\t\t\tthis.sendReplyBox(\n\t\t\t\t`<strong>${Chat.count(logs, 'logs')}</strong> found on the date ${target}:<hr />` +\n\t\t\t\tlogs.map(f => `<a href=\"/${f.roomid}\">${f.roomid}</a>`).join('<br />')\n\t\t\t);\n\t\t},\n\t\tbs: 'backupsettings',\n\t\tasync backupsettings(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\ttarget = target.replace(/\\//g, '-').toLowerCase().trim();\n\t\t\tlet dotIdx = target.lastIndexOf('.');\n\t\t\tif (dotIdx < 0) {\n\t\t\t\tdotIdx = target.length;\n\t\t\t}\n\t\t\ttarget = target.toLowerCase().slice(0, dotIdx);\n\t\t\tif (target) {\n\t\t\t\ttarget = `/artemis/${target}`;\n\t\t\t\tawait FS(`config/chat-plugins/artemis/`).mkdirIfNonexistent();\n\t\t\t} else {\n\t\t\t\ttarget = `/nf.backup`;\n\t\t\t}\n\t\t\tsaveSettings(target);\n\t\t\tthis.addGlobalModAction(`${user.name} used /abusemonitor backupsettings`);\n\t\t\tthis.stafflog(`Logged to ${target || \"default location\"}`);\n\t\t\tif (target) { // named? probably relevant\n\t\t\t\tthis.globalModlog(`ABUSEMONITOR BACKUP`, null, target);\n\t\t\t}\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t},\n\t\tlb: 'loadbackup',\n\t\tasync loadbackup(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tlet path = `nf.backup`;\n\t\t\tif (target) {\n\t\t\t\tpath = `artemis/${target.toLowerCase().replace(/\\//g, '-')}`;\n\t\t\t}\n\t\t\tconst backup = await FS(`config/chat-plugins/${path}.json`).readIfExists();\n\t\t\tif (!backup) return this.errorReply(`No backup settings saved.`);\n\t\t\tconst backupSettings = JSON.parse(backup);\n\t\t\tObject.assign(settings, backupSettings);\n\t\t\tsaveSettings();\n\t\t\tthis.addGlobalModAction(`${user.name} used /abusemonitor loadbackup`);\n\t\t\tthis.stafflog(`Loaded ${path}`);\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t},\n\t\tasync deletebackup(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\ttarget = target.toLowerCase().replace(/\\//g, '-');\n\t\t\tif (!target) return this.errorReply(`Specify a backup file.`);\n\t\t\tconst path = FS(`config/chat-plugins/artemis/${target}.json`);\n\t\t\tif (!(await path.exists())) {\n\t\t\t\treturn this.errorReply(`Backup '${target}' not found.`);\n\t\t\t}\n\t\t\tawait path.unlinkIfExists();\n\t\t\tthis.globalModlog(`ABUSEMONITOR DELETEBACKUP`, null, target);\n\t\t\tthis.sendReply(`Backup '${target}' deleted.`);\n\t\t\tthis.privateGlobalModAction(`${user.name} deleted the abuse-monitor backup '${target}'`);\n\t\t},\n\t\tasync backups() {\n\t\t\tcheckAccess(this);\n\t\t\tlet buf = `<strong>Artemis backups:</strong><br />`;\n\t\t\tconst files = await FS(`config/chat-plugins/artemis`).readdirIfExists();\n\t\t\tif (!files.length) {\n\t\t\t\tbuf += `No backups found.`;\n\t\t\t} else {\n\t\t\t\tbuf += files.map(f => {\n\t\t\t\t\tconst fName = f.slice(0, f.lastIndexOf('.'));\n\t\t\t\t\tlet line = `&bull; ${fName} `;\n\t\t\t\t\tline += `<button name=\"send\" value=\"/abusemonitor deletebackup ${fName}\">Delete</button> `;\n\t\t\t\t\tline += `<button name=\"send\" value=\"/abusemonitor loadbackup ${fName}\">Load</button>`;\n\t\t\t\t\treturn line;\n\t\t\t\t}).join('<br />');\n\t\t\t}\n\t\t\tthis.sendReplyBox(buf);\n\t\t},\n\t\ttogglepunishments(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tlet message;\n\t\t\tif (this.meansYes(target)) {\n\t\t\t\tif (!settings.recommendOnly) {\n\t\t\t\t\treturn this.errorReply(`Automatic punishments are already enabled.`);\n\t\t\t\t}\n\t\t\t\tsettings.recommendOnly = false;\n\t\t\t\tmessage = `${user.name} enabled automatic punishments for the Artemis battle monitor`;\n\t\t\t} else if (this.meansNo(target)) {\n\t\t\t\tif (settings.recommendOnly) {\n\t\t\t\t\treturn this.errorReply(`Automatic punishments are already disabled.`);\n\t\t\t\t}\n\t\t\t\tsettings.recommendOnly = true;\n\t\t\t\tmessage = `${user.name} disabled automatic punishments for the Artemis battle monitor`;\n\t\t\t} else {\n\t\t\t\treturn this.sendReply(`Automatic punishments are: ${!settings.recommendOnly ? 'ON' : 'OFF'}.`);\n\t\t\t}\n\t\t\tthis.privateGlobalModAction(message);\n\t\t\tthis.globalModlog(`ABUSEMONITOR TOGGLE`, null, settings.recommendOnly ? 'off' : 'on');\n\t\t\tsaveSettings();\n\t\t},\n\t\treview() {\n\t\t\tthis.checkCan('lock');\n\t\t\treturn this.parse(`/join view-abusemonitor-review`);\n\t\t},\n\t\treviews() {\n\t\t\tcheckAccess(this);\n\t\t\treturn this.parse(`/join view-abusemonitor-reviews`);\n\t\t},\n\t\tasync submitreview(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tif (!target) return this.parse(`/help abusemonitor submitreview`);\n\t\t\tconst [roomid, reason] = Utils.splitFirst(target, ',').map(f => f.trim());\n\t\t\tconst log = await getBattleLog(getBattleLinks(roomid)[0] || \"\");\n\t\t\tif (!log) {\n\t\t\t\treturn this.popupReply(`No logs found for that roomid.`);\n\t\t\t}\n\t\t\tif (reviews[user.id]?.some(f => f.room === roomid)) {\n\t\t\t\treturn this.popupReply(`You have already submitted a review for this room.`);\n\t\t\t}\n\t\t\tif (reason.length < 1 || reason.length > 2000) {\n\t\t\t\treturn this.popupReply(`Your review must be between 1 and 2000 characters.`);\n\t\t\t}\n\t\t\t(reviews[user.id] ||= []).push({\n\t\t\t\troom: roomid,\n\t\t\t\tdetails: reason,\n\t\t\t\tstaff: user.id,\n\t\t\t\ttime: Date.now(),\n\t\t\t});\n\t\t\tsaveReviews();\n\t\t\tChat.refreshPageFor('abusemonitor-reviews', 'staff');\n\t\t\tthis.closePage('abusemonitor-review');\n\t\t\tthis.popupReply(`Your review has been submitted.`);\n\t\t},\n\t\tresolvereview(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tlet [userid, roomid, accurate, result] = Utils.splitFirst(target, ',', 3).map(f => f.trim());\n\t\t\tuserid = toID(userid);\n\t\t\troomid = getBattleLinks(roomid)[0] || \"\";\n\t\t\tif (!userid || !roomid || !accurate || !result) {\n\t\t\t\treturn this.parse(`/help abusemonitor resolvereview`);\n\t\t\t}\n\t\t\tif (!reviews[userid]) {\n\t\t\t\treturn this.errorReply(`No reviews found by that user.`);\n\t\t\t}\n\t\t\tconst review = reviews[userid].find(f => getBattleLinks(f.room).includes(roomid));\n\t\t\tif (!review) {\n\t\t\t\treturn this.errorReply(`No reviews found by that user for that room.`);\n\t\t\t}\n\t\t\tconst isAccurate = Number(accurate);\n\t\t\tif (isNaN(isAccurate) || isAccurate < 0 || isAccurate > 1) {\n\t\t\t\treturn this.popupReply(`Invalid accuracy. Must be a number between 0 and 1.`);\n\t\t\t}\n\t\t\tif (review.resolved) {\n\t\t\t\treturn this.errorReply(`That review has already been resolved.`);\n\t\t\t}\n\t\t\treview.resolved = {\n\t\t\t\tby: user.id,\n\t\t\t\ttime: Date.now(),\n\t\t\t\tdetails: result,\n\t\t\t\tresult: isAccurate,\n\t\t\t};\n\t\t\tdisplayResolved(review, true);\n\t\t\twriteStats('reviews', review);\n\t\t\tChat.refreshPageFor('abusemonitor-reviews', 'staff');\n\t\t},\n\t\treplace(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!target) return this.parse(`/help am`);\n\t\t\tconst [old, newWord] = target.split(',');\n\t\t\tif (!old || !newWord) return this.errorReply(`Invalid arguments - must be [oldWord], [newWord].`);\n\t\t\tif (toID(old) === toID(newWord)) return this.errorReply(`The old word and the new word are the same.`);\n\t\t\tif (settings.replacements[old]) {\n\t\t\t\treturn this.errorReply(`The old word '${old}' is already in use (for '${settings.replacements[old]}').`);\n\t\t\t}\n\t\t\tChat.validateRegex(target);\n\t\t\tsettings.replacements[old] = newWord;\n\t\t\tsaveSettings();\n\t\t\tthis.privateGlobalModAction(`${user.name} added an Artemis replacement for '${old}' to '${newWord}'.`);\n\t\t\tthis.globalModlog(`ABUSEMONITOR REPLACE`, null, `'${old}' to '${newWord}'`);\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t},\n\t\tremovereplace(target, room, user) {\n\t\t\tcheckAccess(this);\n\t\t\tif (!target) return this.parse(`/help am`);\n\t\t\tconst replaceTo = settings.replacements[target];\n\t\t\tif (!replaceTo) {\n\t\t\t\treturn this.errorReply(`${target} is not a currently set replacement.`);\n\t\t\t}\n\t\t\tdelete settings.replacements[target];\n\t\t\tsaveSettings();\n\t\t\tthis.privateGlobalModAction(`${user.name} removed the Artemis replacement for ${target}`);\n\t\t\tthis.globalModlog(`ABUSEMONITOR REMOVEREPLACEMENT`, null, `${target} (=> ${replaceTo})`);\n\t\t\tthis.refreshPage('abusemonitor-settings');\n\t\t},\n\t\tedithistory(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = toID(target);\n\t\t\tif (!target) {\n\t\t\t\treturn this.parse(`/help abusemonitor`);\n\t\t\t}\n\t\t\treturn this.parse(`/j view-abusemonitor-edithistory-${target}`);\n\t\t},\n\t\tignoremodlog: {\n\t\t\tadd(target, room, user) {\n\t\t\t\tthis.checkCan('lock');\n\t\t\t\tlet targetUser: string;\n\t\t\t\t[targetUser, target] = this.splitOne(target).map(f => f.trim());\n\t\t\t\ttargetUser = toID(targetUser);\n\t\t\t\tif (!targetUser || !target) {\n\t\t\t\t\treturn this.popupReply(\n\t\t\t\t\t\t`Must specify a user and a target date (or modlog entry number).`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tif (!metadata.modlogIgnores) metadata.modlogIgnores = {};\n\t\t\t\tconst num = Number(target);\n\t\t\t\tif (isNaN(num)) {\n\t\t\t\t\tif (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(target)) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid date provided. Must be in YYYY-MM-DD format.`);\n\t\t\t\t\t}\n\t\t\t\t\tmetadata.modlogIgnores[targetUser] = target;\n\t\t\t\t\ttarget = 'before and including ' + target;\n\t\t\t\t} else {\n\t\t\t\t\tlet ignores = metadata.modlogIgnores[targetUser];\n\t\t\t\t\tif (!Array.isArray(ignores)) {\n\t\t\t\t\t\tmetadata.modlogIgnores[targetUser] = ignores = [];\n\t\t\t\t\t}\n\t\t\t\t\tif (ignores.includes(num)) {\n\t\t\t\t\t\treturn this.errorReply(`That modlog entry is already ignored.`);\n\t\t\t\t\t}\n\t\t\t\t\tignores.push(num);\n\t\t\t\t\ttarget = `entry #${target}`;\n\t\t\t\t}\n\t\t\t\tthis.globalModlog(`ABUSEMONITOR MODLOGIGNORE`, targetUser, target);\n\t\t\t\tsaveMetadata();\n\t\t\t\tthis.refreshPage(`abusemonitor-edithistory-${targetUser}`);\n\t\t\t},\n\t\t\tremove(target, room, user) {\n\t\t\t\tthis.checkCan('lock');\n\t\t\t\tlet [targetUser, rawNum] = this.splitOne(target).map(f => f.trim());\n\t\t\t\ttargetUser = toID(targetUser);\n\t\t\t\tconst num = Number(rawNum);\n\t\t\t\tif (!targetUser || !rawNum) {\n\t\t\t\t\treturn this.popupReply(\n\t\t\t\t\t\t`Specify a target user and a target (either a modlog entry # or a date).`\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst entry = metadata.modlogIgnores?.[targetUser];\n\t\t\t\tif (!entry) {\n\t\t\t\t\treturn this.errorReply(`That user has no ignored modlog entries registered.`);\n\t\t\t\t}\n\t\t\t\tif (typeof entry === 'string') {\n\t\t\t\t\trawNum = entry;\n\t\t\t\t\tdelete metadata.modlogIgnores![targetUser];\n\t\t\t\t} else {\n\t\t\t\t\tif (isNaN(num)) {\n\t\t\t\t\t\treturn this.errorReply(`Invalid modlog entry number: ${num}`);\n\t\t\t\t\t}\n\t\t\t\t\tconst idx = entry.indexOf(num);\n\t\t\t\t\tif (idx === -1) {\n\t\t\t\t\t\treturn this.errorReply(`That modlog entry is not ignored for the user ${targetUser}.`);\n\t\t\t\t\t}\n\t\t\t\t\tentry.splice(idx, 1);\n\t\t\t\t\tif (!entry.length) {\n\t\t\t\t\t\tdelete metadata.modlogIgnores![targetUser];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tsaveMetadata();\n\t\t\t\tthis.globalModlog(`ABUSEMONITOR REMOVEMODLOGIGNORE`, targetUser, rawNum);\n\t\t\t\tthis.refreshPage(`abusemonitor-edithistory-${targetUser}`);\n\t\t\t},\n\t\t},\n\t},\n\tabusemonitorhelp() {\n\t\treturn this.sendReplyBox([\n\t\t\t`<strong>Staff commands:</strong>`,\n\t\t\t`/am userlogs [user] - View the Artemis flagged message logs for the given [user]. Requires: % @ ~`,\n\t\t\t`/am unmute [user] - Remove the Artemis mute from the given [user]. Requires: % @ ~`,\n\t\t\t`/am review - Submit feedback for manual abuse monitor review. Requires: % @ ~`,\n\t\t\t`</details><br /><details class=\"readmore\"><summary><strong>Management commands:</strong></summary>`,\n\t\t\t`/am toggle - Toggle the abuse monitor on and off. Requires: whitelist ~`,\n\t\t\t`/am threshold [number] - Set the abuse monitor trigger threshold. Requires: whitelist ~`,\n\t\t\t`/am resolve [room] - Mark a abuse monitor flagged room as handled by staff. Requires: % @ ~`,\n\t\t\t`/am respawn - Respawns abuse monitor processes. Requires: whitelist ~`,\n\t\t\t`/am logs [count][, userid] - View logs of recent matches by the abuse monitor. `,\n\t\t\t`If a userid is given, searches only logs from that userid. Requires: whitelist ~`,\n\t\t\t`/am edithistory [user] - Clear specific abuse monitor hit(s) for a user. Requires: % @ ~`,\n\t\t\t`/am userclear [user] - Clear all logged abuse monitor hits for a user. Requires: whitelist ~`,\n\t\t\t`/am deletelog [number] - Deletes a abuse monitor log matching the row ID [number] given. Requires: whitelist ~`,\n\t\t\t`/am editspecial [type], [percent], [score] - Sets a special case for the abuse monitor. Requires: whitelist ~`,\n\t\t\t`[score] can be either a number or MAXIMUM, which will set it to the maximum score possible (that will trigger an action)`,\n\t\t\t`/am deletespecial [type], [percent] - Deletes a special case for the abuse monitor. Requires: whitelist ~`,\n\t\t\t`/am editmin [number] - Sets the minimum percent needed to process for all flags. Requires: whitelist ~`,\n\t\t\t`/am viewsettings - View the current settings for the abuse monitor. Requires: whitelist ~`,\n\t\t\t`/am thresholdincrement [num], [amount][, min turns] - Sets the threshold increment for the abuse monitor to increase [amount] every [num] turns.`,\n\t\t\t`If [min turns] is provided, increments will start after that turn number. Requires: whitelist ~`,\n\t\t\t`/am deleteincrement - clear abuse-monitor threshold increment. Requires: whitelist ~`,\n\t\t\t`</details>`,\n\t\t].join('<br />'));\n\t},\n};\n\nexport const pages: Chat.PageTable = {\n\tabusemonitor: {\n\t\tflagged(query, user) {\n\t\t\tcheckAccess(this, 'lock');\n\t\t\tconst ids = getFlaggedRooms();\n\t\t\tthis.title = '[Abuse Monitor] Flagged rooms';\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tbuf += `<h2>Flagged rooms</h2>`;\n\t\t\tif (!ids.length) {\n\t\t\t\tbuf += `<p class=\"error\">No rooms have been flagged recently.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tbuf += `<p>Currently flagged rooms: ${ids.length}</p>`;\n\t\t\tbuf += `<div class=\"ladder pad\">`;\n\t\t\tbuf += `<table><tr><th>Status</th><th>Room</th><th>Claimed by</th><th>Action</th></tr>`;\n\t\t\tfor (const roomid of ids) {\n\t\t\t\tconst entry = cache[roomid];\n\t\t\t\tbuf += `<tr>`;\n\t\t\t\tif (entry.claimed) {\n\t\t\t\t\tbuf += `<td><span style=\"color:green\">`;\n\t\t\t\t\tbuf += `<i class=\"fa fa-circle-o\"></i> <strong>Claimed</strong></span></td>`;\n\t\t\t\t} else {\n\t\t\t\t\tbuf += `<td><span style=\"color:orange\">`;\n\t\t\t\t\tbuf += `<i class=\"fa fa-circle-o\"></i> <strong>Unclaimed</strong></span></td>`;\n\t\t\t\t}\n\t\t\t\t// should never happen, fallback just in case\n\t\t\t\tbuf += Utils.html`<td>${Rooms.get(roomid)?.title || roomid}</td>`;\n\t\t\t\tbuf += `<td>${entry.claimed ? entry.claimed : '-'}</td>`;\n\t\t\t\tbuf += `<td><button class=\"button\" name=\"send\" value=\"/am view ${roomid}\">`;\n\t\t\t\tbuf += `${entry.claimed ? 'Show' : 'Claim'}</button></td>`;\n\t\t\t\tbuf += `</tr>`;\n\t\t\t}\n\t\t\tbuf += `</table></div>`;\n\t\t\treturn buf;\n\t\t},\n\t\tasync view(query, user) {\n\t\t\tcheckAccess(this, 'lock');\n\t\t\tconst roomid = query.join('-') as RoomID;\n\t\t\tif (!toID(roomid)) {\n\t\t\t\treturn this.errorReply(`You must specify a roomid to view abuse monitor data for.`);\n\t\t\t}\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tbuf += `<button style=\"float:right;\" class=\"button\" name=\"send\" value=\"/join ${this.pageid}\">`;\n\t\t\tbuf += `<i class=\"fa fa-refresh\"></i> Refresh</button>`;\n\t\t\tbuf += `<h2>Abuse Monitor`;\n\t\t\tconst room = Rooms.get(roomid);\n\t\t\tif (!room) {\n\t\t\t\tif (cache[roomid]) {\n\t\t\t\t\tdelete cache[roomid];\n\t\t\t\t\tnotifyStaff();\n\t\t\t\t}\n\t\t\t\tbuf += `</h2><hr /><p class=\"error\">No such room.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\troom.pokeExpireTimer(); // don't want it to expire while staff are reviewing\n\t\t\tif (!cache[roomid]) {\n\t\t\t\tbuf += `</h2><hr /><p class=\"error\">The abuse monitor has not flagged the given room.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tconst titleParts = room.roomid.split('-');\n\t\t\tif (titleParts[titleParts.length - 1].endsWith('pw')) {\n\t\t\t\ttitleParts.pop(); // remove password\n\t\t\t}\n\t\t\tbuf += Utils.html` - ${room.title}</h2>`;\n\t\t\tthis.title = `[Abuse Monitor] ${titleParts.join('-')}`;\n\t\t\tbuf += `<p>${Chat.formatText(`<<${room.roomid}>>`)}</p>`;\n\t\t\tbuf += `<hr />`;\n\t\t\tif (!cache[roomid].claimed) {\n\t\t\t\tcache[roomid].claimed = user.id;\n\t\t\t\tnotifyStaff();\n\t\t\t} else {\n\t\t\t\tbuf += `<p><strong>Claimed:</strong> ${cache[roomid].claimed}</p>`;\n\t\t\t}\n\n\t\t\tbuf += `<details class=\"readmore\"><summary><strong>Chat:</strong></summary><div class=\"infobox\">`;\n\t\t\t// we parse users specifically from the log so we can see it after they leave the room\n\t\t\tconst users = new Utils.Multiset<string>();\n\t\t\tconst logData = await getBattleLog(room.roomid, true);\n\t\t\t// should only extremely rarely happen - if the room expires while this is happening.\n\t\t\tif (!logData) return `<div class=\"pad\"><p class=\"error\">No such room.</p></div>`;\n\t\t\t// assume logs exist - why else would the filter activate?\n\t\t\tfor (const line of logData.log) {\n\t\t\t\tconst data = room.log.parseChatLine(line);\n\t\t\t\tif (!data) continue; // not chat\n\t\t\t\tif (['/log', '/raw'].some(prefix => data.message.startsWith(prefix))) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tconst id = toID(data.user);\n\t\t\t\tif (!id) continue;\n\t\t\t\tusers.add(id);\n\t\t\t\tbuf += `<div class=\"chat chatmessage\">`;\n\t\t\t\tbuf += `<strong style=\"color: ${HelpTicket.colorName(id, logData)}\">`;\n\t\t\t\tbuf += Utils.html`<span class=\"username\">${data.user}:</span></strong> ${data.message}</div>`;\n\t\t\t}\n\t\t\tbuf += `</div></details>`;\n\t\t\tconst recs = cache[roomid].recommended || {};\n\t\t\tif (Object.keys(recs).length) {\n\t\t\t\tfor (const id in recs) {\n\t\t\t\t\tconst rec = recs[id];\n\t\t\t\t\tbuf += `<p><strong>Recommended action for ${id}:</strong> ${rec.type} (${rec.reason})</p>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += `<p><strong>Users:</strong><small> (click a name to punish)</small></p>`;\n\t\t\tconst sortedUsers = Utils.sortBy([...users], ([id, num]) => (\n\t\t\t\t[isFlaggedUserid(id, roomid), -num, id]\n\t\t\t));\n\t\t\tfor (const [id] of sortedUsers) {\n\t\t\t\tconst curUser = Users.getExact(id);\n\t\t\t\tbuf += Utils.html`<details class=\"readmore\"><summary>${curUser?.name || id} `;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/mlid ${id},room=global\">Modlog</button>`;\n\t\t\t\tbuf += `</summary><div class=\"infobox\">`;\n\t\t\t\tconst punishments = ['Warn', 'Lock', 'Weeklock', 'Forcerename', 'Namelock', 'Weeknamelock'];\n\t\t\t\tfor (const name of punishments) {\n\t\t\t\t\tbuf += `<form data-submitsend=\"/am nojoinpunish ${roomid},${toID(name)},${id},{reason}\">`;\n\t\t\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">${name}</button><br />`;\n\t\t\t\t\tbuf += `Optional reason: <input name=\"reason\" />`;\n\t\t\t\t\tbuf += `</form><br />`;\n\t\t\t\t}\n\t\t\t\tbuf += `</div></details><br />`;\n\t\t\t}\n\t\t\tbuf += `<hr /><strong>Mark resolved:</strong><br />`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff, /am resolve ${room.roomid},success\">As accurate flag</button> | `;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff, /am resolve ${room.roomid},failure\">As inaccurate flag</button>`;\n\t\t\treturn buf;\n\t\t},\n\t\tasync userlogs(query, user) {\n\t\t\t// separate from logs bc logs presents all sorts of data. this only needs time/room/user/message\n\t\t\t// as so to not overwhelm staff\n\t\t\tthis.checkCan('lock');\n\t\t\tlet buf = `<div class=\"pad\"><h2>Artemis user logs</h2><hr />`;\n\t\t\tconst userid = toID(query.shift());\n\t\t\tif (!userid || userid.length > 18) {\n\t\t\t\tbuf += `<p class=\"message-error\">Invalid username.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tthis.title = `[Artemis Logs] ${userid}`;\n\t\t\t// hardcoding this limit bc no single user should ever really break it\n\t\t\tconst logs = await Chat.database.all(`SELECT * FROM perspective_logs WHERE userid = ? LIMIT 100`, [userid]);\n\t\t\tif (!logs.length) {\n\t\t\t\tbuf += `<p class=\"message-error\">No logs found.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tbuf += `<div class=\"ladder pad\"><table><tr><th>Date</th><th>Room</th><th>User</th><th>Message</th></tr>`;\n\t\t\tUtils.sortBy(logs, log => -log.time);\n\t\t\tfor (const log of logs) {\n\t\t\t\tbuf += `<tr><td>${Chat.toTimestamp(new Date(log.time), { human: true })}</td>`;\n\t\t\t\tbuf += `<td><a href=\"/${log.roomid}\">${log.roomid}</a></td>`;\n\t\t\t\tbuf += Utils.html`<td>${log.userid}</td><td>${log.message}</td></tr>`;\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\tasync logs(query, user) {\n\t\t\tcheckAccess(this);\n\t\t\tthis.title = '[Abuse Monitor] Logs';\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tbuf += `<h2>Abuse Monitor Logs</h2><hr />`;\n\t\t\tconst rawCount = query.shift() || \"\";\n\t\t\tlet count = 200;\n\t\t\tif (rawCount) {\n\t\t\t\tcount = parseInt(rawCount);\n\t\t\t\tif (isNaN(count)) {\n\t\t\t\t\tbuf += `<p class=\"message-error\">Invalid limit specified: ${rawCount}</p>`;\n\t\t\t\t\treturn buf;\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst userid = toID(query.shift());\n\t\t\tlet logQuery = `SELECT rowid, * FROM perspective_logs `;\n\t\t\tconst args = [];\n\t\t\tif (userid) {\n\t\t\t\tlogQuery += `WHERE userid = ? `;\n\t\t\t\targs.push(userid);\n\t\t\t}\n\t\t\tlogQuery += `ORDER BY rowid DESC LIMIT ?`;\n\t\t\targs.push(count);\n\n\t\t\tconst logs = await Chat.database.all(logQuery, args);\n\t\t\tif (!logs.length) {\n\t\t\t\tbuf += `<p class=\"message-error\">No logs found${userid ? ` for the user ${userid}` : \"\"}.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tUtils.sortBy(logs, log => [-log.time, log.roomid, log.userid]);\n\t\t\tbuf += `<p>${logs.length} log(s) found.</p>`;\n\t\t\tbuf += `<div class=\"ladder pad\">`;\n\t\t\tbuf += `<table><tr><th>Room</th>`;\n\t\t\tif (!userid) {\n\t\t\t\tbuf += `<th>User</th>`;\n\t\t\t}\n\t\t\tbuf += `<th>Message</th>`;\n\t\t\tbuf += `<th>Time</th><th>Score / Flags</th><th>Other data</th><th>Manage</th></tr>`;\n\t\t\tconst prettifyFlag = (flag: string) => flag.toLowerCase().replace(/_/g, ' ');\n\t\t\tfor (const log of logs) {\n\t\t\t\tconst { roomid } = log;\n\t\t\t\tbuf += `<tr>`;\n\t\t\t\tbuf += `<td><a href=\"https://${Config.routes.replays}/${roomid.slice(7)}\">${roomid}</a></td>`;\n\t\t\t\tif (!userid) buf += `<td>${log.userid}</td>`;\n\t\t\t\tbuf += Utils.html`<td>${log.message}</td>`;\n\t\t\t\tbuf += `<td>${Chat.toTimestamp(new Date(log.time))}</td>`;\n\t\t\t\tbuf += `<td>${log.score} (${log.flags.split(',').map(prettifyFlag).join(', ')})</td>`;\n\t\t\t\tbuf += `<td>Hit threshold: ${log.hit_threshold ? 'Yes' : 'No'}</td><td>`;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/abusemonitor deletelog ${log.rowid}\">Delete</button>`;\n\t\t\t\tbuf += `</td>`;\n\t\t\t\tbuf += `</tr>`;\n\t\t\t}\n\t\t\tbuf += `</table></div>`;\n\t\t\t// assume this probably means there are more.\n\t\t\t// if there's less than the count we requested, that's as far as it goes.\n\t\t\tif (count === logs.length) {\n\t\t\t\tbuf += `<center>`;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff, /am logs ${count + 100}\">Show 100 more</button>`;\n\t\t\t\tbuf += `</center>`;\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\tasync stats(query, user) {\n\t\t\tcheckAccess(this);\n\t\t\tconst dateString = (query.join('-') || Chat.toTimestamp(new Date())).slice(0, 7);\n\t\t\tif (!/^[0-9]{4}-[0-9]{2}$/.test(dateString)) {\n\t\t\t\treturn this.errorReply(`Invalid date: ${dateString}`);\n\t\t\t}\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tbuf += `<button style=\"float:right;\" class=\"button\" name=\"send\" value=\"/join ${this.pageid}\">`;\n\t\t\tbuf += `<i class=\"fa fa-refresh\"></i> Refresh</button>`;\n\t\t\tbuf += `<h2>Abuse Monitor stats for ${dateString}</h2>`;\n\t\t\tconst next = nextMonth(dateString);\n\t\t\tconst prev = new Date(new Date(`${dateString}-15`).getTime() - (30 * 24 * 60 * 60 * 1000)).toISOString().slice(0, 7);\n\t\t\tbuf += `<a class=\"button\" target=\"replace\" href=\"/view-abusemonitor-stats-${prev}-15\">Previous month</a> | `;\n\t\t\tbuf += `<a class=\"button\" target=\"replace\" href=\"/view-abusemonitor-stats-${next}-15\">Next month</a>`;\n\t\t\tbuf += `<hr />`;\n\t\t\tconst logs = await Chat.database.all(\n\t\t\t\t`SELECT * FROM perspective_stats WHERE timestamp > ? AND timestamp < ?`,\n\t\t\t\t[new Date(dateString + '-01').getTime(), new Date(nextMonth(dateString)).getTime()]\n\t\t\t);\n\t\t\tthis.title = '[Abuse Monitor] Stats';\n\t\t\tif (!logs.length) {\n\t\t\t\tbuf += `<p class=\"message-error\">No logs found for the month ${dateString}.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tthis.title += ` ${dateString}`;\n\t\t\tbuf += `<p>${Chat.count(logs.length, 'logs')} found.</p>`;\n\t\t\tlet successes = 0;\n\t\t\tlet failures = 0;\n\t\t\tlet dead = 0;\n\t\t\tconst staffStats: Record<string, number> = {};\n\t\t\tconst dayStats: Record<string, { successes: number, failures: number, dead: number, total: number }> = {};\n\t\t\tfor (const log of logs) {\n\t\t\t\tconst cur = Chat.toTimestamp(new Date(log.timestamp)).split(' ')[0];\n\t\t\t\tif (!dayStats[cur]) dayStats[cur] = { successes: 0, failures: 0, dead: 0, total: 0 };\n\t\t\t\tif (log.result === 2) {\n\t\t\t\t\tdead++;\n\t\t\t\t\tdayStats[cur].dead++;\n\t\t\t\t\t// don't increment total - we don't want dead to count in the percentages\n\t\t\t\t\tcontinue;\n\t\t\t\t} else if (log.result === 1) {\n\t\t\t\t\tsuccesses++;\n\t\t\t\t\tdayStats[cur].successes++;\n\t\t\t\t} else {\n\t\t\t\t\tfailures++;\n\t\t\t\t\tdayStats[cur].failures++;\n\t\t\t\t}\n\t\t\t\tif (!staffStats[log.staff]) staffStats[log.staff] = 0;\n\t\t\t\tstaffStats[log.staff]++;\n\t\t\t\tdayStats[cur].total++;\n\t\t\t}\n\t\t\tconst percent = (numerator: number, denom: number) => Math.floor((numerator / denom) * 100) || 0;\n\t\t\tbuf += `<p><strong>Success rate:</strong> ${percent(successes, successes + failures)}% (${successes})</p>`;\n\t\t\tbuf += `<p><strong>Failure rate:</strong> ${percent(failures, successes + failures)}% (${failures})</p>`;\n\t\t\tbuf += `<p><details class=\"readmore\"><summary><strong>Stats including dead flags</strong></summary>`;\n\t\t\tbuf += `<p><strong>Total dead: ${dead}</strong></p>`;\n\t\t\tbuf += `<p><strong>Success rate:</strong> ${percent(successes, logs.length)}% (${successes})</p>`;\n\t\t\tbuf += `<p><strong>Failure rate:</strong> ${percent(failures, logs.length)}% (${failures})</p>`;\n\t\t\tbuf += `</summary></details></p>`;\n\t\t\tbuf += `<p><strong>Day stats:</strong></p>`;\n\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\tlet header = '';\n\t\t\tlet data = '';\n\t\t\tconst sortedDays = Utils.sortBy(Object.keys(dayStats), d => new Date(d).getTime());\n\t\t\tfor (const [i, day] of sortedDays.entries()) {\n\t\t\t\tconst cur = dayStats[day];\n\t\t\t\tif (!cur.total) continue;\n\t\t\t\theader += `<th>${day.split('-')[2]} (${cur.total})</th>`;\n\t\t\t\tdata += `<td><small>${cur.successes} (${percent(cur.successes, cur.total)}%)`;\n\t\t\t\tif (cur.failures) {\n\t\t\t\t\tdata += ` | ${cur.failures} (${percent(cur.failures, cur.total)}%)`;\n\t\t\t\t} else { // so one cannot confuse dead tickets ~ false hit tickets\n\t\t\t\t\tdata += ' | 0 (0%)';\n\t\t\t\t}\n\t\t\t\tif (cur.dead) data += ` | ${cur.dead}`;\n\t\t\t\tdata += '</small></td>';\n\t\t\t\t// i + 1 ensures it's above 0 always (0 % 5 === 0)\n\t\t\t\tif ((i + 1) % 5 === 0 && sortedDays[i + 1]) {\n\t\t\t\t\tbuf += `<tr>${header}</tr><tr>${data}</tr>`;\n\t\t\t\t\tbuf += `</div></table>`;\n\t\t\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\t\t\theader = '';\n\t\t\t\t\tdata = '';\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += `<tr>${header}</tr><tr>${data}</tr>`;\n\t\t\tbuf += `</div></table>`;\n\t\t\tbuf += `<hr /><p><strong>Punishment stats:</strong></p>`;\n\t\t\tconst punishmentStats = {\n\t\t\t\tinaccurate: 0,\n\t\t\t\ttotal: 0,\n\t\t\t\tbyDay: {} as Record<string, { total: number, inaccurate: number }>,\n\t\t\t\ttypes: {} as Record<string, number>,\n\t\t\t};\n\t\t\tconst inaccurate = new Set();\n\t\t\tconst logPath = Monitor.logPath(`artemis/punishments/${dateString}.jsonl`);\n\t\t\tif (await logPath.exists()) {\n\t\t\t\tconst stream = logPath.createReadStream();\n\t\t\t\tfor await (const line of stream.byLine()) {\n\t\t\t\t\tif (!line.trim()) continue;\n\t\t\t\t\tconst chunk = JSON.parse(line.trim());\n\t\t\t\t\tpunishmentStats.total++;\n\t\t\t\t\tif (!punishmentStats.types[chunk.punishment]) punishmentStats.types[chunk.punishment] = 0;\n\t\t\t\t\tpunishmentStats.types[chunk.punishment]++;\n\t\t\t\t\tconst day = Chat.toTimestamp(new Date(chunk.timestamp)).split(' ')[0];\n\t\t\t\t\tif (!punishmentStats.byDay[day]) punishmentStats.byDay[day] = { total: 0, inaccurate: 0 };\n\t\t\t\t\tpunishmentStats.byDay[day].total++;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst reviewLogPath = Monitor.logPath(`artemis/reviews/${dateString}.jsonl`);\n\t\t\tif (await reviewLogPath.exists()) {\n\t\t\t\tconst stream = reviewLogPath.createReadStream();\n\t\t\t\tfor await (const line of stream.byLine()) {\n\t\t\t\t\tif (!line.trim()) continue;\n\t\t\t\t\tconst chunk = JSON.parse(line.trim());\n\t\t\t\t\tif (!chunk.resolved.result) { // inaccurate punishment\n\t\t\t\t\t\tpunishmentStats.inaccurate++;\n\t\t\t\t\t\tinaccurate.add(chunk.room);\n\t\t\t\t\t\tconst day = Chat.toTimestamp(new Date(chunk.time)).split(' ')[0];\n\t\t\t\t\t\tif (!punishmentStats.byDay[day]) punishmentStats.byDay[day] = { total: 0, inaccurate: 0 };\n\t\t\t\t\t\tpunishmentStats.byDay[day].inaccurate++;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tbuf += `<p>Total punishments: ${punishmentStats.total}</p>`;\n\t\t\tconst accurate = punishmentStats.total - punishmentStats.inaccurate;\n\t\t\tbuf += `<p>Accurate punishments: ${accurate} (${percent(accurate, punishmentStats.total)}%)</p>`;\n\t\t\tbuf += `<details class=\"readmore\"><summary>Inaccurate punishments: ${punishmentStats.inaccurate} `;\n\t\t\tbuf += `(${percent(punishmentStats.inaccurate, punishmentStats.total)}%)</summary>`;\n\t\t\tbuf += Array.from(inaccurate).map(f => `<a href=\"/${f}\">${f}</a>`).join(', ');\n\t\t\tbuf += `</details>`;\n\n\t\t\tif (punishmentStats.total) {\n\t\t\t\tbuf += `<p><strong>Day stats:</strong></p>`;\n\t\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\t\theader = '';\n\t\t\t\tdata = '';\n\t\t\t\tconst sortedDayStats = Utils.sortBy(Object.keys(punishmentStats.byDay), d => new Date(d).getTime());\n\t\t\t\tfor (const [i, day] of sortedDayStats.entries()) {\n\t\t\t\t\tconst cur = punishmentStats.byDay[day];\n\t\t\t\t\tif (!cur.total) continue;\n\t\t\t\t\theader += `<th>${day.split('-')[2]} (${cur.total})</th>`;\n\t\t\t\t\tconst curAccurate = cur.total - cur.inaccurate;\n\t\t\t\t\tdata += `<td><small>${curAccurate} (${percent(curAccurate, cur.total)}%)`;\n\t\t\t\t\tif (cur.inaccurate) {\n\t\t\t\t\t\tdata += ` | ${cur.inaccurate} (${percent(cur.inaccurate, cur.total)}%)`;\n\t\t\t\t\t} else { // so one cannot confuse dead tickets ~ false hit tickets\n\t\t\t\t\t\tdata += ' | 0 (0%)';\n\t\t\t\t\t}\n\t\t\t\t\tdata += '</small></td>';\n\t\t\t\t\t// i + 1 ensures it's above 0 always (0 % 5 === 0)\n\t\t\t\t\tif ((i + 1) % 5 === 0 && sortedDays[i + 1]) {\n\t\t\t\t\t\tbuf += `<tr>${header}</tr><tr>${data}</tr>`;\n\t\t\t\t\t\tbuf += `</div></table>`;\n\t\t\t\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\t\t\t\theader = '';\n\t\t\t\t\t\tdata = '';\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbuf += `<tr>${header}</tr><tr>${data}</tr>`;\n\t\t\t\tbuf += `</div></table>`;\n\t\t\t\tbuf += `<br /><strong>Punishment breakdown:</strong><br />`;\n\t\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\t\tbuf += `<tr><th>Type</th><th>Count</th><th>Percent</th></tr>`;\n\t\t\t\tconst sorted = Utils.sortBy(Object.entries(punishmentStats.types), e => e[1]);\n\t\t\t\tfor (const [type, num] of sorted) {\n\t\t\t\t\tbuf += `<tr><td>${type}</td><td>${num}</td><td>${percent(num, punishmentStats.total)}%</td></tr>`;\n\t\t\t\t}\n\t\t\t\tbuf += `</table></div>`;\n\t\t\t}\n\t\t\tbuf += `<hr /><p><strong>Staff stats:</strong></p>`;\n\t\t\tbuf += `<div class=\"ladder pad\"><table>`;\n\t\t\tbuf += `<tr><th>User</th><th>Total</th><th>Percent total</th></tr>`;\n\t\t\tfor (const id of Utils.sortBy(Object.keys(staffStats), k => -staffStats[k])) {\n\t\t\t\tbuf += `<tr><td>${id}</td><td>${staffStats[id]}</td><td>${(staffStats[id] / logs.length) * 100}%</td></tr>`;\n\t\t\t}\n\t\t\tbuf += `</table></div>`;\n\t\t\treturn buf;\n\t\t},\n\t\tasync settings() {\n\t\t\tcheckAccess(this);\n\t\t\tthis.title = `[Abuse Monitor] Settings`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>Abuse Monitor Settings</h2>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/am vs\">Reload page</button>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am respawn\">Reload processes</button>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am bs\">Backup settings</button>`;\n\t\t\tif (await FS('config/chat-plugins/nf.backup.json').exists()) {\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am lb\">Load backup</button>`;\n\t\t\t}\n\t\t\tbuf += `<div class=\"infobox\"><h3>Miscellaneous settings</h3><hr />`;\n\t\t\tbuf += `Minimum percent to process: <form data-submitsend=\"/msgroom staff,/am editmin {num}\">`;\n\t\t\tbuf += `<input name=\"num\" value=\"${settings.minScore}\"/>`;\n\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Change minimum</button></form>`;\n\t\t\tbuf += `<br />Score threshold: <form data-submitsend=\"/msgroom staff,/am threshold {num}\">`;\n\t\t\tbuf += `<input name=\"num\" value=\"${settings.threshold}\"/>`;\n\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Change threshold</button></form>`;\n\t\t\tconst incr = settings.thresholdIncrement;\n\t\t\tif (incr) {\n\t\t\t\tbuf += `<br />Threshold increments: `;\n\t\t\t\tbuf += `Increases ${incr.amount} every ${incr.turns} turns`;\n\t\t\t\tif (incr.minTurns) buf += ` after turn ${incr.minTurns}`;\n\t\t\t\tbuf += `<br />`;\n\t\t\t}\n\t\t\tconst replacements = Object.keys(settings.replacements);\n\t\t\tif (replacements.length) {\n\t\t\t\tbuf += `<br />Replacements: `;\n\t\t\t\tbuf += replacements.map(k => `${k}: ${settings.replacements[k]}`).join(', ');\n\t\t\t\tbuf += `<br />`;\n\t\t\t}\n\t\t\tbuf += `</div><div class=\"infobox\"><h3>Punishment settings</h3><hr />`;\n\t\t\tif (settings.punishments.length) {\n\t\t\t\tfor (const [i, p] of settings.punishments.entries()) {\n\t\t\t\t\tbuf += `&bull; ${i + 1}: `;\n\t\t\t\t\tbuf += Object.keys(p).map(\n\t\t\t\t\t\tf => `${f}: ${visualizePunishmentKey(p, f as keyof PunishmentSettings)}`\n\t\t\t\t\t).join(', ');\n\t\t\t\t\tbuf += ` (<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am dp ${i + 1}\">delete</button>)`;\n\t\t\t\t\tbuf += `<br />`;\n\t\t\t\t}\n\t\t\t\tbuf += `<br />`;\n\t\t\t}\n\t\t\tbuf += `<details class=\"readmore\"><summary>Add a punishment</summary>`;\n\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,/am ap p={punishment},t={type},ct={certainty},c={count}\">`;\n\t\t\tbuf += `Punishment: <input name=\"punishment\" /> <small>(required)</small><br />`;\n\t\t\tbuf += `Type: <input name=\"type\" /> <small>(required)</small><br />`;\n\t\t\tbuf += `Certainty: <input name=\"certainty\" /> <small>(optional)</small><br />`;\n\t\t\tbuf += `Count: <input name=\"count\" /> <small>(optional)</small><br />`;\n\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Add punishment</button></details>`;\n\t\t\tbuf += `</form><br />`;\n\t\t\tbuf += `</div><div class=\"infobox\"><h3>Scoring:</h3><hr />`;\n\t\t\tconst keys = Utils.sortBy(\n\t\t\t\tObject.keys(Artemis.RemoteClassifier.ATTRIBUTES),\n\t\t\t\tk => [-Object.keys(settings.specials[k] || {}).length, k]\n\t\t\t);\n\t\t\tfor (const k of keys) {\n\t\t\t\tbuf += `<strong>${k}</strong>:<br />`;\n\t\t\t\tif (settings.specials[k]) {\n\t\t\t\t\tfor (const percent in settings.specials[k]) {\n\t\t\t\t\t\tbuf += `&bull; ${percent}%: ${settings.specials[k][percent]} `;\n\t\t\t\t\t\tbuf += `(<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am ds ${k},${percent}\">Delete</button>)`;\n\t\t\t\t\t\tbuf += `<br />`;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tbuf += `<br />`;\n\t\t\t\tbuf += `<details class=\"readmore\"><summary>Add a special case</summary>`;\n\t\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,/am es ${k},{percent},{score}\">`;\n\t\t\t\tbuf += `Percent needed: <input type=\"text\" name=\"percent\" /><br />`;\n\t\t\t\tbuf += `Score: <input type=\"text\" name=\"score\" /><br />`;\n\t\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Add</button>`;\n\t\t\t\tbuf += `</form></details>`;\n\t\t\t\tbuf += `<hr />`;\n\t\t\t}\n\t\t\tbuf += `</div>`;\n\t\t\treturn buf;\n\t\t},\n\t\treviews() {\n\t\t\tcheckAccess(this);\n\t\t\tthis.title = `[Abuse Monitor] Reviews`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>Artemis recommendation reviews ({{total}})</h2>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/am reviews\">Reload reviews</button>`;\n\t\t\tbuf += `<hr />`;\n\t\t\tlet total = 0;\n\t\t\tlet atLeastOne = false;\n\t\t\tfor (const userid in reviews) {\n\t\t\t\tconst curReviews = reviews[userid].filter(f => !f.resolved);\n\t\t\t\tif (curReviews.length) {\n\t\t\t\t\tbuf += `<strong>${Chat.count(curReviews, 'reviews')} from ${userid}:</strong><hr />`;\n\t\t\t\t\ttotal += curReviews.length;\n\t\t\t\t} else {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tfor (const review of curReviews) {\n\t\t\t\t\tbuf += `<div class=\"infobox\">`;\n\t\t\t\t\tbuf += `Battle: <a href=\"//${Config.routes.client}/${getBattleLinks(review.room)[0]}\">${review.room}</a><br />`;\n\t\t\t\t\tbuf += Utils.html`<details class=\"readmore\"><summary>Review details:</summary>${review.details}</details>`;\n\t\t\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,/am resolvereview ${review.staff},${review.room},{result},{response}\">`;\n\t\t\t\t\tbuf += `Respond: <br /><textarea name=\"response\" rows=\"3\" cols=\"40\"></textarea><br />`;\n\t\t\t\t\tbuf += `Mark result: <select name=\"result\">`;\n\t\t\t\t\tbuf += `<option value=\"1\">Accurate</option>`;\n\t\t\t\t\tbuf += `<option value=\"0\">Inaccurate</option>`;\n\t\t\t\t\tbuf += `</select><br />`;\n\t\t\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Resolve</button>`;\n\t\t\t\t\tbuf += `</form></div><br />`;\n\t\t\t\t\tatLeastOne = true;\n\t\t\t\t}\n\t\t\t\tbuf += `<hr />`;\n\t\t\t}\n\t\t\tif (!atLeastOne) {\n\t\t\t\tbuf += `No reviews to display.`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tbuf = buf.replace('{{total}}', `${total}`);\n\t\t\treturn buf;\n\t\t},\n\t\treview() {\n\t\t\tthis.checkCan('lock');\n\t\t\tthis.title = `[Abuse Monitor] Review`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>Artemis recommendation review</h2>`;\n\t\t\tbuf += `<hr />`;\n\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,/am submitreview {room},{details}\">`;\n\t\t\tbuf += `<label>Enter a room ID (replay URL will work):</label>`;\n\t\t\tbuf += `<br />`;\n\t\t\tbuf += `<input type=\"text\" name=\"room\" />`;\n\t\t\tbuf += `<br />`;\n\t\t\tbuf += `<label>Tell what was inaccurate and why:</label> `;\n\t\t\tbuf += `<br />`;\n\t\t\tbuf += `<textarea name=\"details\" rows=\"3\" cols=\"20\"></textarea>`;\n\t\t\tbuf += `<br />`;\n\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">Submit</button>`;\n\t\t\tbuf += `</form>`;\n\t\t\treturn buf;\n\t\t},\n\t\tasync edithistory(query, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst targetUser = toID(query[0]);\n\t\t\tif (!targetUser) {\n\t\t\t\treturn this.errorReply(`Specify a user.`);\n\t\t\t}\n\t\t\tthis.title = `[Artemis History] ${targetUser}`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>Artemis modlog handling for ${targetUser}</h2><hr />`;\n\t\t\tconst modlogEntries = await Rooms.Modlog.search('global', {\n\t\t\t\tuser: [{ search: targetUser, isExact: true }],\n\t\t\t\tnote: [],\n\t\t\t\tip: [],\n\t\t\t\taction: [],\n\t\t\t\tactionTaker: [],\n\t\t\t}, 100, true);\n\t\t\tif (!modlogEntries?.results.length) {\n\t\t\t\tbuf += `<div class=\"message-error\">No entries found.</div>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tbuf += `<div class=\"ladder pad\"><table><tr><th>Entry</th><th>Options</th></tr><tr>`;\n\t\t\tbuf += modlogEntries.results.map(result => {\n\t\t\t\tconst day = Chat.toTimestamp(new Date(result.time)).split(' ')[0];\n\t\t\t\tlet innerBuf = Utils.html`<td><small>#${result.entryID}</small> [${day}] `;\n\t\t\t\tinnerBuf += `${result.action}${result.note ? ` (${result.note.trim()})` : ``}</td>`;\n\t\t\t\tconst existingIgnore = metadata.modlogIgnores?.[targetUser];\n\t\t\t\tconst todayMatch = existingIgnore === day;\n\t\t\t\tconst entryMatch = (\n\t\t\t\t\t(Array.isArray(existingIgnore) && existingIgnore?.includes(result.entryID))\n\t\t\t\t);\n\t\t\t\tlet cmd = entryMatch ? `am ignoremodlog remove` : `am ignoremodlog add`;\n\t\t\t\tinnerBuf += `<td><button class=\"button\" name=\"send\" value=\"/${cmd} ${targetUser},${result.entryID}\">`;\n\t\t\t\tinnerBuf += `(${entryMatch ? 'Unignore' : 'Ignore'} specific)</button> `;\n\t\t\t\tcmd = todayMatch ? `am ignoremodlog remove` : `am ignoremodlog add`;\n\t\t\t\tinnerBuf += `<button class=\"button\" name=\"send\" value=\"/${cmd} ${targetUser},${day}\">`;\n\t\t\t\tinnerBuf += `(${todayMatch ? 'Unignore' : 'Ignore'} up to this date)</button></td>`;\n\t\t\t\treturn innerBuf;\n\t\t\t}).join('</tr><tr>');\n\t\t\tbuf += `</tr></table></div>`;\n\t\t\treturn buf;\n\t\t},\n\t},\n\tasync battlechat(query) {\n\t\tconst [format, num, pw] = query.map(toID);\n\t\tthis.checkCan('lock');\n\t\tif (!format || !num) {\n\t\t\treturn this.errorReply(`Invalid battle link provided.`);\n\t\t}\n\t\tthis.title = `[Battle Logs] ${format}-${num}`;\n\t\tconst full = `battle-${format}-${num}${pw ? `-${pw}` : \"\"}`;\n\t\tconst logData = await getBattleLog(full);\n\t\tif (!logData) {\n\t\t\treturn this.errorReply(`No logs found for the battle <code>${full}</code>.`);\n\t\t}\n\t\tlet log = logData.log;\n\t\tlog = log.filter(l => l.startsWith('|c|'));\n\n\t\tlet buf = '<div class=\"pad\">';\n\t\tbuf += `<h2>Logs for <a href=\"/${full}\">${logData.title}</a></h2>`;\n\t\tbuf += `Players: ${Object.values(logData.players).map(toID).filter(Boolean).join(', ')}<hr />`;\n\t\tlet atLeastOne = false;\n\t\tfor (const line of log) {\n\t\t\tconst [,, username, message] = Utils.splitFirst(line, '|', 3);\n\t\t\tbuf += Utils.html`<div class=\"chat\"><span class=\"username\"><username>${username}:</username></span> ${message}</div>`;\n\t\t\tatLeastOne = true;\n\t\t}\n\t\tif (!atLeastOne) buf += `None found.`;\n\t\treturn buf;\n\t},\n};\n\nexport const punishmentfilter: Chat.PunishmentFilter = (user, punishment) => {\n\tif (typeof user === 'string') return;\n\tif (!Punishments.punishmentTypes.has(punishment.type)) return;\n\tconst cacheEntry = punishmentCache.get(user) || {};\n\tif (!cacheEntry[punishment.type]) cacheEntry[punishment.type] = 0;\n\tcacheEntry[punishment.type]++;\n};\n"],
"mappings": "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",
"names": ["punishment"]
}