Made image settings green (#72)

diff --git a/.eslintignore b/.eslintignore
index d7b2f7f..a753b6e 100644
--- a/.eslintignore
+++ b/.eslintignore
@@ -1 +1,2 @@
-ClicksMigratingProblems/**/*
\ No newline at end of file
+ClicksMigratingProblems/**/*
+src/reflex/nsfwjs/**/*
diff --git a/.eslintrc.json b/.eslintrc.json
index 165e759..7db4826 100644
--- a/.eslintrc.json
+++ b/.eslintrc.json
@@ -23,6 +23,8 @@
                 "caughtErrorsIgnorePattern": "^_"
             }
         ],
-        "@typescript-eslint/no-explicit-any": "error"
+        "@typescript-eslint/no-explicit-any": "error",
+        "@typescript-eslint/no-misused-promises": "error",
+        "@typescript-eslint/no-floating-promises": "error"
     }
 }
diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md
index 12384fc..68e5d1f 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.md
+++ b/.github/ISSUE_TEMPLATE/bug_report.md
@@ -1,32 +1,29 @@
 ---
 name: Bug report
-about: Something doesn't work how you expect it to
+about: Something didn't work like you expected
 title: "[BUG]"
-labels: ""
+labels: "\U0001F41B Bug"
 assignees: PineaFan
 ---
 
 [Describe the bug in one line, keep it concise]
 
-**To Reproduce**
-Steps to reproduce the behaviour:
+**Command or Feature:**
+The name of the command (e.g. /settings filters) or the feature (e.g. Message edit logs)
 
-1. Go to '...'
-2. Click on '....'
-3. Scroll down to '....'
-4. See an error
+**Steps to reproduce:**
 
-**Expected behaviour**
-A clear and concise description of what you expected to happen.
+1. Run ...
+2. Press ...
 
-**Screenshots**
-If applicable, add screenshots to help explain your problem.
+**Expected behaviour:**
+Explain what you expected to happen in one line
 
-**Desktop (please complete the following information):**
+**Actual behaviour:**
+What was meant to happen?
 
--   OS: [e.g. iOS]
--   Browser [e.g. chrome, safari]
--   Version [e.g. 22]
+**Version:**
+Let us know the date this happened, so we can check if it's already been fixed
 
 **Additional context**
 Add any other context about the problem here.
diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md
index b865782..a8178cb 100644
--- a/.github/ISSUE_TEMPLATE/feature_request.md
+++ b/.github/ISSUE_TEMPLATE/feature_request.md
@@ -2,18 +2,21 @@
 name: Feature request
 about: I want something added to Nucleus
 title: "[FEATURE]"
-labels: ""
+labels: "✓ Feature"
 assignees: PineaFan
 ---
 
-**Is your feature request related to a problem? Please describe.**
-A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
+**Is this related to a bug? If so, briefly explain the bug below**
+N/A
 
-**Describe the solution you'd like**
-A clear and concise description of what you want to happen.
+**What's your idea?**
+A clear and concise description of what you'd like us to add
 
-**Describe alternatives you've considered**
-A clear and concise description of any alternative solutions or features you've considered.
+**How would you like it implemented?**
+List any options you'd like your feature to add here
+
+**How does this help?**
+If it helps with the feature, explain your use case and how this feature helps to solve the problem
 
 **Additional context**
-Add any other context or screenshots about the feature request here.
+Add any other context about the feature request
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index c1da375..325f0d8 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -22,6 +22,8 @@
               with:
                   node-version: 19.x
             - run: yarn install --immutable
+            - name: Show versions
+              run: yarn run versions
             - name: Compile
               run: yarn build
             - name: Run prettier and eslint
diff --git a/.gitignore b/.gitignore
index d73f2ea..9eaba59 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,7 +6,7 @@
 !src/config/*.d.ts
 !src/config/format.ts
 !src/config/default.ts
-!src/config/emojis.json
+!src/config/emojis.ts
 src/utils/migration/data
 src/config/main.ts
 .vscode/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..da4b2df
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,4 @@
+[submodule "src/reflex/nsfwjs"]
+	path = src/reflex/nsfwjs
+	url = https://github.com/infinitered/nsfwjs
+	shallow = true
diff --git a/.prettierignore b/.prettierignore
index 6deb598..1d61cc6 100644
--- a/.prettierignore
+++ b/.prettierignore
@@ -21,3 +21,4 @@
 ClicksMigratingProblems/oldData copy/
 
 .direnv/
+src/reflex/nsfwjs/**/*
diff --git a/flake.nix b/flake.nix
index c11ea5f..bdbd76c 100644
--- a/flake.nix
+++ b/flake.nix
@@ -8,7 +8,7 @@
       pkgs = nixpkgs.legacyPackages.${system};
     in {
       devShells.default = pkgs.mkShell {
-        packages = [ pkgs.yarn pkgs.nodejs-19_x pkgs.typescript pkgs.act ];
+        packages = [ pkgs.nodejs-19_x pkgs.nodePackages_latest.yarn ];
       };
     });
 }
diff --git a/package.json b/package.json
index 629c6dd..2ff313c 100644
--- a/package.json
+++ b/package.json
@@ -1,20 +1,24 @@
 {
     "dependencies": {
         "@hokify/agenda": "^6.2.12",
+        "@octokit/graphql": "^5.0.5",
         "@tensorflow/tfjs": "^3.18.0",
-        "@tensorflow/tfjs-node": "^4.2.0",
+        "@tensorflow/tfjs-node": "^3.18.0",
         "@total-typescript/ts-reset": "^0.3.7",
         "@tsconfig/node18-strictest-esm": "^1.0.0",
+        "@types/gm": "^1.25.0",
         "@types/node": "^18.14.6",
         "@ungap/structured-clone": "^1.0.1",
         "agenda": "^4.3.0",
         "body-parser": "^1.20.0",
         "canvas": "^2.11.0",
         "clamscan": "^2.1.2",
-        "discord.js": "^14.7.1",
+        "discord.js": "^14.8.0",
         "eslint": "^8.21.0",
         "express": "^4.18.1",
         "fuse.js": "^6.6.2",
+        "gifencoder": "^2.0.1",
+        "gm": "^1.25.0",
         "humanize-duration": "^3.27.1",
         "immutable": "^4.1.0",
         "lodash": "^4.17.21",
@@ -22,26 +26,34 @@
         "node-fetch": "^3.3.0",
         "node-tesseract-ocr": "^2.2.1",
         "nsfwjs": "^2.4.2",
+        "octokit": "^2.0.14",
         "seedrandom": "^3.0.5",
         "structured-clone": "^0.2.2",
         "systeminformation": "^5.17.3"
     },
+    "resolutions": {
+        "discord-api-types": "0.37.23"
+    },
     "name": "nucleus",
     "version": "0.0.1",
     "description": "Nucleus: The core of your server",
     "main": "dist/index.js",
     "scripts": {
-        "build": "tsc",
+        "build": "tsc && yarn copy-files",
+        "copy-files": "copyfiles -u 1 src/reflex/nsfwjs/example/nsfw_demo/public/model/**/* dist/",
         "start": "node --experimental-json-modules --enable-source-maps dist/index.js",
-        "dev": "rm -rf dist && eslint src --fix && tsc && node --experimental-json-modules --enable-source-maps dist/index.js",
-        "force-dev": "clear; rm -rf dist; tsc-suppress && node --experimental-json-modules --enable-source-maps dist/index.js",
+        "dev": "rm -rf dist && eslint src --fix && yarn build && node --experimental-json-modules --enable-source-maps dist/index.js",
+        "force-dev": "clear; rm -rf dist; tsc-suppress && yarn copy-files && node --experimental-json-modules --enable-source-maps dist/index.js",
         "lint": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To auto-fix everything possible, please run `yarn lint-fix`'; true",
+        "lint-no-stylecheck": "echo 'Linting...'; eslint src; echo 'A full lint and style check is required for PRs to be accepted. Please run `yarn lint` before committing'; true",
         "lint-fix": "echo 'Fixing eslint issues...'; eslint src --fix; echo 'Reformatting...'; prettier --write --loglevel warn --cache .; true",
         "lint-list": "echo 'Style checking...'; prettier --check .; echo 'Linting...'; eslint src; echo 'To view errors in more detail, please run `yarn lint`'; true",
         "lint-ci": "echo 'Style checking...' && prettier --check . && echo 'Linting...' && eslint src",
         "setup": "node Installer.js",
-        "win-force-build": "clear | rm -r dist | tsc-suppress",
-        "audit-fix": "yarn-audit-fix"
+        "win-force-build": "clear | rm -r dist | tsc-suppress | yarn copy-files",
+        "audit-fix": "yarn-audit-fix",
+        "versions": "yarn versions && yarn list && node --version",
+        "win-lint-fix": "echo 'Fixing eslint issues...' | eslint src --fix | echo 'Reformatting...' | prettier --write --loglevel warn --cache . | true"
     },
     "repository": {
         "type": "git",
@@ -61,9 +73,11 @@
     "type": "module",
     "devDependencies": {
         "@types/clamscan": "^2.0.4",
+        "@types/gifencoder": "^2.0.1",
         "@types/lodash": "^4.14.191",
         "@typescript-eslint/eslint-plugin": "^5.32.0",
         "@typescript-eslint/parser": "^5.32.0",
+        "copyfiles": "^2.4.1",
         "eslint-config-prettier": "^8.5.0",
         "prettier": "^2.7.1",
         "prettier-eslint": "^15.0.1",
diff --git a/src/Unfinished/categorizationTest.ts b/src/Unfinished/categorizationTest.ts
index 763669c..dfe9098 100644
--- a/src/Unfinished/categorizationTest.ts
+++ b/src/Unfinished/categorizationTest.ts
@@ -51,7 +51,6 @@
         let channel: string | GuildChannel;
         if (typeof c === "string") channel = interaction.guild!.channels.cache.get(c as string)!.id;
         else channel = (c[0] as unknown as GuildChannel).id;
-        console.log(channel);
         if (!predicted[channel]) predicted[channel] = [];
         m = await interaction.editReply({
             embeds: [
@@ -139,7 +138,6 @@
         }
         categorized[channel] = selected;
     }
-    console.log(categorized);
 };
 
 const check = () => {
diff --git a/src/actions/createModActionTicket.ts b/src/actions/createModActionTicket.ts
index ea85255..6b34739 100644
--- a/src/actions/createModActionTicket.ts
+++ b/src/actions/createModActionTicket.ts
@@ -115,8 +115,8 @@
             type: Discord.ChannelType.PrivateThread,
             reason: "Creating ticket"
         })) as Discord.PrivateThreadChannel;
-        c.members.add(user.id);
-        c.members.add(createdBy.id);
+        await c.members.add(user.id);
+        await c.members.add(createdBy.id);
         try {
             await c.send({
                 content:
@@ -174,7 +174,7 @@
             guild: guild.id
         }
     };
-    log(data);
+    await log(data);
     return c.id;
 }
 
diff --git a/src/actions/roleMenu.ts b/src/actions/roleMenu.ts
index 9796b28..6997393 100644
--- a/src/actions/roleMenu.ts
+++ b/src/actions/roleMenu.ts
@@ -175,7 +175,7 @@
                 console.log(e);
                 return;
             }
-            component.deferUpdate();
+            await component.deferUpdate();
         }
     }
 
@@ -246,7 +246,7 @@
             console.log(e);
             return;
         }
-        component.deferUpdate();
+        await component.deferUpdate();
         if (component.customId === "back") {
             page = Math.max(0, page - 1);
         } else if (component.customId === "next") {
diff --git a/src/actions/tickets/create.ts b/src/actions/tickets/create.ts
index 26236d8..8dafe52 100644
--- a/src/actions/tickets/create.ts
+++ b/src/actions/tickets/create.ts
@@ -155,7 +155,7 @@
                 new ActionRowBuilder<ButtonBuilder>().addComponents(formattedTicketTypes.slice(i, i + 5))
             );
         }
-        component.update({
+        await component.update({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Create Ticket")
@@ -280,7 +280,7 @@
             type: Discord.ChannelType.PrivateThread,
             reason: "Creating ticket"
         })) as Discord.PrivateThreadChannel;
-        c.members.add(interaction.member!.user.id);
+        await c.members.add(interaction.member!.user.id);
         try {
             await c.send({
                 content:
@@ -357,7 +357,7 @@
             guild: interaction.guild.id
         }
     };
-    log(data);
+    await log(data);
     await interaction.editReply({
         embeds: [
             new EmojiEmbed()
diff --git a/src/actions/tickets/delete.ts b/src/actions/tickets/delete.ts
index 1c1e464..769bc32 100644
--- a/src/actions/tickets/delete.ts
+++ b/src/actions/tickets/delete.ts
@@ -78,7 +78,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
 
         await channel.delete();
     } else if (status === "Active") {
@@ -86,12 +86,12 @@
         // Archive the ticket
         await interaction.channel.fetch();
         if (channel.isThread()) {
-            channel.setName(`${channel.name.replace("Active", "Archived")}`);
-            channel.members.remove(channel.name.split(" - ")[1]!);
+            await channel.setName(`${channel.name.replace("Active", "Archived")}`);
+            await channel.members.remove(channel.name.split(" - ")[1]!);
         } else {
-            channel.setTopic(`${(channel.topic ?? "").replace("Active", "Archived")}`);
+            await channel.setTopic(`${(channel.topic ?? "").replace("Active", "Archived")}`);
             if (!channel.topic!.includes("Archived")) {
-                channel.setTopic("0 Archived");
+                await channel.setTopic("0 Archived");
             }
             await channel.permissionOverwrites.delete(channel.topic!.split(" ")[0]!);
         }
@@ -153,7 +153,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
     }
     return;
 }
@@ -170,28 +170,28 @@
     if (tickets.type === Discord.ChannelType.GuildCategory) {
         // For channels, the topic is the user ID, then the word Active
         const category = tickets as Discord.CategoryChannel;
-        category.children.cache.forEach((element) => {
+        for (const [_id, element] of category.children.cache) {
             if (!(element.type === Discord.ChannelType.GuildText)) return;
             if (!((element as Discord.TextChannel).topic ?? "").includes(member)) return;
             try {
-                element.delete();
+                await element.delete();
                 deleted++;
             } catch (e) {
                 console.error(e);
             }
-        });
+        }
     } else {
         // For threads, the name is the users name, id, then the word Active
         const channel = tickets as Discord.TextChannel;
-        channel.threads.cache.forEach((element: Discord.ThreadChannel) => {
+        for (const [_id, element] of channel.threads.cache) {
             if (!element.name.includes(member)) return;
             try {
-                element.delete();
+                await element.delete();
                 deleted++;
             } catch (e) {
                 console.error(e);
             }
-        });
+        }
     }
     if (!deleted) return;
     const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
@@ -214,7 +214,7 @@
             guild: guild
         }
     };
-    log(data);
+    await log(data);
 }
 
 export { purgeByUser };
diff --git a/src/api/index.ts b/src/api/index.ts
index 4b849f1..41f281d 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -35,7 +35,7 @@
             await member.roles.add(client.verify[code]!.rID);
 
             const interaction = client.verify[code]!.interaction;
-            interaction.editReply({
+            await interaction.editReply({
                 embeds: [
                     new EmojiEmbed()
                         .setTitle("Verify")
@@ -70,7 +70,7 @@
                         guild: guild.id
                     }
                 };
-                log(data);
+                await log(data);
             } catch {
                 res.sendStatus(500);
             }
@@ -80,12 +80,12 @@
         }
     });
 
-    app.get("/verify/:code", jsonParser, function (req: express.Request, res: express.Response) {
+    app.get("/verify/:code", jsonParser, async function (req: express.Request, res: express.Response) {
         const code = req.params.code;
         if (client.verify[code]) {
             try {
                 const interaction = client.verify[code]!.interaction;
-                interaction.editReply({
+                await interaction.editReply({
                     embeds: [
                         new EmojiEmbed()
                             .setTitle("Verify")
@@ -124,12 +124,12 @@
         }
     });
 
-    app.get("/rolemenu/:code", jsonParser, function (req: express.Request, res: express.Response) {
+    app.get("/rolemenu/:code", jsonParser, async function (req: express.Request, res: express.Response) {
         const code = req.params.code;
         if (client.roleMenu[code] !== undefined) {
             try {
                 const interaction = client.roleMenu[code]!.interaction;
-                interaction.editReply({
+                await interaction.editReply({
                     embeds: [
                         new EmojiEmbed()
                             .setTitle("Roles")
diff --git a/src/commands/help.ts b/src/commands/help.ts
index 482bca2..f95eb6e 100644
--- a/src/commands/help.ts
+++ b/src/commands/help.ts
@@ -22,7 +22,10 @@
 import { getCommandByName, getCommandMentionByName } from "../utils/getCommandDataByName.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 
-const command = new SlashCommandBuilder().setName("help").setDescription("Shows help for commands");
+const command = new SlashCommandBuilder()
+    .setName("help")
+    .setDescription("Shows help for commands")
+    .setDMPermission(true);
 
 const styles: Record<string, { emoji: string }> = {
     help: { emoji: "NUCLEUS.LOGO" },
@@ -127,23 +130,23 @@
                 );
             }
             for (const option of options) {
-                optionString += `> ${option.name} (${ApplicationCommandOptionType[option.type]})- ${
-                    option.description
-                }\n`;
+                optionString += ` - \`${option.name}\` (${ApplicationCommandOptionType[option.type]
+                    .replace("Integer", "Number")
+                    .replace("String", "Text")}) - ${option.description}\n`;
             }
             const APICommand =
                 client.commands[
                     "commands/" + currentPath.filter((value) => value !== "" && value !== "none").join("/")
                 ]![0];
             let allowedToRun = true;
-            if (APICommand?.check) {
+            if (interaction.guild && APICommand?.check) {
                 allowedToRun = await APICommand.check(interaction as Interaction, true);
             }
             embed.setDescription(
-                `${getEmojiByName(styles[currentPath[0]]!.emoji)} **${capitalize(currentData.name)}**\n> ${
+                `${getEmojiByName(styles[currentPath[0]]!.emoji)} **${capitalize(currentData.name)}** | ${
                     currentData.mention
                 }\n\n` +
-                    `> ${currentData.description}\n\n` +
+                    `${currentData.description}\n\n` +
                     (APICommand
                         ? `${getEmojiByName(allowedToRun ? "CONTROL.TICK" : "CONTROL.CROSS")} You ${
                               allowedToRun ? "" : "don't "
diff --git a/src/commands/mod/about.ts b/src/commands/mod/about.ts
index 8736054..6f8b74c 100644
--- a/src/commands/mod/about.ts
+++ b/src/commands/mod/about.ts
@@ -266,7 +266,7 @@
                 }
             });
         } catch (e) {
-            interaction.editReply({
+            await interaction.editReply({
                 embeds: [
                     new EmojiEmbed()
                         .setEmoji("MEMBER.JOIN")
diff --git a/src/commands/mod/ban.ts b/src/commands/mod/ban.ts
index 91e074d..78f936c 100644
--- a/src/commands/mod/ban.ts
+++ b/src/commands/mod/ban.ts
@@ -126,7 +126,7 @@
         dmSent = false;
     }
     try {
-        member.ban({
+        await member.ban({
             deleteMessageSeconds: deleteDays * 24 * 60 * 60,
             reason: reason ?? "*No reason provided*"
         });
@@ -159,7 +159,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
     } catch {
         await interaction.editReply({
             embeds: [
@@ -191,7 +191,10 @@
     if (!interaction.guild) return;
     const member = interaction.member as GuildMember;
     // Check if the user has ban_members permission
-    if (!member.permissions.has("BanMembers")) return "You do not have the *Ban Members* permission";
+    if (!member.permissions.has("BanMembers")) {
+        // if(!partial) client.logger.warn("Missing permissions", "Ban", "User does not have Ban Members permission");
+        return "You do not have the *Ban Members* permission";
+    }
     if (partial) return true;
     const me = interaction.guild.members.me!;
     let apply: GuildMember;
diff --git a/src/commands/mod/kick.ts b/src/commands/mod/kick.ts
index 4ef78c8..f9242fe 100644
--- a/src/commands/mod/kick.ts
+++ b/src/commands/mod/kick.ts
@@ -114,7 +114,7 @@
         dmSent = false;
     }
     try {
-        member.kick(reason || "No reason provided");
+        await member.kick(reason || "No reason provided");
         await client.database.history.create("kick", interaction.guild.id, member.user, interaction.user, reason);
         const { log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
         const timeInServer = member.joinedTimestamp
@@ -157,7 +157,7 @@
             data.list.joined = entry(member.joinedTimestamp.toString(), renderDelta(member.joinedTimestamp));
         }
         await client.database.history.create("kick", interaction.guild.id, member.user, interaction.user, reason);
-        log(data);
+        await log(data);
     } catch {
         await interaction.editReply({
             embeds: [
diff --git a/src/commands/mod/mute.ts b/src/commands/mod/mute.ts
index 2266a1a..0cfe660 100644
--- a/src/commands/mod/mute.ts
+++ b/src/commands/mod/mute.ts
@@ -132,7 +132,7 @@
         } catch {
             return;
         }
-        component.deferUpdate();
+        await component.deferUpdate();
         if (component.customId === "cancel")
             return interaction.editReply({
                 embeds: [
@@ -389,7 +389,7 @@
             guild: interaction.guild.id
         }
     };
-    log(data);
+    await log(data);
     const failed = !status.dm && notify;
     await interaction.editReply({
         embeds: [
diff --git a/src/commands/mod/nick.ts b/src/commands/mod/nick.ts
index cfdcf47..178246a 100644
--- a/src/commands/mod/nick.ts
+++ b/src/commands/mod/nick.ts
@@ -81,7 +81,7 @@
                 "Change nickname",
                 "ICONS.EDIT",
                 "modal",
-                newNickname ?? "",
+                { default: newNickname ?? "" },
                 new ModalBuilder().setTitle("Editing nickname").addComponents(
                     new ActionRowBuilder<TextInputBuilder>().addComponents(
                         new TextInputBuilder()
@@ -103,7 +103,7 @@
             notify = confirmation.components["notify"]!.active;
             createAppealTicket = confirmation.components["appeal"]!.active;
         }
-        if (confirmation.modals) newNickname = confirmation.modals![0]!.value;
+        if (confirmation.modals) newNickname = confirmation.modals![0]!.values["default"];
     } while (!timedOut && !success);
     if (timedOut || !success) return;
     let dmSent = false;
@@ -153,7 +153,7 @@
     let before: string | null;
     try {
         before = member.nickname;
-        member.setNickname(newNickname ?? null, "Nucleus Nickname command");
+        await member.setNickname(newNickname ?? null, "Nucleus Nickname command");
         await client.database.history.create(
             "nickname",
             interaction.guild!.id,
@@ -202,7 +202,7 @@
             guild: interaction.guild!.id
         }
     };
-    log(data);
+    await log(data);
     const failed = !dmSent && notify;
     await interaction.editReply({
         embeds: [
@@ -222,7 +222,7 @@
     });
 };
 
-const check = async (interaction: CommandInteraction | ButtonInteraction, partial: boolean, target?: GuildMember) => {
+const check = (interaction: CommandInteraction | ButtonInteraction, partial: boolean, target?: GuildMember) => {
     const member = interaction.member as GuildMember;
     // Check if the user has manage_nicknames permission
     if (!member.permissions.has("ManageNicknames")) return "You do not have the *Manage Nicknames* permission";
diff --git a/src/commands/mod/purge.ts b/src/commands/mod/purge.ts
index dadab04..1170c33 100644
--- a/src/commands/mod/purge.ts
+++ b/src/commands/mod/purge.ts
@@ -100,7 +100,7 @@
             })) as Discord.Message;
             let component;
             try {
-                component = m.awaitMessageComponent({
+                component = await m.awaitMessageComponent({
                     filter: (i) => i.user.id === interaction.user.id && i.channel!.id === interaction.channel!.id,
                     time: 300000
                 });
@@ -108,12 +108,12 @@
                 timedOut = true;
                 continue;
             }
-            (await component).deferUpdate();
-            if ((await component).customId === "done") {
+            await component.deferUpdate();
+            if (component.customId === "done") {
                 amountSelected = true;
                 continue;
             }
-            const amount = parseInt((await component).customId);
+            const amount = parseInt(component.customId);
 
             let messages: Discord.Message[] = [];
             await (interaction.channel as TextChannel).messages.fetch({ limit: amount }).then(async (ms) => {
@@ -167,7 +167,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
         const newOut = await client.database.transcripts.createTranscript(
             "purge",
             deleted,
@@ -209,7 +209,7 @@
             return;
         }
         if (component.customId === "download") {
-            interaction.editReply({
+            await interaction.editReply({
                 embeds: [
                     new EmojiEmbed()
                         .setEmoji("CHANNEL.PURGE.GREEN")
@@ -221,7 +221,7 @@
                 files: [attachmentObject]
             });
         } else {
-            interaction.editReply({
+            await interaction.editReply({
                 embeds: [
                     new EmojiEmbed()
                         .setEmoji("CHANNEL.PURGE.GREEN")
@@ -261,12 +261,12 @@
                 messages = await (channel as TextChannel).bulkDelete(toDelete, true);
             } else {
                 const toDelete = (
-                    await (
-                        await (interaction.channel as TextChannel).messages.fetch({
-                            limit: 100
-                        })
-                    ).filter((m) => m.author.id === user.id)
-                ).first(interaction.options.get("amount")?.value as number);
+                    await (interaction.channel as TextChannel).messages.fetch({
+                        limit: 100
+                    })
+                )
+                    .filter((m) => m.author.id === user.id)
+                    .first(interaction.options.get("amount")?.value as number);
                 messages = await (channel as TextChannel).bulkDelete(toDelete, true);
             }
         } catch (e) {
@@ -326,7 +326,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
         const messageArray: Message[] = messages
             .filter(
                 (message) =>
diff --git a/src/commands/mod/slowmode.ts b/src/commands/mod/slowmode.ts
index ba88c00..8fe9f16 100644
--- a/src/commands/mod/slowmode.ts
+++ b/src/commands/mod/slowmode.ts
@@ -51,7 +51,7 @@
         .send();
     if (confirmation.cancelled || !confirmation.success) return;
     try {
-        (interaction.channel as TextChannel).setRateLimitPerUser(time);
+        await (interaction.channel as TextChannel).setRateLimitPerUser(time);
     } catch (e) {
         await interaction.editReply({
             embeds: [
diff --git a/src/commands/mod/softban.ts b/src/commands/mod/softban.ts
index cd03d1a..984bb6b 100644
--- a/src/commands/mod/softban.ts
+++ b/src/commands/mod/softban.ts
@@ -128,7 +128,7 @@
     try {
         const member = interaction.options.getMember("user") as GuildMember;
         const days: number = (interaction.options.get("delete")?.value as number | null) ?? 0;
-        member.ban({
+        await member.ban({
             deleteMessageSeconds: days * 24 * 60 * 60,
             reason: reason ?? "*No reason provided*"
         });
@@ -162,7 +162,7 @@
                 guild: interaction.guild.id
             }
         };
-        log(data);
+        await log(data);
     } catch {
         await interaction.editReply({
             embeds: [
diff --git a/src/commands/mod/unban.ts b/src/commands/mod/unban.ts
index 7397414..1c1a877 100644
--- a/src/commands/mod/unban.ts
+++ b/src/commands/mod/unban.ts
@@ -76,7 +76,7 @@
                     guild: interaction.guild.id
                 }
             };
-            log(data);
+            await log(data);
         } catch {
             await interaction.editReply({
                 embeds: [
diff --git a/src/commands/mod/unmute.ts b/src/commands/mod/unmute.ts
index f248a3b..516bd39 100644
--- a/src/commands/mod/unmute.ts
+++ b/src/commands/mod/unmute.ts
@@ -76,7 +76,7 @@
     }
     const member = interaction.options.getMember("user") as GuildMember;
     try {
-        member.timeout(0, reason ?? "*No reason provided*");
+        await member.timeout(0, reason ?? "*No reason provided*");
     } catch {
         await interaction.editReply({
             embeds: [
@@ -122,7 +122,7 @@
             guild: interaction.guild.id
         }
     };
-    log(data);
+    await log(data);
     const failed = !dmSent && notify;
     await interaction.editReply({
         embeds: [
diff --git a/src/commands/mod/warn.ts b/src/commands/mod/warn.ts
index 232219b..0424d48 100644
--- a/src/commands/mod/warn.ts
+++ b/src/commands/mod/warn.ts
@@ -153,7 +153,7 @@
         }
     };
     await client.database.history.create("warn", interaction.guild.id, member.user, interaction.user, reason);
-    log(data);
+    await log(data);
     const failed = !dmSent && notify;
     if (!failed) {
         await interaction.editReply({
diff --git a/src/commands/nucleus/guide.ts b/src/commands/nucleus/guide.ts
index d05e265..c95e78c 100644
--- a/src/commands/nucleus/guide.ts
+++ b/src/commands/nucleus/guide.ts
@@ -6,7 +6,7 @@
     builder.setName("guide").setDescription("Shows the welcome guide for the bot");
 
 const callback = async (interaction: CommandInteraction) => {
-    guide(interaction.guild!, interaction);
+    await guide(interaction.guild!, interaction);
 };
 
 export { command };
diff --git a/src/commands/nucleus/invite.ts b/src/commands/nucleus/invite.ts
index 9f78cc5..0307c68 100644
--- a/src/commands/nucleus/invite.ts
+++ b/src/commands/nucleus/invite.ts
@@ -7,7 +7,7 @@
     builder.setName("invite").setDescription("Invites Nucleus to your server");
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
-    interaction.reply({
+    await interaction.reply({
         embeds: [
             new EmojiEmbed()
                 .setTitle("Invite")
diff --git a/src/commands/nucleus/ping.ts b/src/commands/nucleus/ping.ts
index 62988bb..8a9ca87 100644
--- a/src/commands/nucleus/ping.ts
+++ b/src/commands/nucleus/ping.ts
@@ -13,7 +13,7 @@
     const initial = Date.now();
     await interaction.reply({ embeds: LoadingEmbed, ephemeral: true });
     const ping = Date.now() - initial;
-    interaction.editReply({
+    await interaction.editReply({
         embeds: [
             new EmojiEmbed()
                 .setTitle("Ping")
diff --git a/src/commands/nucleus/premium.ts b/src/commands/nucleus/premium.ts
index 4effb23..fed2964 100644
--- a/src/commands/nucleus/premium.ts
+++ b/src/commands/nucleus/premium.ts
@@ -93,8 +93,7 @@
         if (i.isButton()) {
             closed = true;
         } else {
-            const response = await client.database.premium.removePremium(interaction.user.id, i.values[0]!);
-            console.log(response);
+            await client.database.premium.removePremium(interaction.user.id, i.values[0]!);
         }
     } while (!closed);
     await interaction.deleteReply();
@@ -106,7 +105,7 @@
     const member = await (await interaction.client.guilds.fetch("684492926528651336")).members
         .fetch(interaction.user.id)
         .catch(() => {
-            interaction.editReply({
+            void interaction.editReply({
                 embeds: [
                     new EmojiEmbed()
                         .setTitle("Premium")
@@ -197,7 +196,7 @@
     if ((dbMember?.appliesTo.length ?? 0) > 0)
         userPremiumServers = "\nIf you want to remove premium from a server, run this command in your DMs with me.";
 
-    interaction.editReply({
+    await interaction.editReply({
         embeds: [
             new EmojiEmbed()
                 .setTitle("Premium")
@@ -216,10 +215,10 @@
     } catch (e) {
         return;
     }
-    i.deferUpdate();
+    await i.deferUpdate();
     const guild = i.guild!;
     if (count - appliesTo.length <= 0) {
-        interaction.editReply({
+        await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Premium")
@@ -235,7 +234,7 @@
         });
     } else {
         await client.database.premium.addPremium(interaction.user.id, guild.id);
-        interaction.editReply({
+        await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Premium")
diff --git a/src/commands/nucleus/stats.ts b/src/commands/nucleus/stats.ts
index 294ee27..d6577e7 100644
--- a/src/commands/nucleus/stats.ts
+++ b/src/commands/nucleus/stats.ts
@@ -8,6 +8,7 @@
     CommandInteraction,
     ComponentType,
     Guild,
+    GuildTextBasedChannel,
     ModalBuilder,
     ModalSubmitInteraction,
     TextInputBuilder,
@@ -21,6 +22,52 @@
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder.setName("stats").setDescription("Gets the bot's stats");
 
+const confirm = async (interaction: ButtonInteraction) => {
+    const requiredTexts = [
+        "just do it",
+        "yes, do as i say!",
+        "clicksminuteper/nucleus",
+        "i've said it once i'll say it again",
+        "no, i've changed my mind",
+        "this incident will be reported",
+        "coded told me to",
+        "mini told me to",
+        "pinea told me to",
+        "what's a java script",
+        "it's a feature not a bug",
+        "that never happened during testing"
+    ];
+    const chosen = requiredTexts[Math.floor(Math.random() * (requiredTexts.length - 1))]!;
+
+    const modal = new ModalBuilder()
+        .addComponents(
+            new ActionRowBuilder<TextInputBuilder>().addComponents(
+                new TextInputBuilder()
+                    .setStyle(TextInputStyle.Short)
+                    .setLabel(`Type "${chosen}" below`)
+                    .setCustomId("confirm")
+                    .setPlaceholder("Guild ID")
+                    .setMinLength(chosen.length)
+                    .setMaxLength(chosen.length)
+            )
+        )
+        .setTitle("Admin Panel")
+        .setCustomId("adminPanel");
+    await interaction.showModal(modal);
+    let out: ModalSubmitInteraction;
+    try {
+        out = await interaction.awaitModalSubmit({
+            filter: (i) => i.customId === "adminPanel" && i.user.id === interaction.user.id,
+            time: 300000
+        });
+    } catch {
+        return;
+    }
+    await out.deferUpdate();
+    const typed = out.fields.getTextInputValue("confirm");
+    return typed.toLowerCase() === chosen.toLowerCase();
+};
+
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     const description = `**Servers:** ${client.guilds.cache.size}\n` + `**Ping:** \`${client.ws.ping * 2}ms\``;
     const m = await interaction.reply({
@@ -35,7 +82,7 @@
         fetchReply: true
     });
     if (config.owners.includes(interaction.user.id)) {
-        interaction.editReply({
+        await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
                     .setTitle("Admin")
@@ -47,9 +94,9 @@
                 new ActionRowBuilder<ButtonBuilder>().addComponents(
                     new ButtonBuilder().setCustomId("admin").setLabel("Admin Panel").setStyle(ButtonStyle.Primary),
                     new ButtonBuilder()
-                        .setCustomId("mod:nickname:599498449733550102")
-                        .setLabel("Testing")
-                        .setStyle(ButtonStyle.Primary)
+                        .setCustomId("announce")
+                        .setLabel("Announce to all Guilds")
+                        .setStyle(ButtonStyle.Danger)
                 )
             ]
         });
@@ -77,134 +124,281 @@
             return;
         // console.log(interaction)
         if (!("awaitMessageComponent" in channel)) return;
+        let GuildID = interaction.guildId;
         try {
-            i1 = await channel!.awaitMessageComponent<ComponentType.Button>({
-                filter: (i) => i.customId === "admin" && i.user.id === interaction.user.id,
+            i1 = await m.awaitMessageComponent<ComponentType.Button>({
+                filter: (i) => i.user.id === interaction.user.id,
                 time: 300000
             });
         } catch (e) {
             console.log(e);
             return;
         }
-        await i1.showModal(modal);
-        let out: ModalSubmitInteraction;
-        try {
-            out = await i1.awaitModalSubmit({
-                filter: (i) => i.customId === "adminPanel" && i.user.id === interaction.user.id,
-                time: 300000
-            });
-        } catch {
-            return;
-        }
-        out.deferUpdate();
-        const GuildID = out.fields.getTextInputValue("guildID");
-        if (!client.guilds.cache.has(GuildID)) {
-            await interaction.editReply({
-                embeds: [new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")],
-                components: []
-            });
-        }
+        switch (i1.customId) {
+            case "admin": {
+                if (!GuildID) {
+                    await i1.showModal(modal);
+                    let out: ModalSubmitInteraction;
+                    try {
+                        out = await i1.awaitModalSubmit({
+                            filter: (i) => i.customId === "adminPanel" && i.user.id === interaction.user.id,
+                            time: 300000
+                        });
+                    } catch {
+                        return;
+                    }
+                    await out.deferUpdate();
+                    GuildID = out.fields.getTextInputValue("guildID");
+                } else if (!client.guilds.cache.has(GuildID)) {
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")
+                        ],
+                        components: []
+                    });
+                }
 
-        await interaction.editReply({
-            embeds: [],
-            components: [
-                new ActionRowBuilder<ButtonBuilder>().addComponents(
-                    new ButtonBuilder().setCustomId("stats").setLabel("Stats").setStyle(ButtonStyle.Primary),
-                    new ButtonBuilder().setCustomId("leave").setLabel("Leave").setStyle(ButtonStyle.Danger),
-                    new ButtonBuilder().setCustomId("data").setLabel("Guild data").setStyle(ButtonStyle.Secondary),
-                    new ButtonBuilder().setCustomId("purge").setLabel("Delete data").setStyle(ButtonStyle.Danger),
-                    new ButtonBuilder().setCustomId("cache").setLabel("Reset cache").setStyle(ButtonStyle.Success)
-                )
-            ]
-        });
-        let i;
-        try {
-            i = await m.awaitMessageComponent<ComponentType.Button>({
-                filter: (i) => i.user.id === interaction.user.id,
-                time: 300000
-            });
-        } catch {
-            return;
-        }
-        i.deferUpdate();
-        const guild = (await client.guilds.fetch(GuildID)) as Guild | null;
-        if (!guild) {
-            await interaction.editReply({
-                embeds: [new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")],
-                components: []
-            });
-            return;
-        }
-        if (i.customId === "stats") {
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Stats")
-                        .setDescription(
-                            `**Name:** ${guild.name}\n` +
-                                `**ID:** \`${guild.id}\`\n` +
-                                `**Owner:** ${client.users.cache.get(guild.ownerId)!.tag}\n` +
-                                `**Member Count:** ${guild.memberCount}\n` +
-                                `**Created:** <t:${guild.createdTimestamp}:F>\n` +
-                                `**Added Nucleus:** <t:${guild.members.me!.joinedTimestamp}:R>\n` +
-                                `**Nucleus' Perms:** https://discordapi.com/permissions.html#${guild.members.me!.permissions.valueOf()}\n`
+                await interaction.editReply({
+                    embeds: [],
+                    components: [
+                        new ActionRowBuilder<ButtonBuilder>().addComponents(
+                            new ButtonBuilder().setCustomId("stats").setLabel("Stats").setStyle(ButtonStyle.Primary),
+                            new ButtonBuilder()
+                                .setCustomId("data")
+                                .setLabel("Guild data")
+                                .setStyle(ButtonStyle.Secondary),
+                            new ButtonBuilder()
+                                .setCustomId("cache")
+                                .setLabel("Reset cache")
+                                .setStyle(ButtonStyle.Success),
+                            new ButtonBuilder().setCustomId("leave").setLabel("Leave").setStyle(ButtonStyle.Danger),
+                            new ButtonBuilder()
+                                .setCustomId("purge")
+                                .setLabel("Delete data")
+                                .setStyle(ButtonStyle.Danger)
                         )
-                        .setStatus("Success")
-                        .setEmoji("SETTINGS.STATS.GREEN")
-                ]
-            });
-        } else if (i.customId === "leave") {
-            await guild.leave();
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Left")
-                        .setDescription(`Left ${guild.name}`)
-                        .setStatus("Success")
-                        .setEmoji("SETTINGS.STATS.GREEN")
-                ],
-                components: []
-            });
-        } else if (i.customId === "data") {
-            // Get all the data and convert to a string
-            const data = await client.database.guilds.read(guild.id);
-            const stringified = JSON.stringify(data, null, 2);
-            const buffer = Buffer.from(stringified);
-            const attachment = new AttachmentBuilder(buffer).setName("data.json");
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed().setTitle("Data").setDescription(`Data for ${guild.name}`).setStatus("Success")
-                ],
-                components: [],
-                files: [attachment]
-            });
-        } else if (i.customId === "purge") {
-            await client.database.guilds.delete(GuildID);
-            await client.database.history.delete(GuildID);
-            await client.database.notes.delete(GuildID);
-            await client.database.transcripts.deleteAll(GuildID);
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Purge")
-                        .setDescription(`Deleted data for ${guild.name}`)
-                        .setStatus("Success")
-                        .setEmoji("SETTINGS.STATS.GREEN")
-                ],
-                components: []
-            });
-        } else if (i.customId === "cache") {
-            await client.memory.forceUpdate(guild.id);
-            await interaction.editReply({
-                embeds: [
-                    new EmojiEmbed()
-                        .setTitle("Cache")
-                        .setDescription(`Reset cache for ${guild.name}`)
-                        .setStatus("Success")
-                        .setEmoji("SETTINGS.STATS.GREEN")
-                ],
-                components: []
-            });
+                    ]
+                });
+                let i;
+                try {
+                    i = await m.awaitMessageComponent<ComponentType.Button>({
+                        filter: (i) => i.user.id === interaction.user.id && i.message.id === m.id,
+                        time: 300000
+                    });
+                } catch {
+                    return;
+                }
+                const guild = (await client.guilds.fetch(GuildID)) as Guild | null;
+                if (!guild) {
+                    await i.deferUpdate();
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed().setTitle("Admin").setDescription("Not in server").setStatus("Danger")
+                        ],
+                        components: []
+                    });
+                    return;
+                }
+                if (i.customId === "stats") {
+                    await i.deferUpdate();
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Stats")
+                                .setDescription(
+                                    `**Name:** ${guild.name}\n` +
+                                        `**ID:** \`${guild.id}\`\n` +
+                                        `**Owner:** ${client.users.cache.get(guild.ownerId)!.tag}\n` +
+                                        `**Member Count:** ${guild.memberCount}\n` +
+                                        `**Created:** <t:${guild.createdTimestamp}:F>\n` +
+                                        `**Added Nucleus:** <t:${guild.members.me!.joinedTimestamp}:R>\n` +
+                                        `**Nucleus' Perms:** https://discordapi.com/permissions.html#${guild.members.me!.permissions.valueOf()}\n`
+                                )
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ]
+                    });
+                } else if (i.customId === "leave") {
+                    if (!(await confirm(i))) {
+                        await interaction.editReply({
+                            embeds: [new EmojiEmbed().setTitle("No changes were made").setStatus("Danger")],
+                            components: []
+                        });
+                        return;
+                    }
+                    await guild.leave();
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Left")
+                                .setDescription(`Left ${guild.name}`)
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ],
+                        components: []
+                    });
+                } else if (i.customId === "data") {
+                    await i.deferUpdate();
+                    // Get all the data and convert to a string
+                    const data = await client.database.guilds.read(guild.id);
+                    const stringified = JSON.stringify(data, null, 2);
+                    const buffer = Buffer.from(stringified);
+                    const attachment = new AttachmentBuilder(buffer).setName("data.json");
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Data")
+                                .setDescription(`Data for ${guild.name}`)
+                                .setStatus("Success")
+                        ],
+                        components: [],
+                        files: [attachment]
+                    });
+                } else if (i.customId === "purge") {
+                    if (!(await confirm(i))) {
+                        await interaction.editReply({
+                            embeds: [new EmojiEmbed().setTitle("No changes were made").setStatus("Danger")],
+                            components: []
+                        });
+                        return;
+                    }
+                    await client.database.guilds.delete(GuildID);
+                    await client.database.history.delete(GuildID);
+                    await client.database.notes.delete(GuildID);
+                    await client.database.transcripts.deleteAll(GuildID);
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Purge")
+                                .setDescription(`Deleted data for ${guild.name}`)
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ],
+                        components: []
+                    });
+                } else if (i.customId === "cache") {
+                    await i.deferUpdate();
+                    await client.memory.forceUpdate(guild.id);
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Cache")
+                                .setDescription(`Reset cache for ${guild.name}`)
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ],
+                        components: []
+                    });
+                }
+                break;
+            }
+            case "announce": {
+                const channelsToNotify = await client.database.guilds.staffChannels();
+                const modal2 = new ModalBuilder()
+                    .addComponents(
+                        new ActionRowBuilder<TextInputBuilder>().addComponents(
+                            new TextInputBuilder()
+                                .setStyle(TextInputStyle.Paragraph)
+                                .setLabel("Announcement")
+                                .setCustomId("announcement")
+                                .setPlaceholder("Announcement...")
+                        )
+                    )
+                    .setTitle("Announcement")
+                    .setCustomId("announce");
+                await i1.showModal(modal2);
+                let out: ModalSubmitInteraction;
+                try {
+                    out = await i1.awaitModalSubmit({
+                        filter: (i) => i.customId === "announce" && i.user.id === interaction.user.id,
+                        time: 300000
+                    });
+                } catch {
+                    return;
+                }
+                await out.deferUpdate();
+                const announcement = out.fields.getTextInputValue("announcement");
+                await interaction.editReply({
+                    embeds: [
+                        new EmojiEmbed()
+                            .setTitle("Announcement")
+                            .setDescription(
+                                `Announcement will be sent to ${channelsToNotify.length} channels.\n\n${announcement}`
+                            )
+                            .setStatus("Success")
+                            .setEmoji("SETTINGS.STATS.GREEN")
+                    ],
+                    components: [
+                        new ActionRowBuilder<ButtonBuilder>().addComponents(
+                            new ButtonBuilder()
+                                .setCustomId("confirm")
+                                .setLabel("Confirm")
+                                .setStyle(ButtonStyle.Success),
+                            new ButtonBuilder().setCustomId("cancel").setLabel("Cancel").setStyle(ButtonStyle.Danger)
+                        )
+                    ]
+                });
+
+                let i;
+                try {
+                    i = await m.awaitMessageComponent<ComponentType.Button>({
+                        filter: (i) => i.user.id === interaction.user.id,
+                        time: 300000
+                    });
+                } catch {
+                    return;
+                }
+                if (i.customId === "confirm") {
+                    await i.deferUpdate();
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Announcement")
+                                .setDescription(
+                                    `Sending to ${channelsToNotify.length} channels. Preview:\n\n${announcement}`
+                                )
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ],
+                        components: []
+                    });
+                    const announcementEmbed = new EmojiEmbed()
+                        .setTitle("Developer Announcement")
+                        .setDescription(announcement)
+                        .setStatus("Danger")
+                        .setEmoji("NUCLEUS.LOGO")
+                        .setFooter({
+                            text: `Sent by ${interaction.user.username}`,
+                            iconURL: interaction.user.displayAvatarURL()
+                        });
+                    for (const channel of channelsToNotify) {
+                        const ch = (await client.channels.fetch(channel)) as GuildTextBasedChannel | null;
+                        if (!ch) continue;
+                        await ch.send({
+                            embeds: [announcementEmbed]
+                        });
+                    }
+                    await interaction.editReply({
+                        embeds: [
+                            new EmojiEmbed()
+                                .setTitle("Announcement")
+                                .setDescription(
+                                    `Sent to ${channelsToNotify.length} channels. Preview:\n\n${announcement}`
+                                )
+                                .setStatus("Success")
+                                .setEmoji("SETTINGS.STATS.GREEN")
+                        ],
+                        components: []
+                    });
+                } else if (i.customId === "cancel") {
+                    await i.deferUpdate();
+                    await interaction.editReply({
+                        embeds: [new EmojiEmbed().setTitle("Announcement Cancelled").setStatus("Danger")],
+                        components: []
+                    });
+                }
+                break;
+            }
         }
     }
 };
diff --git a/src/commands/nucleus/suggest.ts b/src/commands/nucleus/suggest.ts
index 79a0673..c1f0312 100644
--- a/src/commands/nucleus/suggest.ts
+++ b/src/commands/nucleus/suggest.ts
@@ -1,61 +1,133 @@
 import { LoadingEmbed } from "../../utils/defaults.js";
-import { ButtonStyle, CommandInteraction } from "discord.js";
-import Discord from "discord.js";
+import Discord, {
+    ActionRowBuilder,
+    ButtonBuilder,
+    ButtonStyle,
+    CommandInteraction,
+    ModalBuilder,
+    TextInputBuilder,
+    TextInputStyle
+} from "discord.js";
 import type { SlashCommandSubcommandBuilder } from "discord.js";
 import confirmationMessage from "../../utils/confirmationMessage.js";
 import EmojiEmbed from "../../utils/generateEmojiEmbed.js";
 import client from "../../utils/client.js";
-import getEmojiByName from "../../utils/getEmojiByName.js";
+import config from "../../config/main.js";
+import _ from "lodash";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
-    builder
-        .setName("suggest")
-        .setDescription("Sends a suggestion to the developers")
-        .addStringOption((option) =>
-            option.setName("suggestion").setDescription("The suggestion to send").setRequired(true)
-        );
+    builder.setName("suggest").setDescription("Sends a suggestion to the developers");
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     await interaction.guild?.members.fetch(interaction.member!.user.id);
-    const { renderUser } = client.logger;
-    const suggestion = interaction.options.get("suggestion")?.value as string;
     await interaction.reply({ embeds: LoadingEmbed, ephemeral: true });
-    const confirmation = await new confirmationMessage(interaction)
-        .setEmoji("ICONS.OPP.ADD")
-        .setTitle("Suggest")
-        .setDescription(
-            `**Suggestion:**\n> ${suggestion}\n` +
-                "Your username and ID will also be sent with your suggestion.\n\nAre you sure you want to send this suggestion?"
-        )
-        .setColor("Danger")
-        .setInverted(true)
-        .setFailedMessage("Your suggestion was deleted", "Success", "ICONS.ADD")
-        .send(true);
-    if (confirmation.cancelled || !confirmation.success) return;
-    await (client.channels.cache.get("955161206459600976") as Discord.TextChannel).send({
+    let closed = false;
+    let suggestionTitle: string | null = null;
+    let suggestionDesc: string | null = null;
+    do {
+        const modal = new ModalBuilder()
+            .setTitle("Suggestion")
+            .setComponents(
+                new ActionRowBuilder<TextInputBuilder>().addComponents(
+                    new TextInputBuilder()
+                        .setLabel("Suggestion Title")
+                        .setRequired(false)
+                        .setStyle(TextInputStyle.Short)
+                        .setCustomId("suggestionTitle")
+                        .setPlaceholder("Summarize your suggestion in 1 sentence...")
+                        .setMaxLength(256)
+                ),
+                new ActionRowBuilder<TextInputBuilder>().addComponents(
+                    new TextInputBuilder()
+                        .setLabel("Suggestion Description")
+                        .setCustomId("suggestionDesc")
+                        .setStyle(TextInputStyle.Paragraph)
+                        .setRequired(true)
+                        .setPlaceholder("Put the full details of your suggestion here...")
+                        .setMinLength(50)
+                )
+            );
+        const o: { suggestionDesc?: string; suggestionTitle?: string } = {};
+        if (suggestionTitle) {
+            o.suggestionTitle = suggestionTitle;
+            modal.components[0]!.components[0]!.setValue(suggestionTitle);
+        }
+        if (suggestionDesc) {
+            o.suggestionDesc = suggestionDesc;
+            modal.components[1]!.components[0]!.setValue(suggestionDesc);
+        }
+        const confirmation = await new confirmationMessage(interaction)
+            .setEmoji("ICONS.ADD")
+            .setTitle("Suggest")
+            .setDescription(
+                suggestionDesc
+                    ? `Are you sure you want to send this suggestion?\n\n**Title ${
+                          suggestionTitle ? "" : "(*Placeholder*)"
+                      }:**\n> ${
+                          suggestionTitle ? suggestionTitle : `${suggestionDesc.substring(0, 70)}`
+                      }\n\n**Suggestion:**\n> ${suggestionDesc}`
+                    : "Please enter your suggestion below."
+            )
+            .addModal("Edit Suggestion", "ICONS.EDIT", "editSuggestion", _.cloneDeep(o), modal)
+            .setColor("Success")
+            .setInverted(true)
+            .setFailedMessage("Your suggestion was deleted", "Success", "ICONS.ADD")
+            .send(true);
+        if (confirmation.modals?.[0] && !_.isEqual(confirmation.modals[0].values, o)) {
+            suggestionTitle = confirmation.modals[0].values["suggestionTitle"] as string | null;
+            suggestionDesc = confirmation.modals[0].values["suggestionDesc"] as string | null;
+            continue;
+        }
+        if (confirmation.cancelled || confirmation.success === false) {
+            closed = true;
+            return;
+        }
+        if (confirmation.success) {
+            closed = true;
+        }
+    } while (!closed);
+    if (!suggestionDesc) return;
+    suggestionTitle = suggestionTitle ? suggestionTitle : `${suggestionDesc.substring(0, 70)}`;
+    const channel = client.channels.cache.get(config.suggestionChannel) as Discord.TextChannel;
+    const m = await channel.send({ embeds: LoadingEmbed });
+    const issue = await client.GitHub.rest.issues.create({
+        owner: "ClicksMinutePer",
+        repo: "Nucleus",
+        title: suggestionTitle,
+        body: `Linked Suggestion in Private Developer Channel: [Message](${
+            m.url
+        })\n\n**Suggestion:**\n> ${suggestionDesc
+            .replaceAll("@", "@<!-- -->")
+            .replaceAll("/issues", "/issues<!-- -->")
+            .replaceAll("/pull", "/pull<!-- -->")}\n\n`,
+        labels: ["🤖 Auto", "📝 Suggestion"]
+    });
+    await m.edit({
         embeds: [
             new EmojiEmbed()
-                .setTitle("Suggestion")
-                .setDescription(
-                    `**From:** ${renderUser(
-                        interaction.member!.user as Discord.User
-                    )}\n**Suggestion:**\n> ${suggestion}\n\n` +
-                        `**Server:** ${interaction.guild!.name} (${interaction.guild!.id})\n`
-                )
-                .setStatus("Warning")
+                .setEmoji("ICONS.ADD")
+                .setTitle(`Suggestion from ${interaction.user.tag} (${interaction.user.id})`)
+                .setDescription(`**Suggestion:**\n> ${suggestionDesc}\n\n`)
+                .setStatus("Success")
+                .setFooter({ text: `${issue.data.number}` })
         ],
         components: [
-            new Discord.ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
-                new Discord.ButtonBuilder()
-                    .setCustomId("suggestionAccept")
-                    .setLabel("Accept")
-                    .setStyle(ButtonStyle.Secondary)
-                    .setEmoji(getEmojiByName("ICONS.ADD", "id")),
-                new Discord.ButtonBuilder()
-                    .setCustomId("suggestionDeny")
-                    .setLabel("Delete")
-                    .setStyle(ButtonStyle.Secondary)
-                    .setEmoji(getEmojiByName("ICONS.REMOVE", "id"))
+            new Discord.ActionRowBuilder<ButtonBuilder>().addComponents(
+                new ButtonBuilder().setCustomId("accept:Suggestion").setLabel("Accept").setStyle(ButtonStyle.Success),
+                new ButtonBuilder().setCustomId("deny:Suggestion").setLabel("Deny").setStyle(ButtonStyle.Danger),
+                new ButtonBuilder().setCustomId("close:Suggestion").setLabel("Close").setStyle(ButtonStyle.Secondary),
+                new ButtonBuilder()
+                    .setCustomId("implemented:Suggestion")
+                    .setLabel("Implemented")
+                    .setStyle(ButtonStyle.Secondary),
+                new ButtonBuilder()
+                    .setLabel(`Open Issue #${issue.data.number}`)
+                    .setStyle(ButtonStyle.Link)
+                    .setURL(`https://github.com/ClicksMinutePer/Nucleus/issues/${issue.data.number}`)
+            ),
+            new Discord.ActionRowBuilder<ButtonBuilder>().addComponents(
+                new ButtonBuilder().setCustomId("lock:Suggestion").setLabel("Lock").setStyle(ButtonStyle.Danger),
+                new ButtonBuilder().setCustomId("spam:Suggestion").setLabel("Mark as Spam").setStyle(ButtonStyle.Danger)
             )
         ]
     });
diff --git a/src/commands/privacy.ts b/src/commands/privacy.ts
index 590e866..aa17e7b 100644
--- a/src/commands/privacy.ts
+++ b/src/commands/privacy.ts
@@ -29,11 +29,11 @@
                     .setDescription(
                         "Nucleus is a bot that naturally needs to store data about servers.\n" +
                             "We are entirely [open source](https://github.com/ClicksMinutePer/Nucleus), so you can check exactly what we store, and how it works.\n\n" +
-                            "Any questions about Nucleus, how it works, and what data is stored can be asked in [our server](https://discord.gg/bPaNnxe)."
+                            "Any questions about Nucleus, how it works, and what data is stored can be asked in [our server](https://discord.gg/bPaNnxe)." +
+                            "\n\n[[Privacy Policy]](https://clicksminuteper.github.io/policies/nucleus) | [[Terms of Service]](https://clicksminuteper.github.io/policies/nucleustos)"
                     )
                     .setEmoji("NUCLEUS.LOGO")
                     .setStatus("Danger")
-                    .setFooter({ text: "https://clicksminuteper.github.io/policies/nucleus" })
             )
             .setTitle("Welcome")
             .setDescription("General privacy information")
@@ -43,15 +43,16 @@
                 new EmojiEmbed()
                     .setTitle("Scanners")
                     .setDescription(
-                        "Nucleus uses [unscan](https://rapidapi.com/abcdan/api/unscan/) to scan links, images and files for malware and other threats.\n" +
-                            'This service\'s [privacy policy](https://unscan.co/policies) is public, and they "do not store or sell your data."'
+                        "Nucleus scans content sent by users for malware and NSFW content\n" +
+                            "Malware is detected using [ClamAV](https://clamav.net/), and the standard ClamAV database.\n" +
+                            "NSFW detection is provided by [NsfwJS](https://nsfwjs.com/), with a model provided by [GantMan](https://github.com/GantMan/nsfw_model/releases/tag/1.1.0)\n\n" +
+                            "All data is processed on our servers and is not processed by a 3rd party."
                     )
                     .setEmoji("NUCLEUS.LOGO")
                     .setStatus("Danger")
-                    .setFooter({ text: "https://clicksminuteper.github.io/policies/nucleus" })
             )
             .setTitle("Scanners")
-            .setDescription("About Unscan")
+            .setDescription("About Scanners")
             .setPageId(1),
         new Embed()
             .setEmbed(
@@ -62,13 +63,12 @@
                     )
                     .setEmoji("NUCLEUS.LOGO")
                     .setStatus("Danger")
-                    .setFooter({ text: "https://clicksminuteper.github.io/policies/nucleus" })
             )
             .setTitle("Link scanning and Transcripts")
             .setDescription("Information about how links and images are scanned, and transcripts are stored")
             .setPageId(2)
     ].concat(
-        (interaction.member as Discord.GuildMember).permissions.has("Administrator")
+        (interaction.member as Discord.GuildMember).id === interaction.guild!.ownerId
             ? [
                   new Embed()
                       .setEmbed(
@@ -77,7 +77,6 @@
                               .setDescription("Below are buttons for controlling this servers privacy settings")
                               .setEmoji("NUCLEUS.LOGO")
                               .setStatus("Danger")
-                              .setFooter({ text: "https://clicksminuteper.github.io/policies/nucleus" })
                       )
                       .setTitle("Options")
                       .setDescription("Options")
@@ -88,7 +87,6 @@
                                   .setLabel("Clear all data")
                                   .setCustomId("clear-all-data")
                                   .setStyle(ButtonStyle.Danger)
-                                  .setDisabled(!(interaction.user.id === interaction.guild!.ownerId))
                           ])
                       ])
               ]
@@ -214,7 +212,7 @@
             const em = new Discord.EmbedBuilder(pages[page]!.embed);
             em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
             em.setFooter({ text: "Message closed" });
-            interaction.editReply({ embeds: [em], components: [] });
+            await interaction.editReply({ embeds: [em], components: [] });
             return;
         }
     }
diff --git a/src/commands/server/about.ts b/src/commands/server/about.ts
index 815b9e6..1857653 100644
--- a/src/commands/server/about.ts
+++ b/src/commands/server/about.ts
@@ -32,7 +32,7 @@
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     const guild = interaction.guild!;
     const { renderUser, renderDelta } = client.logger;
-    interaction.reply({
+    await interaction.reply({
         embeds: [
             new EmojiEmbed()
                 .setTitle("Server Info")
diff --git a/src/commands/server/buttons.ts b/src/commands/server/buttons.ts
index 3ba9c25..f07f3ce 100644
--- a/src/commands/server/buttons.ts
+++ b/src/commands/server/buttons.ts
@@ -20,6 +20,7 @@
 import lodash from "lodash";
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import { modalInteractionCollector } from "../../utils/dualCollector.js";
+import _ from "lodash";
 
 export const command = new SlashCommandSubcommandBuilder()
     .setName("buttons")
@@ -50,6 +51,27 @@
     createticket: "Create Ticket"
 };
 
+const presetButtons = [
+    {
+        title: "Verify",
+        description: "Click the button below to get verified in the server.",
+        buttons: ["verifybutton"],
+        color: "GREEN"
+    },
+    {
+        title: "Get Roles",
+        description: "Click the button to choose which roles you would like in the server",
+        buttons: ["rolemenu"],
+        color: "BLUE"
+    },
+    {
+        title: "Create Ticket",
+        description: "Click the button below to create a ticket",
+        buttons: ["createticket"],
+        color: "RED"
+    }
+];
+
 export const callback = async (interaction: CommandInteraction): Promise<void> => {
     const m = await interaction.reply({
         embeds: LoadingEmbed,
@@ -58,7 +80,7 @@
     });
 
     let closed = false;
-    const data: Data = {
+    let data: Data = {
         buttons: [],
         title: null,
         description: null,
@@ -67,7 +89,11 @@
     };
     do {
         const buttons = new ActionRowBuilder<ButtonBuilder>().addComponents(
-            new ButtonBuilder().setCustomId("edit").setLabel("Edit Embed").setStyle(ButtonStyle.Secondary),
+            new ButtonBuilder()
+                .setCustomId("edit")
+                .setLabel("Edit Embed")
+                .setStyle(ButtonStyle.Secondary)
+                .setEmoji(getEmojiByName("ICONS.EDIT", "id") as APIMessageComponentEmoji),
             new ButtonBuilder()
                 .setCustomId("send")
                 .setLabel("Send")
@@ -91,6 +117,22 @@
                 )
         );
 
+        const presetSelect = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
+            new StringSelectMenuBuilder()
+                .setCustomId("preset")
+                .setPlaceholder("Select a preset")
+                .setMaxValues(1)
+                .addOptions(
+                    presetButtons.map((preset, i) => {
+                        return new StringSelectMenuOptionBuilder()
+                            .setLabel(preset.title)
+                            .setValue(i.toString())
+                            .setDescription(preset.description)
+                            .setEmoji(getEmojiByName("COLORS." + preset.color, "id") as APIMessageComponentEmoji);
+                    })
+                )
+        );
+
         const buttonSelect = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
             new StringSelectMenuBuilder()
                 .setCustomId("button")
@@ -137,13 +179,14 @@
 
         await interaction.editReply({
             embeds: [embed],
-            components: [colorSelect, buttonSelect, channelMenu, buttons]
+            components: [presetSelect, colorSelect, buttonSelect, channelMenu, buttons]
         });
 
         let i: Discord.ButtonInteraction | Discord.ChannelSelectMenuInteraction | Discord.StringSelectMenuInteraction;
         try {
             i = (await interaction.channel!.awaitMessageComponent({
-                filter: (i: Discord.Interaction) => i.user.id === interaction.user.id,
+                filter: (i: Discord.Interaction) =>
+                    i.user.id === interaction.user.id && i.isMessageComponent() && i.message.id === m.id,
                 time: 300000
             })) as
                 | Discord.ButtonInteraction
@@ -223,17 +266,18 @@
                 case "send": {
                     await i.deferUpdate();
                     const channel = interaction.guild!.channels.cache.get(data.channel!) as Discord.TextChannel;
-                    const components = new ActionRowBuilder<ButtonBuilder>();
+                    const messageData: MessageCreateOptions = {};
                     for (const button of data.buttons) {
-                        components.addComponents(
-                            new ButtonBuilder()
-                                .setCustomId(button)
-                                .setLabel(buttonNames[button]!)
-                                .setStyle(ButtonStyle.Primary)
-                        );
+                        messageData.components = [
+                            new ActionRowBuilder<ButtonBuilder>().addComponents(
+                                new ButtonBuilder()
+                                    .setCustomId(button)
+                                    .setLabel(buttonNames[button]!)
+                                    .setStyle(ButtonStyle.Primary)
+                            )
+                        ];
                     }
-                    const messageData: MessageCreateOptions = { components: [components] };
-                    if (data.title || data.description) {
+                    if (data.title || data.description || data.color) {
                         const e = new EmojiEmbed();
                         if (data.title) e.setTitle(data.title);
                         if (data.description) e.setDescription(data.description);
@@ -251,6 +295,12 @@
                 console.log(err);
             }
             switch (i.customId) {
+                case "preset": {
+                    const chosen = presetButtons[parseInt(i.values[0]!)]!;
+                    const newColor = colors[chosen.color!]!;
+                    data = _.assign(data, chosen, { color: newColor });
+                    break;
+                }
                 case "color": {
                     data.color = colors[i.values[0]!]!;
                     break;
diff --git a/src/commands/settings/automod.ts b/src/commands/settings/automod.ts
index 684edf4..7756ae7 100644
--- a/src/commands/settings/automod.ts
+++ b/src/commands/settings/automod.ts
@@ -28,6 +28,7 @@
 import getEmojiByName from "../../utils/getEmojiByName.js";
 import { modalInteractionCollector } from "../../utils/dualCollector.js";
 import listToAndMore from "../../utils/listToAndMore.js";
+import _ from "lodash";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder.setName("automod").setDescription("Setting for automatic moderation features");
@@ -157,6 +158,7 @@
 const imageMenu = async (
     interaction: StringSelectMenuInteraction,
     m: Message,
+    unsavedChanges: boolean,
     current: {
         NSFW: boolean;
         size: boolean;
@@ -188,7 +190,10 @@
             // .setEmoji("")  // TODO
             .setDescription(
                 `${emojiFromBoolean(current.NSFW)} **NSFW**\n` + `${emojiFromBoolean(current.size)} **Size**\n`
-            );
+            )
+            .setFooter({
+                text: unsavedChanges ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [options] });
 
@@ -209,10 +214,12 @@
             }
             case "nsfw": {
                 current.NSFW = !current.NSFW;
+                unsavedChanges = true;
                 break;
             }
             case "size": {
                 current.size = !current.size;
+                unsavedChanges = true;
                 break;
             }
         }
@@ -223,6 +230,7 @@
 const wordMenu = async (
     interaction: StringSelectMenuInteraction,
     m: Message,
+    unsavedChanges: boolean,
     current: {
         enabled: boolean;
         words: { strict: string[]; loose: string[] };
@@ -298,7 +306,10 @@
                     )
             )
             .setStatus("Success")
-            .setEmoji("GUILD.SETTINGS.GREEN");
+            .setEmoji("GUILD.SETTINGS.GREEN")
+            .setFooter({
+                text: unsavedChanges ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [selectMenu, buttons] });
 
@@ -322,6 +333,7 @@
                 }
                 case "enabled": {
                     current.enabled = !current.enabled;
+                    unsavedChanges = true;
                     break;
                 }
             }
@@ -393,6 +405,7 @@
                         .split(",")
                         .map((s) => s.trim())
                         .filter((s) => s.length > 0);
+                    unsavedChanges = true;
                     break;
                 }
                 case "allowedUsers": {
@@ -404,6 +417,7 @@
                         "member",
                         "Word Filter"
                     );
+                    unsavedChanges = true;
                     break;
                 }
                 case "allowedRoles": {
@@ -415,6 +429,7 @@
                         "role",
                         "Word Filter"
                     );
+                    unsavedChanges = true;
                     break;
                 }
                 case "allowedChannels": {
@@ -426,6 +441,7 @@
                         "channel",
                         "Word Filter"
                     );
+                    unsavedChanges = true;
                     break;
                 }
             }
@@ -437,6 +453,7 @@
 const inviteMenu = async (
     interaction: StringSelectMenuInteraction,
     m: Message,
+    unsavedChanges: boolean,
     current: {
         enabled: boolean;
         allowed: { users: string[]; roles: string[]; channels: string[] };
@@ -505,7 +522,10 @@
                     )
             )
             .setStatus("Success")
-            .setEmoji("GUILD.SETTINGS.GREEN");
+            .setEmoji("GUILD.SETTINGS.GREEN")
+            .setFooter({
+                text: unsavedChanges ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [menu, buttons] });
 
@@ -528,6 +548,7 @@
                 }
                 case "enabled": {
                     current.enabled = !current.enabled;
+                    unsavedChanges = true;
                     break;
                 }
             }
@@ -542,6 +563,7 @@
                         "member",
                         "Invite Settings"
                     );
+                    unsavedChanges = true;
                     break;
                 }
                 case "roles": {
@@ -552,6 +574,7 @@
                         "role",
                         "Invite Settings"
                     );
+                    unsavedChanges = true;
                     break;
                 }
                 case "channels": {
@@ -562,6 +585,7 @@
                         "channel",
                         "Invite Settings"
                     );
+                    unsavedChanges = true;
                     break;
                 }
             }
@@ -573,6 +597,7 @@
 const mentionMenu = async (
     interaction: StringSelectMenuInteraction,
     m: Message,
+    unsavedChanges: boolean,
     current: {
         mass: number;
         everyone: boolean;
@@ -689,7 +714,10 @@
                     )
             )
             .setStatus("Success")
-            .setEmoji("GUILD.SETTINGS.GREEN");
+            .setEmoji("GUILD.SETTINGS.GREEN")
+            .setFooter({
+                text: unsavedChanges ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [menu, allowedMenu, buttons] });
 
@@ -713,10 +741,12 @@
                 }
                 case "everyone": {
                     current.everyone = !current.everyone;
+                    unsavedChanges = true;
                     break;
                 }
                 case "roles": {
                     current.roles = !current.roles;
+                    unsavedChanges = true;
                     break;
                 }
             }
@@ -766,6 +796,7 @@
                             if (!out) break;
                             if (out.isButton()) break;
                             current.mass = parseInt(out.fields.getTextInputValue("mass"));
+                            unsavedChanges = true;
                             break;
                         }
                         case "roles": {
@@ -777,6 +808,7 @@
                                 "role",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                     }
@@ -793,6 +825,7 @@
                                 "member",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                         case "roles": {
@@ -803,6 +836,7 @@
                                 "role",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                         case "channels": {
@@ -813,6 +847,7 @@
                                 "channel",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                     }
@@ -827,6 +862,7 @@
 const cleanMenu = async (
     interaction: StringSelectMenuInteraction,
     m: Message,
+    unsavedChanges: boolean,
     current?: {
         channels?: string[];
         allowed?: {
@@ -889,7 +925,10 @@
                             : "None"
                     }\n\n`
             )
-            .setStatus("Success");
+            .setStatus("Success")
+            .setFooter({
+                text: unsavedChanges ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [channelMenu, allowedMenu, buttons] });
 
@@ -957,6 +996,7 @@
                             }
                         }
                     }
+                    unsavedChanges = true;
                     break;
                 }
                 case "allowed": {
@@ -969,6 +1009,7 @@
                                 "member",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                         case "roles": {
@@ -979,6 +1020,7 @@
                                 "role",
                                 "Mention Settings"
                             );
+                            unsavedChanges = true;
                             break;
                         }
                     }
@@ -1000,15 +1042,19 @@
 const callback = async (interaction: CommandInteraction): Promise<void> => {
     if (!interaction.guild) return;
     const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
-    const config = (await client.database.guilds.read(interaction.guild.id)).filters;
+    let config = (await client.database.guilds.read(interaction.guild.id)).filters;
 
     let closed = false;
 
-    const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
-        new ButtonBuilder().setCustomId("save").setLabel("Save").setStyle(ButtonStyle.Success)
-    );
-
+    let current = _.cloneDeep(config);
     do {
+        const button = new ActionRowBuilder<ButtonBuilder>().addComponents(
+            new ButtonBuilder()
+                .setCustomId("save")
+                .setLabel("Save")
+                .setStyle(ButtonStyle.Success)
+                .setDisabled(_.isEqual(config, current))
+        );
         const selectMenu = new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(
             new StringSelectMenuBuilder()
                 .setCustomId("filter")
@@ -1054,7 +1100,10 @@
                     `${emojiFromBoolean(config.clean.channels.length > 0)} **Clean**\n`
             )
             .setStatus("Success")
-            .setEmoji("GUILD.SETTINGS.GREEN");
+            .setEmoji("GUILD.SETTINGS.GREEN")
+            .setFooter({
+                text: _.isEqual(config, current) ? "No changes made" : "Changes not saved"
+            });
 
         await interaction.editReply({ embeds: [embed], components: [selectMenu, button] });
 
@@ -1068,40 +1117,37 @@
             closed = true;
             continue;
         }
+        await i.deferUpdate();
         if (i.isButton()) {
-            await i.deferUpdate();
-            await client.database.guilds.write(interaction.guild.id, { filters: config });
+            await client.database.guilds.write(interaction.guild.id, { filters: current });
             await client.memory.forceUpdate(interaction.guild.id);
+            config = current;
+            current = _.cloneDeep(config);
         } else {
             switch (i.values[0]) {
                 case "invites": {
-                    i.deferUpdate();
-                    config.invite = await inviteMenu(i, m, config.invite);
+                    config.invite = await inviteMenu(i, m, _.isEqual(config, current), config.invite);
                     break;
                 }
                 case "mentions": {
-                    i.deferUpdate();
-                    config.pings = await mentionMenu(i, m, config.pings);
+                    config.pings = await mentionMenu(i, m, _.isEqual(config, current), config.pings);
                     break;
                 }
                 case "words": {
-                    config.wordFilter = await wordMenu(i, m, config.wordFilter);
+                    config.wordFilter = await wordMenu(i, m, _.isEqual(config, current), config.wordFilter);
                     break;
                 }
                 case "malware": {
-                    i.deferUpdate();
                     config.malware = !config.malware;
                     break;
                 }
                 case "images": {
-                    i.deferUpdate();
-                    const next = await imageMenu(i, m, config.images);
+                    const next = await imageMenu(i, m, _.isEqual(config, current), config.images);
                     config.images = next;
                     break;
                 }
                 case "clean": {
-                    i.deferUpdate();
-                    const next = await cleanMenu(i, m, config.clean);
+                    const next = await cleanMenu(i, m, _.isEqual(config, current), config.clean);
                     config.clean = next;
                     break;
                 }
diff --git a/src/commands/settings/autopublish.ts b/src/commands/settings/autopublish.ts
index afc4e7d..421cfb8 100644
--- a/src/commands/settings/autopublish.ts
+++ b/src/commands/settings/autopublish.ts
@@ -20,7 +20,7 @@
     .setDescription("Automatically publish messages posted in announcement channels");
 
 export const callback = async (interaction: CommandInteraction): Promise<void> => {
-    await interaction.reply({
+    const m = await interaction.reply({
         embeds: LoadingEmbed,
         ephemeral: true,
         fetchReply: true
@@ -70,7 +70,8 @@
         let i: Discord.ButtonInteraction | Discord.ChannelSelectMenuInteraction;
         try {
             i = (await interaction.channel!.awaitMessageComponent({
-                filter: (i: Discord.Interaction) => i.user.id === interaction.user.id,
+                filter: (i: Discord.Interaction) =>
+                    i.user.id === interaction.user.id && i.isMessageComponent() && i.message.id === m.id,
                 time: 300000
             })) as Discord.ButtonInteraction | Discord.ChannelSelectMenuInteraction;
         } catch (e) {
diff --git a/src/commands/settings/logs/attachment.ts b/src/commands/settings/logs/attachment.ts
index 3ee7675..62abd7e 100644
--- a/src/commands/settings/logs/attachment.ts
+++ b/src/commands/settings/logs/attachment.ts
@@ -18,7 +18,7 @@
 
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     if (interaction.guild) client.database.premium.hasPremium(interaction.guild.id).finally(() => {});
-    await interaction.reply({
+    const m = await interaction.reply({
         embeds: LoadingEmbed,
         ephemeral: true,
         fetchReply: true
@@ -79,7 +79,7 @@
 
         let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
         try {
-            i = (await interaction.channel!.awaitMessageComponent({
+            i = (await m.awaitMessageComponent({
                 filter: (i: Discord.Interaction) => i.user.id === interaction.user.id,
                 time: 300000
             })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
diff --git a/src/commands/settings/logs/events.ts b/src/commands/settings/logs/events.ts
index 4cffab7..1041409 100644
--- a/src/commands/settings/logs/events.ts
+++ b/src/commands/settings/logs/events.ts
@@ -122,7 +122,7 @@
         let i: ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
         try {
             i = (await m.awaitMessageComponent({
-                filter: (i) => i.user.id === interaction.user.id,
+                filter: (i) => i.user.id === interaction.user.id && i.isMessageComponent() && i.message.id === m.id,
                 time: 300000
             })) as ButtonInteraction | StringSelectMenuInteraction | ChannelSelectMenuInteraction;
         } catch (e) {
diff --git a/src/commands/settings/logs/warnings.ts b/src/commands/settings/logs/warnings.ts
index 38b645a..37c5ac8 100644
--- a/src/commands/settings/logs/warnings.ts
+++ b/src/commands/settings/logs/warnings.ts
@@ -5,26 +5,28 @@
     ButtonBuilder,
     ButtonStyle,
     ChannelSelectMenuBuilder,
-    ChannelType
+    ChannelType,
+    ComponentType
 } from "discord.js";
 import EmojiEmbed from "../../../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../../../utils/getEmojiByName.js";
 import type { SlashCommandSubcommandBuilder } from "discord.js";
 import client from "../../../utils/client.js";
+import _ from "lodash";
 
 const command = (builder: SlashCommandSubcommandBuilder) =>
     builder.setName("warnings").setDescription("Settings for the staff notifications channel");
 
 const callback = async (interaction: CommandInteraction): Promise<unknown> => {
     if (!interaction.guild) return;
-    await interaction.reply({
+    const m = await interaction.reply({
         embeds: LoadingEmbed,
         ephemeral: true,
         fetchReply: true
     });
 
     let data = await client.database.guilds.read(interaction.guild.id);
-    let channel = data.logging.staff.channel;
+    let channel = _.clone(data.logging.staff.channel);
     let closed = false;
     do {
         const channelMenu = new ActionRowBuilder<ChannelSelectMenuBuilder>().addComponents(
@@ -45,7 +47,7 @@
                 .setLabel("Save")
                 .setStyle(ButtonStyle.Success)
                 .setEmoji(getEmojiByName("ICONS.SAVE", "id") as Discord.APIMessageComponentEmoji)
-                .setDisabled(channel === data.logging.staff.channel)
+                .setDisabled(_.isEqual(channel, data.logging.staff.channel))
         );
 
         const embed = new EmojiEmbed()
@@ -62,12 +64,13 @@
             components: [channelMenu, buttons]
         });
 
-        let i: Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+        let i: Discord.ButtonInteraction | Discord.ChannelSelectMenuInteraction;
         try {
-            i = (await interaction.channel!.awaitMessageComponent({
-                filter: (i: Discord.Interaction) => i.user.id === interaction.user.id,
+            i = await interaction.channel!.awaitMessageComponent<ComponentType.Button | ComponentType.ChannelSelect>({
+                filter: (i: Discord.Interaction) =>
+                    i.user.id === interaction.user.id && i.isMessageComponent() && i.message.id === m.id,
                 time: 300000
-            })) as Discord.ButtonInteraction | Discord.SelectMenuInteraction;
+            });
         } catch (e) {
             closed = true;
             continue;
@@ -81,7 +84,7 @@
                 }
                 case "save": {
                     await client.database.guilds.write(interaction.guild!.id, {
-                        "logging.warnings.channel": channel
+                        "logging.staff.channel": channel
                     });
                     data = await client.database.guilds.read(interaction.guild!.id);
                     await client.memory.forceUpdate(interaction.guild!.id);
diff --git a/src/commands/settings/moderation.ts b/src/commands/settings/moderation.ts
index 6ee6e1e..4d850a9 100644
--- a/src/commands/settings/moderation.ts
+++ b/src/commands/settings/moderation.ts
@@ -29,7 +29,6 @@
     while (!timedOut) {
         const config = await client.database.guilds.read(interaction.guild!.id);
         const moderation = config.moderation;
-        console.log(moderation);
         await interaction.editReply({
             embeds: [
                 new EmojiEmbed()
diff --git a/src/commands/settings/rolemenu.ts b/src/commands/settings/rolemenu.ts
index e683e4f..7da9dfe 100644
--- a/src/commands/settings/rolemenu.ts
+++ b/src/commands/settings/rolemenu.ts
@@ -89,7 +89,7 @@
         out = null;
     }
     if (!out) return;
-    out.deferUpdate();
+    await out.deferUpdate();
     if (out.isButton()) return;
     const values = out.values;
 
@@ -218,7 +218,7 @@
                     `**Max:** ${data.max}\n`
             );
 
-        interaction.editReply({ embeds: [embed], components: [previewSelect, buttons] });
+        await interaction.editReply({ embeds: [embed], components: [previewSelect, buttons] });
         let i: StringSelectMenuInteraction | ButtonInteraction;
         try {
             i = (await m.awaitMessageComponent({
@@ -304,7 +304,7 @@
                     }\n`
             );
 
-        interaction.editReply({
+        await interaction.editReply({
             embeds: [embed],
             components: [new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(roleSelect), buttons]
         });
diff --git a/src/commands/settings/stats.ts b/src/commands/settings/stats.ts
index d4e4439..ed2fc6f 100644
--- a/src/commands/settings/stats.ts
+++ b/src/commands/settings/stats.ts
@@ -198,7 +198,7 @@
                             )
                         ]
                     });
-                    showModal(i, { name: newChannelName, enabled: newChannelEnabled });
+                    await showModal(i, { name: newChannelName, enabled: newChannelEnabled });
 
                     const out: Discord.ModalSubmitInteraction | ButtonInteraction | null =
                         await modalInteractionCollector(m, interaction.user);
@@ -336,7 +336,7 @@
             }
         }
 
-        interaction.editReply({
+        await interaction.editReply({
             embeds: [embed],
             components: [
                 new ActionRowBuilder<StringSelectMenuBuilder>().addComponents(pageSelect),
@@ -367,7 +367,7 @@
                     modified = true;
                     switch (i.values[0]!) {
                         case "edit": {
-                            showModal(i, current!);
+                            await showModal(i, current!);
                             await interaction.editReply({
                                 embeds: [
                                     new EmojiEmbed()
@@ -439,7 +439,7 @@
                 }
                 case "save": {
                     await client.database.guilds.write(interaction.guild.id, { stats: currentObject });
-                    singleNotify("statsChannelDeleted", interaction.guild.id, true);
+                    await singleNotify("statsChannelDeleted", interaction.guild.id, true);
                     modified = false;
                     await client.memory.forceUpdate(interaction.guild.id);
                     break;
diff --git a/src/commands/settings/tracks.ts b/src/commands/settings/tracks.ts
index 625bcfb..e608f31 100644
--- a/src/commands/settings/tracks.ts
+++ b/src/commands/settings/tracks.ts
@@ -142,7 +142,7 @@
         out = null;
     }
     if (!out) return;
-    out.deferUpdate();
+    await out.deferUpdate();
     if (out.isButton()) return;
     const values = out.values;
 
@@ -171,6 +171,7 @@
     const isAdmin = (interaction.member!.permissions as PermissionsBitField).has("Administrator");
     if (!current) {
         current = _.cloneDeep(defaultTrackData);
+        current.name = "Default";
     }
 
     const roleSelect = new ActionRowBuilder<RoleSelectMenuBuilder>().addComponents(
@@ -268,7 +269,7 @@
         ];
         if (current.track.length >= 1) comps.splice(1, 0, selectMenu);
 
-        interaction.editReply({ embeds: [embed], components: comps });
+        await interaction.editReply({ embeds: [embed], components: comps });
 
         let out: ButtonInteraction | RoleSelectMenuInteraction | StringSelectMenuInteraction | null;
 
@@ -286,7 +287,7 @@
         if (out.isButton()) {
             switch (out.customId) {
                 case "back": {
-                    out.deferUpdate();
+                    await out.deferUpdate();
                     closed = true;
                     break;
                 }
@@ -295,23 +296,23 @@
                     break;
                 }
                 case "reorder": {
-                    out.deferUpdate();
+                    await out.deferUpdate();
                     current.track = (await reorderTracks(interaction, out, message, roles, current.track))!;
                     break;
                 }
                 case "retainPrevious": {
-                    out.deferUpdate();
+                    await out.deferUpdate();
                     current.retainPrevious = !current.retainPrevious;
                     break;
                 }
                 case "nullable": {
-                    out.deferUpdate();
+                    await out.deferUpdate();
                     current.nullable = !current.nullable;
                     break;
                 }
             }
         } else if (out.isStringSelectMenu()) {
-            out.deferUpdate();
+            await out.deferUpdate();
             switch (out.customId) {
                 case "removeRole": {
                     const index = current.track.findIndex(
@@ -322,7 +323,7 @@
                 }
             }
         } else {
-            out.deferUpdate();
+            await out.deferUpdate();
             switch (out.customId) {
                 case "addRole": {
                     const role = out.values![0]!;
@@ -348,16 +349,15 @@
 const callback = async (interaction: CommandInteraction) => {
     const m = await interaction.reply({ embeds: LoadingEmbed, fetchReply: true, ephemeral: true });
     const config = await client.database.guilds.read(interaction.guild!.id);
-    const tracks: ObjectSchema[] = config.tracks;
+    const tracks: ObjectSchema[] = _.cloneDeep(config.tracks);
     const roles = await interaction.guild!.roles.fetch();
 
     let page = 0;
     let closed = false;
-    let modified = false;
 
     do {
         const embed = new EmojiEmbed().setTitle("Track Settings").setEmoji("TRACKS.ICON").setStatus("Success");
-        const noTracks = config.tracks.length === 0;
+        const noTracks = tracks.length === 0;
         let current: ObjectSchema;
 
         const pageSelect = new StringSelectMenuBuilder().setCustomId("page").setPlaceholder("Select a track to manage");
@@ -398,7 +398,7 @@
                 .setLabel("Save")
                 .setEmoji(getEmojiByName("ICONS.SAVE", "id") as APIMessageComponentEmoji)
                 .setStyle(ButtonStyle.Success)
-                .setDisabled(!modified)
+                .setDisabled(_.isEqual(tracks, config.tracks))
         );
         if (noTracks) {
             embed.setDescription(
@@ -471,13 +471,13 @@
                 case "add": {
                     const newPage = await editTrack(i, m, roles);
                     if (_.isEqual(newPage, defaultTrackData)) break;
-                    tracks.push();
+                    if (!newPage) break;
+                    tracks.push(newPage);
                     page = tracks.length - 1;
                     break;
                 }
                 case "save": {
-                    client.database.guilds.write(interaction.guild!.id, { tracks: tracks });
-                    modified = false;
+                    await client.database.guilds.write(interaction.guild!.id, { tracks: tracks });
                     await client.memory.forceUpdate(interaction.guild!.id);
                     break;
                 }
@@ -490,7 +490,6 @@
                             const edited = await editTrack(i, m, roles, current!);
                             if (!edited) break;
                             tracks[page] = edited;
-                            modified = true;
                             break;
                         }
                         case "delete": {
diff --git a/src/commands/settings/verify.ts b/src/commands/settings/verify.ts
index e2318fc..05c4764 100644
--- a/src/commands/settings/verify.ts
+++ b/src/commands/settings/verify.ts
@@ -82,7 +82,7 @@
         if (i.isButton()) {
             switch (i.customId) {
                 case "save": {
-                    client.database.guilds.write(interaction.guild.id, { verify: data });
+                    await client.database.guilds.write(interaction.guild.id, { verify: data });
                     config = await client.database.guilds.read(interaction.guild.id);
                     data = Object.assign({}, config.verify);
                     await client.memory.forceUpdate(interaction.guild.id);
diff --git a/src/commands/user/role.ts b/src/commands/user/role.ts
index 74b6c41..9a0a462 100644
--- a/src/commands/user/role.ts
+++ b/src/commands/user/role.ts
@@ -129,7 +129,7 @@
             continue;
         }
 
-        i.deferUpdate();
+        await i.deferUpdate();
         if (i.isButton()) {
             switch (i.customId) {
                 case "roleSave": {
diff --git a/src/commands/user/track.ts b/src/commands/user/track.ts
index 19b9da2..1ce05ee 100644
--- a/src/commands/user/track.ts
+++ b/src/commands/user/track.ts
@@ -97,7 +97,12 @@
                 selected.length
             } roles from this track. `;
             conflictDropdown = [];
-            if (roles.get(selected[0]!)!.position < memberRoles.highest.position || managed) {
+            const yourRoles = guild.members.cache.get(interaction.user.id)!.roles;
+            if (
+                (roles.get(selected[0]!)!.position < yourRoles.highest.position &&
+                    roles.get(selected[0]!)!.position < guild.members.me!.roles.highest.position!) ||
+                managed
+            ) {
                 generated +=
                     "In order to promote or demote this user, you must select which role the member should keep.";
                 selected.forEach((role) => {
@@ -115,8 +120,13 @@
                         .setPlaceholder("Select a role to keep")
                 ];
             } else {
-                generated +=
-                    "You don't have permission to manage one or more of the users roles, and therefore can't select one to keep.";
+                if (roles.get(selected[0]!)!.position >= yourRoles.highest.position) {
+                    generated +=
+                        "You don't have permission to manage one or more of the user's roles, and therefore can't select one to keep.";
+                } else {
+                    generated +=
+                        "I don't have permission to manage one or more of the user's roles, and therefore can't select one to keep.";
+                }
             }
         } else {
             currentRoleIndex = selected.length === 0 ? -1 : data.track.indexOf(selected[0]!.toString());
@@ -178,11 +188,12 @@
             timedOut = true;
             continue;
         }
-        component.deferUpdate();
+        await component.deferUpdate();
         if (component.customId === "conflict") {
             const rolesToRemove = selected.filter(
                 (role) => role !== (component as StringSelectMenuInteraction).values[0]
             );
+
             await member.roles.remove(rolesToRemove);
         } else if (component.customId === "promote") {
             if (
diff --git a/src/commands/verify.ts b/src/commands/verify.ts
index 0dd8b24..4bbe50f 100644
--- a/src/commands/verify.ts
+++ b/src/commands/verify.ts
@@ -5,7 +5,7 @@
 const command = new SlashCommandBuilder().setName("verify").setDescription("Get verified in the server");
 
 const callback = async (interaction: CommandInteraction): Promise<void> => {
-    verify(interaction);
+    await verify(interaction);
 };
 
 export { command };
diff --git a/src/config/emojis.json b/src/config/emojis.json
deleted file mode 100644
index 585934d..0000000
--- a/src/config/emojis.json
+++ /dev/null
@@ -1,402 +0,0 @@
-{
-    "NUCLEUS": {
-        "LOGO": "953040840945721385",
-        "PREMIUMACTIVATE": "a1067536222764925068",
-        "PREMIUM": "1067928702027042876",
-        "LOADING": "a946346549271732234",
-        "INFO": {
-            "HELP": "751751467014029322",
-            "ABOUT": "751762088346517504",
-            "COMMANDS": "751762088229339136",
-            "SUPPORT": "751762087780286495"
-        },
-        "COMMANDS": {
-            "RAID": "777143043711172608",
-            "LOCK": "776848800995868682",
-            "IGNORE": "777520659270074389"
-        }
-    },
-    "ICONS": {
-        "ADD": "826823514904330251",
-        "REMOVE": "826823515268186152",
-        "EDIT": "989911820267577366",
-        "HISTORY": "989911933069168690",
-        "FILTER": "990242059451514902",
-        "ATTACHMENT": "997570687193587812",
-        "LOGGING": "999613304446144562",
-        "SAVE": "1065722246322200586",
-        "REORDER": "1069323453909454890",
-        "PUBLISH": "1081691380004421743",
-        "NOTIFY": {
-            "ON": "1000726394579464232",
-            "OFF": "1078058136092541008"
-        },
-        "OPP": {
-            "ADD": "837355918831124500",
-            "REMOVE": "837355918420869162"
-        },
-        "CHANNEL": {
-            "GUILD_TEXT": "990209996182679632",
-            "GUILD_TEXT_NSFW": "990216363526221824",
-            "GUILD_VOICE": "990213162697637969",
-            "GUILD_VOICE_NSFW": "990216017244463124",
-            "GUILD_STORE": "853668786925469706",
-            "GUILD_NEWS": "853668786493063169",
-            "GUILD_NEWS_NSFW": "990216028300673094",
-            "GUILD_STAGE_VOICE": "853668786842763294",
-            "THREAD_CHANNEL": "990210005108158514",
-            "THREAD_PIPE": "990213168183779348",
-            "RULES": "990213153080115250",
-            "FORUM": "1061706437526552716",
-            "CATEGORY": "1064943289708597348"
-        },
-        "FLAGS": {
-            "RED": "1082719687219101800",
-            "YELLOW": "1082719684060794890",
-            "GREEN": "1082719681326108763",
-            "BLUE": "1082719679161843734",
-            "PURPLE": "1082719686292156628",
-            "GRAY": "1082719682492125337"
-        }
-    },
-    "CONTROL": {
-        "TICK": "947441964234702849",
-        "REDTICK": "999612396727439370",
-        "CROSS": "947441948543815720",
-        "BLOCKCROSS": "952261738349330493",
-        "BLOCKTICK": "991805475777695855",
-        "LEFT": "947441951148486728",
-        "RIGHT": "947441957473488916",
-        "UP": "963409197293273108",
-        "DOWN": "963409199549796352",
-        "DOWNLOAD": "947959513032585236",
-        "TICKET": "973253514488860683",
-        "MENU": "976580327835320410",
-        "PILL": {
-            "TICK": "753314339082993832",
-            "CROSS": "753314339389309100"
-        }
-    },
-    "STATUS": {
-        "ONLINE": "729064530084102166",
-        "IDLE": "729064531577536582",
-        "DND": "729064531057311886",
-        "STREAMING": "729764055082074153",
-        "OFFLINE": "729064531271221289"
-    },
-    "CHANNEL": {
-        "TEXT": {
-            "CREATE": "729066924943737033",
-            "EDIT": "951957316117360640",
-            "DELETE": "729064529211686922"
-        },
-        "VOICE": {
-            "CREATE": "729064530830950530",
-            "EDIT": "951957316071223336",
-            "DELETE": "729064530981683200"
-        },
-        "CATEGORY": {
-            "CREATE": "787987508465238026",
-            "EDIT": "787987508565770300",
-            "DELETE": "787987508507967488"
-        },
-        "PURGE": {
-            "RED": "729064530797133875",
-            "GREEN": "947443645391441940"
-        },
-        "TITLEUPDATE": "729763053620691044",
-        "TOPICUPDATE": "729763053477953536",
-        "SLOWMODE": {
-            "ON": "973616021304913950",
-            "OFF": "777138171447869480"
-        },
-        "NSFW": {
-            "ON": "729064531208175736",
-            "OFF": "729381430991388752"
-        }
-    },
-    "MEMBER": {
-        "JOIN": "729066519337762878",
-        "LEAVE": "729064531170558575",
-        "BOT": {
-            "JOIN": "729064528666689587",
-            "LEAVE": "729064528998039633"
-        },
-        "KICK": "729263536785850458",
-        "BAN": "729263536643112991",
-        "UNBAN": "729263536840114216"
-    },
-    "INVITE": {
-        "CREATE": "729064529274601482",
-        "DELETE": "729064531103580230"
-    },
-    "WEBHOOK": {
-        "CREATE": "752070251906203679",
-        "UPDATE": "752073772823216191",
-        "DELETE": "752070251948146768"
-    },
-    "MESSAGE": {
-        "CREATE": "751762088229339136",
-        "EDIT": "729065958584614925",
-        "DELETE": "729064530432360461",
-        "PIN": "729064530755190894",
-        "REACTION": {
-            "ADD": "",
-            "REMOVE": "",
-            "CLEAR": "729064531468353606"
-        },
-        "PING": {
-            "MASS": "729620608408879124",
-            "EVERYONE": "729064531073957909",
-            "ROLE": "729263536915742770"
-        }
-    },
-    "PUNISH": {
-        "WARN": {
-            "RED": "947433493384806430",
-            "YELLOW": "729764054897524768",
-            "GREEN": "947433504076091424"
-        },
-        "KICK": {
-            "RED": "729764053794422896",
-            "YELLOW": "947429333289562132",
-            "GREEN": "947428786692042764"
-        },
-        "BAN": {
-            "RED": "729764053861400637",
-            "YELLOW": "729764053941223476",
-            "GREEN": "947421674364629022"
-        },
-        "UNBAN": {
-            "RED": "972511610885255259",
-            "YELLOW": "972511620343414794",
-            "GREEN": "729263536840114216"
-        },
-        "MUTE": {
-            "RED": "947555098974883910",
-            "YELLOW": "729764053865463840",
-            "GREEN": "947555107980066866"
-        },
-        "SOFTBAN": "729764053941223476",
-        "VOICEMUTE": "729764054855450697",
-        "CLEARHISTORY": "729764062270980096",
-        "NICKNAME": {
-            "RED": "959762533101731980",
-            "YELLOW": "729064531019694090",
-            "GREEN": "959762533072392202"
-        }
-    },
-    "BADGES": {
-        "NUCLEUSDEVELOPER": "957722888360853595",
-        "CLICKSDEVELOPER": "957722888314683462",
-        "BOT": "776375959108190239",
-        "BOOSTER": "775783766131605545",
-        "HypeSquadOnlineHouse1": "775783765930016789",
-        "HypeSquadOnlineHouse2": "775783766152577095",
-        "HypeSquadOnlineHouse3": "775783766303440937",
-        "Hypesquad": "775783766194126908",
-        "PremiumEarlySupporter": "775783766055452693",
-        "BugHunterLevel1": "775783766252847154",
-        "BugHunterLevel2": "775783766130950234",
-        "Partner": "775783766178005033",
-        "Staff": "775783766383788082",
-        "VerifiedDeveloper": "775783766425600060",
-        "Quarantined": "1059794708638994474",
-        "Spammer": "1059794708638994474",
-        "ActiveDeveloper": "1059795592966053918"
-    },
-    "VOICE": {
-        "CONNECT": "784785219391193138",
-        "CHANGE": "784785219353968670",
-        "LEAVE": "784785219432480808",
-        "MUTE": "784785219613360149",
-        "UNMUTE": "784785219441524766",
-        "DEAFEN": "784785219424747550",
-        "UNDEAFEN": "784785219324346378",
-        "STREAM": {
-            "START": "853519659775819787",
-            "STOP": "853519660116213780"
-        },
-        "VIDEO": {
-            "START": "853519659945295873",
-            "STOP": "853519660116738078"
-        }
-    },
-    "SETTINGS": {
-        "STATS": {
-            "GREEN": "752214059159650396",
-            "RED": "1065677252630675556"
-        }
-    },
-    "GUILD": {
-        "RED": "959779988264079361",
-        "YELLOW": "729763053352124529",
-        "GREEN": "959779988503154698",
-        "EMOJI": {
-            "CREATE": "953035168115982437",
-            "EDIT": "729066518549233795",
-            "DELETE": "953035210121953320"
-        },
-        "SETTINGS": {
-            "GREEN": "752570111063228507",
-            "RED": "1068607393728049253"
-        },
-        "ICONCHANGE": "729763053612302356",
-        "TICKET": {
-            "OPEN": "853245836331188264",
-            "CLOSE": "853580122506133505",
-            "ARCHIVED": "853580122636025856"
-        },
-        "ROLES": {
-            "CREATE": "729064530763579413",
-            "DELETE": "729064530885476392",
-            "EDIT": "776109664793919489",
-            "MEMBERS": "752570111281594509",
-            "MESSAGES": "752570111373606942",
-            "VOICE": "752570111088525354"
-        }
-    },
-    "MOD": {
-        "IMAGES": {
-            "SWEARING": "730438422627614810",
-            "INVISIBLE": "730438422690398238",
-            "TOOBIG": "730438422921084998",
-            "TOOSMALL": "730438422921216150"
-        },
-        "SWEARING": "730438422816096377",
-        "SPAM": "730438422853845042"
-    },
-    "NUMBERS": [
-        {
-            "NORMAL": "753259024404840529",
-            "GREEN": "753312608378945648",
-            "RED": "753312608890650664"
-        },
-        {
-            "NORMAL": "753259025990418515",
-            "GREEN": "753312608550912112",
-            "RED": "753312609075462246"
-        },
-        {
-            "NORMAL": "753259024409034896",
-            "GREEN": "753312608513294366",
-            "RED": "753312608680935446"
-        },
-        {
-            "NORMAL": "753259024358703205",
-            "GREEN": "753312608815284426",
-            "RED": "753312609377320966"
-        },
-        {
-            "NORMAL": "753259024555835513",
-            "GREEN": "753312608735461457",
-            "RED": "753312609255686223"
-        },
-        {
-            "NORMAL": "753259024744579283",
-            "GREEN": "753312608630604017",
-            "RED": "753312609138376777"
-        },
-        {
-            "NORMAL": "753259024354639994",
-            "GREEN": "753312608656031806",
-            "RED": "753312609465270412"
-        },
-        {
-            "NORMAL": "753259024530800661",
-            "GREEN": "753312608718815322",
-            "RED": "753312609104822313"
-        },
-        {
-            "NORMAL": "753259024895574037",
-            "GREEN": "753312608790249646",
-            "RED": "753312609477984319"
-        },
-        {
-            "NORMAL": "753259024681533553",
-            "GREEN": "753312608899170365",
-            "RED": "753312609557545089"
-        }
-    ],
-    "BOTS": {
-        "GPS": "878919163937185803",
-        "NUCLEUS": "878919163597439016",
-        "CLICKSFORMS": "878919163337388073",
-        "CASTAWAY": "878919164255944726",
-        "CMPING": "878919164125929502",
-        "HOOKY": "878919164121731082"
-    },
-    "CFSERVICE": {
-        "VERIFIED": "881984571242053642",
-        "UNVERIFIED": "881984571258847232"
-    },
-    "TICKETS": {
-        "SUPPORT": "952295894370369587",
-        "REPORT": "952295894437482537",
-        "QUESTION": "952295894403907645",
-        "ISSUE": "952295894412316672",
-        "SUGGESTION": "952295894399725588",
-        "OTHER": "952295894445883502"
-    },
-    "TRACKS": {
-        "ICON": "963170616444334171",
-        "HORIZONTAL": {
-            "LEFT": {
-                "ACTIVE": "963121920038035506",
-                "INACTIVE": "963121944239153242"
-            },
-            "MIDDLE": {
-                "ACTIVE": "963121925893263420",
-                "INACTIVE": "963121949796597870"
-            },
-            "RIGHT": {
-                "ACTIVE": "963121933384302602",
-                "INACTIVE": "963121956125831168"
-            }
-        },
-        "VERTICAL": {
-            "TOP": {
-                "ACTIVE": "963122664648630293",
-                "INACTIVE": "963122659862917140",
-                "GRAY": {
-                    "ACTIVE": "963123505052934144",
-                    "INACTIVE": "963123495221469194"
-                }
-            },
-            "MIDDLE": {
-                "ACTIVE": "963122679332880384",
-                "INACTIVE": "963122673246937199",
-                "GRAY": {
-                    "ACTIVE": "963123517702955018",
-                    "INACTIVE": "963123511927390329"
-                }
-            },
-            "BOTTOM": {
-                "ACTIVE": "963122691752218624",
-                "INACTIVE": "963122685691453552",
-                "GRAY": {
-                    "ACTIVE": "963123529988059187",
-                    "INACTIVE": "963123523742748742"
-                }
-            }
-        },
-        "SINGLE": {
-            "ACTIVE": "963361162215424060",
-            "INACTIVE": "963361431758176316",
-            "GRAY": {
-                "ACTIVE": "963361204695334943",
-                "INACTIVE": "963361200828198952"
-            }
-        }
-    },
-    "COLORS": {
-        "RED": "875822912802803754",
-        "ORANGE": "875822913104785418",
-        "YELLOW": "875822913079611402",
-        "GREEN": "875822913213841418",
-        "BLUE": "875822912777637889",
-        "PURPLE": "875822913213841419",
-        "PINK": "875822913088020541",
-        "GRAY": "875822913117368340"
-    }
-}
diff --git a/src/config/emojis.ts b/src/config/emojis.ts
new file mode 100644
index 0000000..b7ed91a
--- /dev/null
+++ b/src/config/emojis.ts
@@ -0,0 +1,402 @@
+export default {
+    NUCLEUS: {
+        LOGO: "953040840945721385",
+        PREMIUMACTIVATE: "a1067536222764925068",
+        PREMIUM: "1067928702027042876",
+        LOADING: "a946346549271732234",
+        INFO: {
+            HELP: "751751467014029322",
+            ABOUT: "751762088346517504",
+            COMMANDS: "751762088229339136",
+            SUPPORT: "751762087780286495"
+        },
+        COMMANDS: {
+            RAID: "777143043711172608",
+            LOCK: "776848800995868682",
+            IGNORE: "777520659270074389"
+        }
+    },
+    ICONS: {
+        ADD: "826823514904330251",
+        REMOVE: "826823515268186152",
+        EDIT: "989911820267577366",
+        HISTORY: "989911933069168690",
+        FILTER: "990242059451514902",
+        ATTACHMENT: "997570687193587812",
+        LOGGING: "999613304446144562",
+        SAVE: "1065722246322200586",
+        REORDER: "1069323453909454890",
+        PUBLISH: "1081691380004421743",
+        NOTIFY: {
+            ON: "1000726394579464232",
+            OFF: "1078058136092541008"
+        },
+        OPP: {
+            ADD: "837355918831124500",
+            REMOVE: "837355918420869162"
+        },
+        CHANNEL: {
+            GUILD_TEXT: "990209996182679632",
+            GUILD_TEXT_NSFW: "990216363526221824",
+            GUILD_VOICE: "990213162697637969",
+            GUILD_VOICE_NSFW: "990216017244463124",
+            GUILD_STORE: "853668786925469706",
+            GUILD_NEWS: "853668786493063169",
+            GUILD_NEWS_NSFW: "990216028300673094",
+            GUILD_STAGE_VOICE: "853668786842763294",
+            THREAD_CHANNEL: "990210005108158514",
+            THREAD_PIPE: "990213168183779348",
+            RULES: "990213153080115250",
+            FORUM: "1061706437526552716",
+            CATEGORY: "1064943289708597348"
+        },
+        FLAGS: {
+            RED: "1082719687219101800",
+            YELLOW: "1082719684060794890",
+            GREEN: "1082719681326108763",
+            BLUE: "1082719679161843734",
+            PURPLE: "1082719686292156628",
+            GRAY: "1082719682492125337"
+        }
+    },
+    CONTROL: {
+        TICK: "947441964234702849",
+        REDTICK: "999612396727439370",
+        CROSS: "947441948543815720",
+        BLOCKCROSS: "952261738349330493",
+        BLOCKTICK: "991805475777695855",
+        LEFT: "947441951148486728",
+        RIGHT: "947441957473488916",
+        UP: "963409197293273108",
+        DOWN: "963409199549796352",
+        DOWNLOAD: "947959513032585236",
+        TICKET: "973253514488860683",
+        MENU: "976580327835320410",
+        PILL: {
+            TICK: "753314339082993832",
+            CROSS: "753314339389309100"
+        }
+    },
+    STATUS: {
+        ONLINE: "729064530084102166",
+        IDLE: "729064531577536582",
+        DND: "729064531057311886",
+        STREAMING: "729764055082074153",
+        OFFLINE: "729064531271221289"
+    },
+    CHANNEL: {
+        TEXT: {
+            CREATE: "729066924943737033",
+            EDIT: "951957316117360640",
+            DELETE: "729064529211686922"
+        },
+        VOICE: {
+            CREATE: "729064530830950530",
+            EDIT: "951957316071223336",
+            DELETE: "729064530981683200"
+        },
+        CATEGORY: {
+            CREATE: "787987508465238026",
+            EDIT: "787987508565770300",
+            DELETE: "787987508507967488"
+        },
+        PURGE: {
+            RED: "729064530797133875",
+            GREEN: "947443645391441940"
+        },
+        TITLEUPDATE: "729763053620691044",
+        TOPICUPDATE: "729763053477953536",
+        SLOWMODE: {
+            ON: "973616021304913950",
+            OFF: "777138171447869480"
+        },
+        NSFW: {
+            ON: "729064531208175736",
+            OFF: "729381430991388752"
+        }
+    },
+    MEMBER: {
+        JOIN: "729066519337762878",
+        LEAVE: "729064531170558575",
+        BOT: {
+            JOIN: "729064528666689587",
+            LEAVE: "729064528998039633"
+        },
+        KICK: "729263536785850458",
+        BAN: "729263536643112991",
+        UNBAN: "729263536840114216"
+    },
+    INVITE: {
+        CREATE: "729064529274601482",
+        DELETE: "729064531103580230"
+    },
+    WEBHOOK: {
+        CREATE: "752070251906203679",
+        UPDATE: "752073772823216191",
+        DELETE: "752070251948146768"
+    },
+    MESSAGE: {
+        CREATE: "751762088229339136",
+        EDIT: "729065958584614925",
+        DELETE: "729064530432360461",
+        PIN: "729064530755190894",
+        REACTION: {
+            ADD: "",
+            REMOVE: "",
+            CLEAR: "729064531468353606"
+        },
+        PING: {
+            MASS: "729620608408879124",
+            EVERYONE: "729064531073957909",
+            ROLE: "729263536915742770"
+        }
+    },
+    PUNISH: {
+        WARN: {
+            RED: "947433493384806430",
+            YELLOW: "729764054897524768",
+            GREEN: "947433504076091424"
+        },
+        KICK: {
+            RED: "729764053794422896",
+            YELLOW: "947429333289562132",
+            GREEN: "947428786692042764"
+        },
+        BAN: {
+            RED: "729764053861400637",
+            YELLOW: "729764053941223476",
+            GREEN: "947421674364629022"
+        },
+        UNBAN: {
+            RED: "972511610885255259",
+            YELLOW: "972511620343414794",
+            GREEN: "729263536840114216"
+        },
+        MUTE: {
+            RED: "947555098974883910",
+            YELLOW: "729764053865463840",
+            GREEN: "947555107980066866"
+        },
+        SOFTBAN: "729764053941223476",
+        VOICEMUTE: "729764054855450697",
+        CLEARHISTORY: "729764062270980096",
+        NICKNAME: {
+            RED: "959762533101731980",
+            YELLOW: "729064531019694090",
+            GREEN: "959762533072392202"
+        }
+    },
+    BADGES: {
+        NUCLEUSDEVELOPER: "957722888360853595",
+        CLICKSDEVELOPER: "957722888314683462",
+        BOT: "776375959108190239",
+        BOOSTER: "775783766131605545",
+        HypeSquadOnlineHouse1: "775783765930016789",
+        HypeSquadOnlineHouse2: "775783766152577095",
+        HypeSquadOnlineHouse3: "775783766303440937",
+        Hypesquad: "775783766194126908",
+        PremiumEarlySupporter: "775783766055452693",
+        BugHunterLevel1: "775783766252847154",
+        BugHunterLevel2: "775783766130950234",
+        Partner: "775783766178005033",
+        Staff: "775783766383788082",
+        VerifiedDeveloper: "775783766425600060",
+        Quarantined: "1059794708638994474",
+        Spammer: "1059794708638994474",
+        ActiveDeveloper: "1059795592966053918"
+    },
+    VOICE: {
+        CONNECT: "784785219391193138",
+        CHANGE: "784785219353968670",
+        LEAVE: "784785219432480808",
+        MUTE: "784785219613360149",
+        UNMUTE: "784785219441524766",
+        DEAFEN: "784785219424747550",
+        UNDEAFEN: "784785219324346378",
+        STREAM: {
+            START: "853519659775819787",
+            STOP: "853519660116213780"
+        },
+        VIDEO: {
+            START: "853519659945295873",
+            STOP: "853519660116738078"
+        }
+    },
+    SETTINGS: {
+        STATS: {
+            GREEN: "752214059159650396",
+            RED: "1065677252630675556"
+        }
+    },
+    GUILD: {
+        RED: "959779988264079361",
+        YELLOW: "729763053352124529",
+        GREEN: "959779988503154698",
+        EMOJI: {
+            CREATE: "953035168115982437",
+            EDIT: "729066518549233795",
+            DELETE: "953035210121953320"
+        },
+        SETTINGS: {
+            GREEN: "752570111063228507",
+            RED: "1068607393728049253"
+        },
+        ICONCHANGE: "729763053612302356",
+        TICKET: {
+            OPEN: "853245836331188264",
+            CLOSE: "853580122506133505",
+            ARCHIVED: "853580122636025856"
+        },
+        ROLES: {
+            CREATE: "729064530763579413",
+            DELETE: "729064530885476392",
+            EDIT: "776109664793919489",
+            MEMBERS: "752570111281594509",
+            MESSAGES: "752570111373606942",
+            VOICE: "752570111088525354"
+        }
+    },
+    MOD: {
+        IMAGES: {
+            SWEARING: "730438422627614810",
+            INVISIBLE: "730438422690398238",
+            TOOBIG: "730438422921084998",
+            TOOSMALL: "730438422921216150"
+        },
+        SWEARING: "730438422816096377",
+        SPAM: "730438422853845042"
+    },
+    NUMBERS: [
+        {
+            NORMAL: "753259024404840529",
+            GREEN: "753312608378945648",
+            RED: "753312608890650664"
+        },
+        {
+            NORMAL: "753259025990418515",
+            GREEN: "753312608550912112",
+            RED: "753312609075462246"
+        },
+        {
+            NORMAL: "753259024409034896",
+            GREEN: "753312608513294366",
+            RED: "753312608680935446"
+        },
+        {
+            NORMAL: "753259024358703205",
+            GREEN: "753312608815284426",
+            RED: "753312609377320966"
+        },
+        {
+            NORMAL: "753259024555835513",
+            GREEN: "753312608735461457",
+            RED: "753312609255686223"
+        },
+        {
+            NORMAL: "753259024744579283",
+            GREEN: "753312608630604017",
+            RED: "753312609138376777"
+        },
+        {
+            NORMAL: "753259024354639994",
+            GREEN: "753312608656031806",
+            RED: "753312609465270412"
+        },
+        {
+            NORMAL: "753259024530800661",
+            GREEN: "753312608718815322",
+            RED: "753312609104822313"
+        },
+        {
+            NORMAL: "753259024895574037",
+            GREEN: "753312608790249646",
+            RED: "753312609477984319"
+        },
+        {
+            NORMAL: "753259024681533553",
+            GREEN: "753312608899170365",
+            RED: "753312609557545089"
+        }
+    ],
+    BOTS: {
+        GPS: "878919163937185803",
+        NUCLEUS: "878919163597439016",
+        CLICKSFORMS: "878919163337388073",
+        CASTAWAY: "878919164255944726",
+        CMPING: "878919164125929502",
+        HOOKY: "878919164121731082"
+    },
+    CFSERVICE: {
+        VERIFIED: "881984571242053642",
+        UNVERIFIED: "881984571258847232"
+    },
+    TICKETS: {
+        SUPPORT: "952295894370369587",
+        REPORT: "952295894437482537",
+        QUESTION: "952295894403907645",
+        ISSUE: "952295894412316672",
+        SUGGESTION: "952295894399725588",
+        OTHER: "952295894445883502"
+    },
+    TRACKS: {
+        ICON: "963170616444334171",
+        HORIZONTAL: {
+            LEFT: {
+                ACTIVE: "963121920038035506",
+                INACTIVE: "963121944239153242"
+            },
+            MIDDLE: {
+                ACTIVE: "963121925893263420",
+                INACTIVE: "963121949796597870"
+            },
+            RIGHT: {
+                ACTIVE: "963121933384302602",
+                INACTIVE: "963121956125831168"
+            }
+        },
+        VERTICAL: {
+            TOP: {
+                ACTIVE: "963122664648630293",
+                INACTIVE: "963122659862917140",
+                GRAY: {
+                    ACTIVE: "963123505052934144",
+                    INACTIVE: "963123495221469194"
+                }
+            },
+            MIDDLE: {
+                ACTIVE: "963122679332880384",
+                INACTIVE: "963122673246937199",
+                GRAY: {
+                    ACTIVE: "963123517702955018",
+                    INACTIVE: "963123511927390329"
+                }
+            },
+            BOTTOM: {
+                ACTIVE: "963122691752218624",
+                INACTIVE: "963122685691453552",
+                GRAY: {
+                    ACTIVE: "963123529988059187",
+                    INACTIVE: "963123523742748742"
+                }
+            }
+        },
+        SINGLE: {
+            ACTIVE: "963361162215424060",
+            INACTIVE: "963361431758176316",
+            GRAY: {
+                ACTIVE: "963361204695334943",
+                INACTIVE: "963361200828198952"
+            }
+        }
+    },
+    COLORS: {
+        RED: "875822912802803754",
+        ORANGE: "875822913104785418",
+        YELLOW: "875822913079611402",
+        GREEN: "875822913213841418",
+        BLUE: "875822912777637889",
+        PURPLE: "875822913213841419",
+        PINK: "875822913088020541",
+        GRAY: "875822913117368340"
+    }
+}
diff --git a/src/config/format.ts b/src/config/format.ts
index 0560796..042d173 100644
--- a/src/config/format.ts
+++ b/src/config/format.ts
@@ -1,7 +1,7 @@
 import fs from "fs";
 import * as readLine from "node:readline/promises";
 
-const defaultDict: Record<string, string | string[] | boolean | Record<string, string>> = {
+const defaultDict: Record<string, string | string[] | boolean | Record<string, string | number | undefined>> = {
     developmentToken: "Your development bot token (Used for testing in one server, rather than production)",
     developmentGuildID: "Your development guild ID",
     enableDevelopment: true,
@@ -26,10 +26,16 @@
         authSource: ""
     },
     baseUrl: "Your website where buttons such as Verify and Role menu will link to, e.g. https://example.com/",
-    pastebinApiKey: "An API key for pastebin (optional)",
-    pastebinUsername: "Your pastebin username (optional)",
-    pastebinPassword: "Your pastebin password (optional)",
-    rapidApiKey: "Your RapidAPI key (optional), used for Unscan"
+    clamAVSocket: "Your ClamAV socket file (optional)",
+    clamAVHost: "Your ClamAV host (optional)",
+    clamAVPort: "Your ClamAV port (optional)",
+    clamav: {
+        socket: "",
+        host: "",
+        port: 0
+    },
+    githubPAT: "Your GitHub Personal Access Token (optional)",
+    suggestionChannel: "Your suggestion channel ID (optional)"
 };
 
 const readline = readLine.createInterface({
@@ -111,6 +117,9 @@
                     case "mongoOptions": {
                         break;
                     }
+                    case "clamav": {
+                        break;
+                    }
                     default: {
                         json[key] = await getInput(`\x1b[36m${key} \x1b[0m(\x1b[35m${defaultDict[key]}\x1b[0m) > `);
                     }
@@ -122,22 +131,9 @@
     }
     if (walkthrough && !(json["mongoUrl"] ?? false)) json["mongoUrl"] = "mongodb://127.0.0.1:27017";
     if (!((json["baseUrl"] as string | undefined) ?? "").endsWith("/")) (json["baseUrl"] as string) += "/";
-    let hosts;
-    try {
-        hosts = fs.readFileSync("/etc/hosts", "utf8").toString().split("\n");
-    } catch (e) {
-        return console.log(
-            "\x1b[31m⚠ No /etc/hosts found. Please ensure the file exists and is readable. (Windows is not supported, Mac and Linux users should not experience this error)"
-        );
-    }
-    let localhost: string | undefined = hosts.find((line) => line.split(" ")[1] === "localhost");
-    if (localhost) {
-        localhost = localhost.split(" ")[0];
-    } else {
-        localhost = "127.0.0.1";
-    }
-    json["mongoUrl"] = (json["mongoUrl"]! as string).replace("localhost", localhost!);
-    json["baseUrl"] = (json["baseUrl"]! as string).replace("localhost", localhost!);
+    const localhost = "127.0.0.1";
+    json["mongoUrl"] = (json["mongoUrl"]! as string).replace("localhost", localhost);
+    json["baseUrl"] = (json["baseUrl"]! as string).replace("localhost", localhost);
     json["mongoOptions"] = {
         username: json["username"] as string,
         password: json["password"] as string,
@@ -145,6 +141,11 @@
         host: json["host"] as string,
         authSource: json["authSource"] as string
     };
+    json["clamav"] = {
+        socket: json["clamAVSocket"] as string | undefined,
+        host: json["clamAVHost"] as string | undefined,
+        port: json["clamAVPort"] as number | undefined
+    };
 
     fs.writeFileSync("./src/config/main.ts", "export default " + JSON.stringify(json, null, 4) + ";");
 
diff --git a/src/config/main.d.ts b/src/config/main.d.ts
index 99c460d..6c610e0 100644
--- a/src/config/main.d.ts
+++ b/src/config/main.d.ts
@@ -18,7 +18,13 @@
         authSource: string;
     };
     baseUrl: string;
-    rapidApiKey: string;
+    clamav: {
+        socket?: string;
+        host?: string;
+        port?: number;
+    };
+    githubPAT: string;
+    suggestionChannel: string;
 };
 
 export default config;
diff --git a/src/context/messages/purgeto.ts b/src/context/messages/purgeto.ts
index 4f0ea1e..a75a281 100644
--- a/src/context/messages/purgeto.ts
+++ b/src/context/messages/purgeto.ts
@@ -19,14 +19,14 @@
 async function waitForButton(m: Discord.Message, member: Discord.GuildMember): Promise<boolean> {
     let component;
     try {
-        component = m.awaitMessageComponent({
+        component = await m.awaitMessageComponent({
             time: 200000,
             filter: (i) => i.user.id === member.id && i.channel!.id === m.channel.id && i.message.id === m.id
         });
     } catch (e) {
         return false;
     }
-    (await component).deferUpdate();
+    await component.deferUpdate();
     return true;
 }
 
@@ -210,7 +210,7 @@
             guild: interaction.guild!.id
         }
     };
-    log(data);
+    await log(data);
     const messages: Message[] = deleted
         .map((m) => m)
         .filter((m) => m instanceof Message)
diff --git a/src/context/users/userinfo.ts b/src/context/users/userinfo.ts
index 7a75754..9c7433f 100644
--- a/src/context/users/userinfo.ts
+++ b/src/context/users/userinfo.ts
@@ -4,7 +4,6 @@
 const command = new ContextMenuCommandBuilder().setName("User info");
 
 const callback = async (interaction: UserContextMenuCommandInteraction) => {
-    console.log("callback");
     const guild = interaction.guild!;
     let member = interaction.targetMember;
     if (!member) member = await guild.members.fetch(interaction.targetId);
@@ -12,7 +11,6 @@
 };
 
 const check = async (_interaction: UserContextMenuCommandInteraction) => {
-    console.log("check");
     return true;
 };
 
diff --git a/src/events/channelCreate.ts b/src/events/channelCreate.ts
index 90a7f6d..8fd6b35 100644
--- a/src/events/channelCreate.ts
+++ b/src/events/channelCreate.ts
@@ -81,5 +81,5 @@
             guild: channel.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/channelDelete.ts b/src/events/channelDelete.ts
index 8dffd38..b79c2da 100644
--- a/src/events/channelDelete.ts
+++ b/src/events/channelDelete.ts
@@ -123,5 +123,5 @@
             guild: channel.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/channelUpdate.ts b/src/events/channelUpdate.ts
index 6491cc9..adfe87f 100644
--- a/src/events/channelUpdate.ts
+++ b/src/events/channelUpdate.ts
@@ -301,5 +301,5 @@
             guild: newChannel.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/emojiCreate.ts b/src/events/emojiCreate.ts
index 96f7909..873defa 100644
--- a/src/events/emojiCreate.ts
+++ b/src/events/emojiCreate.ts
@@ -30,5 +30,5 @@
             guild: emoji.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/emojiDelete.ts b/src/events/emojiDelete.ts
index 52822cb..21ade1d 100644
--- a/src/events/emojiDelete.ts
+++ b/src/events/emojiDelete.ts
@@ -31,5 +31,5 @@
             guild: emoji.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/emojiUpdate.ts b/src/events/emojiUpdate.ts
index 173f5c5..236a799 100644
--- a/src/events/emojiUpdate.ts
+++ b/src/events/emojiUpdate.ts
@@ -37,5 +37,5 @@
             guild: newEmoji.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/guildBanAdd.ts b/src/events/guildBanAdd.ts
index 6036ddf..c8f3446 100644
--- a/src/events/guildBanAdd.ts
+++ b/src/events/guildBanAdd.ts
@@ -9,7 +9,7 @@
 export async function callback(client: NucleusClient, ban: GuildBan) {
     const { log, isLogging, NucleusColors, entry, renderUser, renderDelta, getAuditLog } = client.logger;
     await statsChannelRemove(ban.user, ban.guild);
-    purgeByUser(ban.user.id, ban.guild.id);
+    await purgeByUser(ban.user.id, ban.guild.id);
     if (!(await isLogging(ban.guild.id, "guildMemberPunish"))) return;
     const auditLog: GuildAuditLogsEntry | undefined = (await getAuditLog(ban.guild, AuditLogEvent.MemberBanAdd)).filter(
         (entry: GuildAuditLogsEntry) => (entry.target! as User).id === ban.user.id
@@ -39,5 +39,5 @@
             guild: ban.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/guildBanRemove.ts b/src/events/guildBanRemove.ts
index fc916ba..64d9de3 100644
--- a/src/events/guildBanRemove.ts
+++ b/src/events/guildBanRemove.ts
@@ -33,5 +33,5 @@
             guild: ban.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/guildCreate.ts b/src/events/guildCreate.ts
index ff6c6b2..f5e43a9 100644
--- a/src/events/guildCreate.ts
+++ b/src/events/guildCreate.ts
@@ -5,5 +5,5 @@
 export const event = "guildCreate";
 
 export async function callback(_client: NucleusClient, guild: Guild) {
-    guide(guild);
+    await guide(guild);
 }
diff --git a/src/events/guildMemberUpdate.ts b/src/events/guildMemberUpdate.ts
index 34a52b8..4e512ee 100644
--- a/src/events/guildMemberUpdate.ts
+++ b/src/events/guildMemberUpdate.ts
@@ -12,6 +12,8 @@
         await client.database.premium.checkAllPremium(after);
     }
 
+    if (before.displayAvatarURL({ forceStatic: true }) !== after.displayAvatarURL({ forceStatic: true }))
+        await doMemberChecks(after);
     if (!before.roles.cache.equals(after.roles.cache)) {
         const auditLog = (await getAuditLog(after.guild, AuditLogEvent.MemberRoleUpdate)).filter(
             (entry: GuildAuditLogsEntry) => (entry.target as GuildMember)!.id === after.id
@@ -84,7 +86,7 @@
                 });
             }
             data = Object.assign(data, { list: list });
-            log(data);
+            await log(data);
         }
     }
     const auditLog = (await getAuditLog(after.guild, AuditLogEvent.MemberUpdate)).filter(
@@ -93,7 +95,7 @@
     if (!auditLog) return;
     if (auditLog.executor!.id === client.user!.id) return;
     if (before.nickname !== after.nickname) {
-        doMemberChecks(after, after.guild);
+        await doMemberChecks(after);
         await client.database.history.create(
             "nickname",
             after.guild.id,
@@ -123,7 +125,7 @@
                 guild: after.guild.id
             }
         };
-        log(data);
+        await log(data);
     }
     if (
         (before.communicationDisabledUntilTimestamp ?? 0) < Date.now() &&
@@ -163,12 +165,16 @@
                 guild: after.guild.id
             }
         };
-        log(data);
-        client.database.eventScheduler.schedule("naturalUnmute", after.communicationDisabledUntil?.toISOString()!, {
-            guild: after.guild.id,
-            user: after.id,
-            expires: after.communicationDisabledUntilTimestamp
-        });
+        await log(data);
+        await client.database.eventScheduler.schedule(
+            "naturalUnmute",
+            after.communicationDisabledUntil?.toISOString()!,
+            {
+                guild: after.guild.id,
+                user: after.id,
+                expires: after.communicationDisabledUntilTimestamp
+            }
+        );
     }
     if (
         after.communicationDisabledUntil === null &&
@@ -204,8 +210,8 @@
                 guild: after.guild.id
             }
         };
-        log(data);
-        client.database.eventScheduler.cancel("naturalUnmute", {
+        await log(data);
+        await client.database.eventScheduler.cancel("naturalUnmute", {
             guild: after.guild.id,
             user: after.id,
             expires: before.communicationDisabledUntilTimestamp
diff --git a/src/events/guildUpdate.ts b/src/events/guildUpdate.ts
index c48c82f..27c609d 100644
--- a/src/events/guildUpdate.ts
+++ b/src/events/guildUpdate.ts
@@ -93,5 +93,5 @@
             guild: after.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/interactionCreate.ts b/src/events/interactionCreate.ts
index 3b0cd62..9d3dceb 100644
--- a/src/events/interactionCreate.ts
+++ b/src/events/interactionCreate.ts
@@ -4,8 +4,18 @@
 import close from "../actions/tickets/delete.js";
 import createTranscript from "../premium/createTranscript.js";
 
-import type { ButtonInteraction, Interaction } from "discord.js";
-import type Discord from "discord.js";
+import {
+    ActionRowBuilder,
+    ButtonBuilder,
+    ButtonInteraction,
+    ButtonStyle,
+    Interaction,
+    InteractionEditReplyOptions,
+    ModalBuilder,
+    ModalSubmitInteraction,
+    TextInputBuilder,
+    TextInputStyle
+} from "discord.js";
 import type { NucleusClient } from "../utils/client.js";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 
@@ -14,6 +24,7 @@
 import { callback as muteCallback, check as muteCheck } from "../commands/mod/mute.js";
 import { callback as nicknameCallback, check as nicknameCheck } from "../commands/mod/nick.js";
 import { callback as warnCallback, check as warnCheck } from "../commands/mod/warn.js";
+import client from "../utils/client.js";
 
 export const event = "interactionCreate";
 
@@ -27,6 +38,13 @@
 
 async function interactionCreate(interaction: Interaction) {
     if (interaction.isButton()) {
+        if (interaction.customId.endsWith(":Suggestion")) {
+            const value =
+                interaction.customId.startsWith("accept") || interaction.customId.startsWith("implement")
+                    ? true
+                    : false;
+            return await modifySuggestion(interaction, value);
+        }
         switch (interaction.customId) {
             case "rolemenu": {
                 return await roleMenu(interaction);
@@ -43,12 +61,6 @@
             case "createtranscript": {
                 return await createTranscript(interaction);
             }
-            case "suggestionAccept": {
-                return await modifySuggestion(interaction, true);
-            }
-            case "suggestionDeny": {
-                return await modifySuggestion(interaction, false);
-            }
         }
         // Mod actions
         if (interaction.customId.startsWith("mod:")) {
@@ -57,27 +69,27 @@
             const member = await interaction.guild?.members.fetch(memberId!);
             switch (action) {
                 case "kick": {
-                    const check = await kickCheck(interaction, false, member);
+                    const check = kickCheck(interaction, false, member);
                     if (check !== true) return await errorMessage(interaction, check!);
                     return await kickCallback(interaction, member);
                 }
                 case "ban": {
-                    const check = await banCheck(interaction, false, member);
+                    const check = banCheck(interaction, false, member);
                     if (check !== true) return await errorMessage(interaction, check!);
                     return await banCallback(interaction, member);
                 }
                 case "mute": {
-                    const check = await muteCheck(interaction, false, member);
+                    const check = muteCheck(interaction, false, member);
                     if (check !== true) return await errorMessage(interaction, check!);
                     return await muteCallback(interaction, member);
                 }
                 case "nickname": {
-                    const check = await nicknameCheck(interaction, false, member);
+                    const check = nicknameCheck(interaction, false, member);
                     if (check !== true) return await errorMessage(interaction, check || "Something went wrong");
                     return await nicknameCallback(interaction, member);
                 }
                 case "warn": {
-                    const check = await warnCheck(interaction, false, member);
+                    const check = warnCheck(interaction, false, member);
                     if (check !== true) return await errorMessage(interaction, check!);
                     return await warnCallback(interaction, member);
                 }
@@ -86,24 +98,138 @@
     }
 }
 
-async function modifySuggestion(interaction: Discord.MessageComponentInteraction, accept: boolean) {
-    const message = await interaction.message;
+const getReason = async (buttonInteraction: ButtonInteraction, prompt: string) => {
+    const modal = new ModalBuilder()
+        .addComponents(
+            new ActionRowBuilder<TextInputBuilder>().addComponents(
+                new TextInputBuilder().setStyle(TextInputStyle.Paragraph).setLabel(prompt).setCustomId("typed")
+            )
+        )
+        .setTitle("Reason")
+        .setCustomId("modal");
+    await buttonInteraction.showModal(modal);
+    let out: ModalSubmitInteraction;
+    try {
+        out = await buttonInteraction.awaitModalSubmit({
+            filter: (i) => i.customId === "modal" && i.user.id === buttonInteraction.user.id,
+            time: 300000
+        });
+    } catch {
+        return null;
+    }
+    await out.deferUpdate();
+    return out.fields.getTextInputValue("typed");
+};
+
+async function modifySuggestion(interaction: ButtonInteraction, accept: boolean) {
+    const message = interaction.message;
     await message.fetch();
     if (message.embeds.length === 0) return;
-    const embed = message.embeds[0];
-    const newcolor = accept ? "Success" : "Danger";
-    const footer = {
-        text: `Suggestion ${accept ? "accepted" : "denied"} by ${interaction.user.tag}`,
-        iconURL: interaction.user.displayAvatarURL()
+    const embed = message.embeds[0]!;
+    const issueNum = embed.footer!.text;
+    if (!issueNum) return;
+    const issue = {
+        owner: "ClicksMinutePer",
+        repo: "Nucleus",
+        issue_number: parseInt(issueNum)
     };
+    let name = "Unknown";
+    const components: InteractionEditReplyOptions["components"] = [];
+    switch (interaction.customId) {
+        case "accept:Suggestion": {
+            name = "Accepted";
+            await interaction.deferUpdate();
+            await client.GitHub.rest.issues.createComment({
+                ...issue,
+                body: "Suggestion accepted by " + interaction.user.tag
+            });
+            components.push(
+                new ActionRowBuilder<ButtonBuilder>().addComponents(
+                    new ButtonBuilder()
+                        .setCustomId("close:Suggestion")
+                        .setLabel("Close")
+                        .setStyle(ButtonStyle.Secondary),
+                    new ButtonBuilder()
+                        .setCustomId("implemented:Suggestion")
+                        .setLabel("Implemented")
+                        .setStyle(ButtonStyle.Secondary)
+                )
+            );
+            break;
+        }
+        case "deny:Suggestion": {
+            name = "Denied";
+            const reason = await getReason(interaction, "Reason for denial");
+            await client.GitHub.rest.issues.createComment({
+                ...issue,
+                body: "Suggestion denied by " + interaction.user.tag + " for reason:\n>" + reason
+            });
+            await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "not_planned" });
+            // await client.GitHub.rest.issues.lock({...issue, lock_reason: "resolved"})
+            components.push(
+                new ActionRowBuilder<ButtonBuilder>().addComponents(
+                    new ButtonBuilder().setCustomId("lock:Suggestion").setLabel("Lock").setStyle(ButtonStyle.Danger)
+                )
+            );
+            break;
+        }
+        case "close:Suggestion": {
+            name = "Closed";
+            const reason = await getReason(interaction, "Reason for closing");
+            await client.GitHub.rest.issues.createComment({
+                ...issue,
+                body: "Suggestion closed by " + interaction.user.tag + " for reason:\n>" + reason
+            });
+            await client.GitHub.rest.issues.update({ ...issue, state: "closed" });
+            // await client.GitHub.rest.issues.lock({...issue})
+            components.push(
+                new ActionRowBuilder<ButtonBuilder>().addComponents(
+                    new ButtonBuilder().setCustomId("lock:Suggestion").setLabel("Lock").setStyle(ButtonStyle.Danger)
+                )
+            );
+            break;
+        }
+        case "implement:Suggestion": {
+            name = "Implemented";
+            await interaction.deferUpdate();
+            await client.GitHub.rest.issues.createComment({ ...issue, body: "Suggestion implemented" });
+            await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "completed" });
+            await client.GitHub.rest.issues.lock({ ...issue, lock_reason: "resolved" });
+            break;
+        }
+        case "lock:Suggestion": {
+            name = "Locked";
+            await interaction.deferUpdate();
+            await client.GitHub.rest.issues.lock({ ...issue });
+            break;
+        }
+        case "spam:Suggestion": {
+            name = "Marked as Spam";
+            await interaction.deferUpdate();
+            await client.GitHub.rest.issues.update({ ...issue, state: "closed", state_reason: "not_planned" });
+            await client.GitHub.rest.issues.lock({ ...issue, lock_reason: "spam" });
+            break;
+        }
+    }
+
+    const newcolor = accept ? "Success" : "Danger";
+    const newEmoji = accept ? "ICONS.ADD" : "ICONS.OPP.ADD";
 
     const newEmbed = new EmojiEmbed()
-        .setTitle(embed!.title!)
+        .setEmoji(newEmoji)
+        .setTitle(embed!.title!.replace(/.+> /, ""))
         .setDescription(embed!.description!)
-        .setFooter(footer)
-        .setStatus(newcolor);
+        .setFields({
+            name: name + " by",
+            value: interaction.user.tag
+        })
+        .setStatus(newcolor)
+        .setFooter(embed!.footer);
 
-    await interaction.update({ embeds: [newEmbed], components: [] });
+    await interaction.editReply({
+        embeds: [newEmbed],
+        components: components
+    });
 }
 
 export async function callback(_client: NucleusClient, interaction: Interaction) {
diff --git a/src/events/inviteCreate.ts b/src/events/inviteCreate.ts
index 240965c..6e28d95 100644
--- a/src/events/inviteCreate.ts
+++ b/src/events/inviteCreate.ts
@@ -33,5 +33,5 @@
             guild: invite.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/inviteDelete.ts b/src/events/inviteDelete.ts
index 81285c7..89bd226 100644
--- a/src/events/inviteDelete.ts
+++ b/src/events/inviteDelete.ts
@@ -33,5 +33,5 @@
             guild: invite.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/memberJoin.ts b/src/events/memberJoin.ts
index 66abe28..55f9ba8 100644
--- a/src/events/memberJoin.ts
+++ b/src/events/memberJoin.ts
@@ -7,9 +7,9 @@
 export const event = "guildMemberAdd";
 
 export async function callback(client: NucleusClient, member: GuildMember) {
-    welcome(member);
-    statsChannelAdd(member.user, member.guild);
-    doMemberChecks(member, member.guild);
+    await welcome(member);
+    await statsChannelAdd(member.user, member.guild);
+    await doMemberChecks(member);
     const { log, isLogging, NucleusColors, entry, renderUser, renderDelta } = client.logger;
     if (!(await isLogging(member.guild.id, "guildMemberUpdate"))) return;
     await client.database.history.create("join", member.guild.id, member.user, null, null);
@@ -33,5 +33,5 @@
             guild: member.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/memberLeave.ts b/src/events/memberLeave.ts
index e80ea0b..1ca50c6 100644
--- a/src/events/memberLeave.ts
+++ b/src/events/memberLeave.ts
@@ -8,7 +8,7 @@
 
 export async function callback(client: NucleusClient, member: GuildMember) {
     const startTime = Date.now() - 10 * 1000;
-    purgeByUser(member.id, member.guild.id);
+    await purgeByUser(member.id, member.guild.id);
     await statsChannelRemove(member.user, member.guild);
     const { getAuditLog, isLogging, log, NucleusColors, entry, renderUser, renderDelta } = client.logger;
     if (!(await isLogging(member.guild.id, "guildMemberUpdate"))) return;
@@ -95,5 +95,5 @@
             }
         };
     }
-    log(data);
+    await log(data);
 }
diff --git a/src/events/messageCreate.ts b/src/events/messageCreate.ts
index 0281fa1..cc69bf0 100644
--- a/src/events/messageCreate.ts
+++ b/src/events/messageCreate.ts
@@ -23,7 +23,11 @@
         if (message.channel.permissionsFor(message.guild.members.me!)!.has("ManageMessages")) {
             await message.crosspost();
         } else {
-            singleNotify(`Nucleus does not have Manage Messages in <#${message.channel.id}>`, message.guild.id, true);
+            await singleNotify(
+                `Nucleus does not have Manage Messages in <#${message.channel.id}>`,
+                message.guild.id,
+                true
+            );
         }
     }
 
@@ -71,7 +75,7 @@
         if (!config.filters.invite.allowed.channels.includes(message.channel.id)) {
             if (/(?:https?:\/\/)?discord(?:app)?\.(?:com\/invite|gg)\/[a-zA-Z0-9]+\/?/.test(content)) {
                 messageException(message.guild.id, message.channel.id, message.id);
-                message.delete();
+                await message.delete();
                 const data = {
                     meta: {
                         type: "messageDelete",
@@ -101,42 +105,42 @@
         for (const element of fileNames.files) {
             const url = element.url ? element.url : element.local;
             if (
-                /\.(j(pe?g|fif)|a?png|gifv?|w(eb[mp]|av)|mp([34]|eg-\d)|ogg|avi|h\.26(4|5)|cda)$/.test(
+                /\.(jpg|jpeg|png|apng|gif|gifv|webm|webp|mp4|wav|mp3|ogg|jfif|mpeg-\d|avi|h\.264|h\.265)$/.test(
                     url.toLowerCase()
                 )
             ) {
-                // jpg|jpeg|png|apng|gif|gifv|webm|webp|mp4|wav|mp3|ogg|jfif|MPEG-#|avi|h.264|h.265
+                // j(pe?g|fif)|a?png|gifv?|w(eb[mp]|av)|mp([34]|eg-\d)|ogg|avi|h\.26(4|5)
+                // ^no
                 if (
                     config.filters.images.NSFW &&
-                    !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw)
+                    !(message.channel instanceof ThreadChannel ? message.channel.parent?.nsfw : message.channel.nsfw) &&
+                    (await NSFWCheck(element.url))
                 ) {
-                    if (await NSFWCheck(url)) {
-                        messageException(message.guild.id, message.channel.id, message.id);
-                        await message.delete();
-                        const data = {
-                            meta: {
-                                type: "messageDelete",
-                                displayName: "Message Deleted",
-                                calculateType: "autoModeratorDeleted",
-                                color: NucleusColors.red,
-                                emoji: "MESSAGE.DELETE",
-                                timestamp: Date.now()
-                            },
-                            separate: {
-                                start:
-                                    filter +
-                                    " Image detected as NSFW\n\n" +
-                                    (content
-                                        ? `**Message:**\n\`\`\`${content}\`\`\``
-                                        : "**Message:** *Message had no content*")
-                            },
-                            list: list,
-                            hidden: {
-                                guild: message.channel.guild.id
-                            }
-                        };
-                        return log(data);
-                    }
+                    messageException(message.guild.id, message.channel.id, message.id);
+                    await message.delete();
+                    const data = {
+                        meta: {
+                            type: "messageDelete",
+                            displayName: "Message Deleted",
+                            calculateType: "autoModeratorDeleted",
+                            color: NucleusColors.red,
+                            emoji: "MESSAGE.DELETE",
+                            timestamp: Date.now()
+                        },
+                        separate: {
+                            start:
+                                filter +
+                                " Image detected as NSFW\n\n" +
+                                (content
+                                    ? `**Message:**\n\`\`\`${content}\`\`\``
+                                    : "**Message:** *Message had no content*")
+                        },
+                        list: list,
+                        hidden: {
+                            guild: message.channel.guild.id
+                        }
+                    };
+                    return log(data);
                 }
                 if (config.filters.wordFilter.enabled) {
                     const text = await TestImage(url);
@@ -205,34 +209,30 @@
                     }
                 }
             }
-            if (config.filters.malware) {
-                if (!(await MalwareCheck(url))) {
-                    messageException(message.guild.id, message.channel.id, message.id);
-                    await message.delete();
-                    const data = {
-                        meta: {
-                            type: "messageDelete",
-                            displayName: "Message Deleted",
-                            calculateType: "autoModeratorDeleted",
-                            color: NucleusColors.red,
-                            emoji: "MESSAGE.DELETE",
-                            timestamp: Date.now()
-                        },
-                        separate: {
-                            start:
-                                filter +
-                                " File detected as malware\n\n" +
-                                (content
-                                    ? `**Message:**\n\`\`\`${content}\`\`\``
-                                    : "**Message:** *Message had no content*")
-                        },
-                        list: list,
-                        hidden: {
-                            guild: message.channel.guild.id
-                        }
-                    };
-                    return log(data);
-                }
+            if (config.filters.malware && (await MalwareCheck(url))) {
+                messageException(message.guild.id, message.channel.id, message.id);
+                await message.delete();
+                const data = {
+                    meta: {
+                        type: "messageDelete",
+                        displayName: "Message Deleted",
+                        calculateType: "autoModeratorDeleted",
+                        color: NucleusColors.red,
+                        emoji: "MESSAGE.DELETE",
+                        timestamp: Date.now()
+                    },
+                    separate: {
+                        start:
+                            filter +
+                            " File detected as malware\n\n" +
+                            (content ? `**Message:**\n\`\`\`${content}\`\`\`` : "**Message:** *Message had no content*")
+                    },
+                    list: list,
+                    hidden: {
+                        guild: message.channel.guild.id
+                    }
+                };
+                return log(data);
             }
         }
     }
diff --git a/src/events/messageDelete.ts b/src/events/messageDelete.ts
index c29bfd0..b847400 100644
--- a/src/events/messageDelete.ts
+++ b/src/events/messageDelete.ts
@@ -68,5 +68,5 @@
             guild: message.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/messageEdit.ts b/src/events/messageEdit.ts
index b743147..270da00 100644
--- a/src/events/messageEdit.ts
+++ b/src/events/messageEdit.ts
@@ -103,5 +103,5 @@
             guild: newMessage.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/roleCreate.ts b/src/events/roleCreate.ts
index 9b900f8..ea85b4d 100644
--- a/src/events/roleCreate.ts
+++ b/src/events/roleCreate.ts
@@ -30,5 +30,5 @@
             guild: role.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/roleDelete.ts b/src/events/roleDelete.ts
index e83d557..1802518 100644
--- a/src/events/roleDelete.ts
+++ b/src/events/roleDelete.ts
@@ -42,5 +42,5 @@
             guild: role.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/roleUpdate.ts b/src/events/roleUpdate.ts
index 236bc0f..c15cf01 100644
--- a/src/events/roleUpdate.ts
+++ b/src/events/roleUpdate.ts
@@ -74,5 +74,5 @@
             guild: newRole.guild.id
         }
     }; // TODO: make our own page for this
-    log(data);
+    await log(data);
 }
diff --git a/src/events/stickerCreate.ts b/src/events/stickerCreate.ts
index 01944fc..bc8adb8 100644
--- a/src/events/stickerCreate.ts
+++ b/src/events/stickerCreate.ts
@@ -32,5 +32,5 @@
             guild: sticker.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/stickerDelete.ts b/src/events/stickerDelete.ts
index a348b73..7704c49 100644
--- a/src/events/stickerDelete.ts
+++ b/src/events/stickerDelete.ts
@@ -30,5 +30,5 @@
             guild: sticker.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/stickerUpdate.ts b/src/events/stickerUpdate.ts
index c42f775..4be1a3d 100644
--- a/src/events/stickerUpdate.ts
+++ b/src/events/stickerUpdate.ts
@@ -35,5 +35,5 @@
             guild: newSticker.guild!.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/threadCreate.ts b/src/events/threadCreate.ts
index cefaf3b..42cda47 100644
--- a/src/events/threadCreate.ts
+++ b/src/events/threadCreate.ts
@@ -44,5 +44,5 @@
             guild: thread.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/threadDelete.ts b/src/events/threadDelete.ts
index ecbf4cf..fba6592 100644
--- a/src/events/threadDelete.ts
+++ b/src/events/threadDelete.ts
@@ -46,5 +46,5 @@
             guild: thread.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/threadUpdate.ts b/src/events/threadUpdate.ts
index 510ec30..e28abf1 100644
--- a/src/events/threadUpdate.ts
+++ b/src/events/threadUpdate.ts
@@ -55,5 +55,5 @@
             guild: newThread.guild.id
         }
     };
-    log(data);
+    await log(data);
 }
diff --git a/src/events/webhookUpdate.ts b/src/events/webhookUpdate.ts
index 438c66e..c4a4efb 100644
--- a/src/events/webhookUpdate.ts
+++ b/src/events/webhookUpdate.ts
@@ -130,7 +130,7 @@
                 guild: channel.guild.id
             }
         };
-        log(data);
+        await log(data);
     } catch (e) {
         console.log(e);
     }
diff --git a/src/index.ts b/src/index.ts
index 50a1526..b3883a1 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -8,7 +8,7 @@
 
 client.on("ready", async () => {
     console.log(`Logged in as ${client.user!.tag}!`);
-    register();
+    await register();
     runServer(client);
     if (config.enableDevelopment) {
         client.fetchedCommands = await client.guilds.cache.get(config.developmentGuildID)?.commands.fetch()!;
diff --git a/src/premium/attachmentLogs.ts b/src/premium/attachmentLogs.ts
index e719f22..9bb216d 100644
--- a/src/premium/attachmentLogs.ts
+++ b/src/premium/attachmentLogs.ts
@@ -36,7 +36,7 @@
     if (await client.database.premium.hasPremium(message.guild.id)) {
         const channel = (await client.database.guilds.read(message.guild.id)).logging.attachments.channel;
         if (!channel) {
-            singleNotify(
+            await singleNotify(
                 "noAttachmentLogChannel",
                 message.guild.id,
                 `No channel set for attachment logging. You can set one with ${getCommandMentionByName(
@@ -48,7 +48,7 @@
         }
         const channelObj = await message.guild.channels.fetch(channel);
         if (!channelObj) {
-            singleNotify(
+            await singleNotify(
                 "attachmentLogChannelDeleted",
                 message.guild.id,
                 `Your attachment history channel was deleted or is not longer accessible. You can set a new one with ${getCommandMentionByName(
@@ -75,7 +75,7 @@
             ],
             files: attachments.map((file) => file.local)
         });
-        client.database.guilds.write(message.guild.id, {
+        await client.database.guilds.write(message.guild.id, {
             [`logging.attachments.saved.${message.channel.id}${message.id}`]: m.url
         });
         return { files: attachments, jump: m.url };
diff --git a/src/premium/createTranscript.ts b/src/premium/createTranscript.ts
index 7a1f57f..fa1f7a4 100644
--- a/src/premium/createTranscript.ts
+++ b/src/premium/createTranscript.ts
@@ -134,7 +134,7 @@
             guild: interaction.guild!.id
         }
     };
-    log(data);
+    await log(data);
     await interaction.channel.delete();
     return;
 }
diff --git a/src/reflex/guide.ts b/src/reflex/guide.ts
index 1901d34..59c12c7 100644
--- a/src/reflex/guide.ts
+++ b/src/reflex/guide.ts
@@ -353,12 +353,12 @@
             const em = new Discord.EmbedBuilder(pages[page]!.embed);
             em.setDescription(em.data.description + "\n\n" + createPageIndicator(pages.length, page));
             em.setFooter({ text: "Message closed" });
-            interaction.editReply({
+            await interaction.editReply({
                 embeds: [em],
                 components: []
             });
         } else {
-            m.delete();
+            await m.delete();
         }
     }
 };
diff --git a/src/reflex/nsfwjs b/src/reflex/nsfwjs
new file mode 160000
index 0000000..f482648
--- /dev/null
+++ b/src/reflex/nsfwjs
@@ -0,0 +1 @@
+Subproject commit f48264888bc1b2a805e4b20a5e5c82e11cb4754a
diff --git a/src/reflex/scanners.ts b/src/reflex/scanners.ts
index 53c8c9b..6d3fc71 100644
--- a/src/reflex/scanners.ts
+++ b/src/reflex/scanners.ts
@@ -6,99 +6,98 @@
 import client from "../utils/client.js";
 import { createHash } from "crypto";
 import * as nsfwjs from "nsfwjs";
-// import * as clamscan from "clamscan";
-import * as tf from "@tensorflow/tfjs";
+import ClamScan from "clamscan";
+import * as tf from "@tensorflow/tfjs-node";
 import EmojiEmbed from "../utils/generateEmojiEmbed.js";
 import getEmojiByName from "../utils/getEmojiByName.js";
 import { ActionRowBuilder, ButtonBuilder, ButtonStyle } from "discord.js";
+import config from "../config/main.js";
+import gm from "gm";
 
 interface NSFWSchema {
     nsfw: boolean;
     errored?: boolean;
 }
 interface MalwareSchema {
-    safe: boolean;
+    malware: boolean;
     errored?: boolean;
 }
 
-const nsfw_model = await nsfwjs.load();
+const nsfw_model = await nsfwjs.load("file://dist/reflex/nsfwjs/example/nsfw_demo/public/model/", { size: 299 });
+const clamscanner = await new ClamScan().init({
+    clamdscan: {
+        socket: "socket" in config.clamav ? (config.clamav.socket as string) : false,
+        host: "host" in config.clamav ? (config.clamav.host as string) : false,
+        port: "port" in config.clamav ? (config.clamav.port as number) : false
+    }
+});
 
-export async function testNSFW(link: string): Promise<NSFWSchema> {
-    const [fileStream, hash] = await streamAttachment(link);
+export async function testNSFW(url: string): Promise<NSFWSchema> {
+    const [fileStream, hash] = await streamAttachment(url);
     const alreadyHaveCheck = await client.database.scanCache.read(hash);
-    if (alreadyHaveCheck?.nsfw) return { nsfw: alreadyHaveCheck.nsfw };
+    if (alreadyHaveCheck && "nsfw" in alreadyHaveCheck!) {
+        return { nsfw: alreadyHaveCheck.nsfw };
+    }
 
-    const image = tf.tensor3d(new Uint8Array(fileStream));
+    const converted = (await new Promise((resolve, reject) =>
+        gm(fileStream)
+            .command("convert")
+            .toBuffer("PNG", (err, buf) => {
+                if (err) return reject(err);
+                resolve(buf);
+            })
+    )) as Buffer;
 
-    const predictions = (await nsfw_model.classify(image, 1))[0]!;
-    image.dispose();
+    const img = tf.node.decodeImage(converted, 3, undefined, false) as tf.Tensor3D;
 
-    return { nsfw: predictions.className === "Hentai" || predictions.className === "Porn" };
+    const predictions = (await nsfw_model.classify(img, 1))[0]!;
+    img.dispose();
+
+    const nsfw = predictions.className === "Hentai" || predictions.className === "Porn";
+    await client.database.scanCache.write(hash, "nsfw", nsfw);
+
+    return { nsfw };
 }
 
 export async function testMalware(link: string): Promise<MalwareSchema> {
-    const [_, hash] = await saveAttachment(link);
+    const [fileName, hash] = await saveAttachment(link);
     const alreadyHaveCheck = await client.database.scanCache.read(hash);
-    if (alreadyHaveCheck?.malware) return { safe: alreadyHaveCheck.malware };
-    return { safe: true };
-    // const data = new URLSearchParams();
-    // // const f = createReadStream(p);
-    // data.append("file", f.read(fs.statSync(p).size));
-    // const result = await fetch("https://unscan.p.rapidapi.com/malware", {
-    //     method: "POST",
-    //     headers: {
-    //         "X-RapidAPI-Key": client.config.rapidApiKey,
-    //         "X-RapidAPI-Host": "unscan.p.rapidapi.com"
-    //     },
-    //     body: data
-    // })
-    //     .then((response) =>
-    //         response.status === 200 ? (response.json() as Promise<MalwareSchema>) : { safe: true, errored: true }
-    //     )
-    //     .catch((err) => {
-    //         console.error(err);
-    //         return { safe: true, errored: true };
-    //     });
-    // if (!result.errored) {
-    //     client.database.scanCache.write(hash, "malware", result.safe);
-    // }
-    // return { safe: result.safe };
+    if (alreadyHaveCheck?.malware !== undefined) return { malware: alreadyHaveCheck.malware };
+    let malware;
+    try {
+        malware = (await clamscanner.scanFile(fileName)).isInfected;
+    } catch (e) {
+        return { malware: true };
+    }
+    await client.database.scanCache.write(hash, "malware", malware);
+    return { malware };
 }
 
 export async function testLink(link: string): Promise<{ safe: boolean; tags: string[] }> {
     const alreadyHaveCheck = await client.database.scanCache.read(link);
-    if (alreadyHaveCheck?.bad_link) return { safe: alreadyHaveCheck.bad_link, tags: alreadyHaveCheck.tags };
-    const scanned: { safe?: boolean; tags?: string[] } = await fetch("https://unscan.p.rapidapi.com/link", {
-        method: "POST",
-        headers: {
-            "X-RapidAPI-Key": client.config.rapidApiKey,
-            "X-RapidAPI-Host": "unscan.p.rapidapi.com"
-        },
-        body: `{"link":"${link}"}`
-    })
-        .then((response) => response.json() as Promise<MalwareSchema>)
-        .catch((err) => {
-            console.error(err);
-            return { safe: true, tags: [] };
-        });
-    client.database.scanCache.write(link, "bad_link", scanned.safe ?? true, scanned.tags ?? []);
-    return {
-        safe: scanned.safe ?? true,
-        tags: scanned.tags ?? []
-    };
+    if (alreadyHaveCheck?.bad_link !== undefined)
+        return { safe: alreadyHaveCheck.bad_link, tags: alreadyHaveCheck.tags ?? [] };
+    return { safe: true, tags: [] };
+    // const scanned: { safe?: boolean; tags?: string[] } = {}
+    // await client.database.scanCache.write(link, "bad_link", scanned.safe ?? true, scanned.tags ?? []);
+    // return {
+    //     safe: scanned.safe ?? true,
+    //     tags: scanned.tags ?? []
+    // };
 }
 
-export async function streamAttachment(link: string): Promise<[ArrayBuffer, string]> {
+export async function streamAttachment(link: string): Promise<[Buffer, string]> {
     const image = await (await fetch(link)).arrayBuffer();
     const enc = new TextDecoder("utf-8");
-    return [image, createHash("sha512").update(enc.decode(image), "base64").digest("base64")];
+    const buf = Buffer.from(image);
+    return [buf, createHash("sha512").update(enc.decode(image), "base64").digest("base64")];
 }
 
 export async function saveAttachment(link: string): Promise<[string, string]> {
     const image = await (await fetch(link)).arrayBuffer();
-    const fileName = generateFileName(link.split("/").pop()!.split(".").pop()!);
+    const fileName = await generateFileName(link.split("/").pop()!.split(".").pop()!);
     const enc = new TextDecoder("utf-8");
-    writeFileSync(fileName, new DataView(image), "base64");
+    writeFileSync(fileName, new DataView(image));
     return [fileName, createHash("sha512").update(enc.decode(image), "base64").digest("base64")];
 }
 
@@ -153,10 +152,11 @@
     return detectionsTypes as string[];
 }
 
-export async function NSFWCheck(element: string): Promise<boolean> {
+export async function NSFWCheck(url: string): Promise<boolean> {
     try {
-        return (await testNSFW(element)).nsfw;
-    } catch {
+        return (await testNSFW(url)).nsfw;
+    } catch (e) {
+        console.log(e);
         return false;
     }
 }
@@ -169,7 +169,7 @@
 
 export async function MalwareCheck(element: string): Promise<boolean> {
     try {
-        return (await testMalware(element)).safe;
+        return (await testMalware(element)).malware;
     } catch {
         return true;
     }
@@ -206,8 +206,9 @@
     return text;
 }
 
-export async function doMemberChecks(member: Discord.GuildMember, guild: Discord.Guild): Promise<void> {
+export async function doMemberChecks(member: Discord.GuildMember): Promise<void> {
     if (member.user.bot) return;
+    const guild = member.guild;
     const guildData = await client.database.guilds.read(guild.id);
     if (!guildData.logging.staff.channel) return;
     const [loose, strict] = [guildData.filters.wordFilter.words.loose, guildData.filters.wordFilter.words.strict];
@@ -217,20 +218,19 @@
     const nicknameCheck = TestString(member.nickname ?? "", loose, strict, guildData.filters.wordFilter.enabled);
     // Does the profile picture contain filtered words
     const avatarTextCheck = TestString(
-        (await TestImage(member.user.displayAvatarURL({ forceStatic: true }))) ?? "",
+        (await TestImage(member.displayAvatarURL({ forceStatic: true }))) ?? "",
         loose,
         strict,
         guildData.filters.wordFilter.enabled
     );
     // Is the profile picture NSFW
-    const avatarCheck =
-        guildData.filters.images.NSFW && (await NSFWCheck(member.user.displayAvatarURL({ forceStatic: true })));
+    const avatar = member.displayAvatarURL({ extension: "png", size: 1024, forceStatic: true });
+    const avatarCheck = guildData.filters.images.NSFW && (await NSFWCheck(avatar));
     // Does the username contain an invite
     const inviteCheck = guildData.filters.invite.enabled && /discord\.gg\/[a-zA-Z0-9]+/gi.test(member.user.username);
     // Does the nickname contain an invite
     const nicknameInviteCheck =
         guildData.filters.invite.enabled && /discord\.gg\/[a-zA-Z0-9]+/gi.test(member.nickname ?? "");
-
     if (
         usernameCheck !== null ||
         nicknameCheck !== null ||
@@ -257,7 +257,7 @@
         }
         if (avatarTextCheck !== null) {
             infractions.push(
-                `Profile picture contains a ${avatarTextCheck.type}ly filtered word: ${avatarTextCheck.word}`
+                `Profile picture contains a ${avatarTextCheck.type}ly filtered word (${avatarTextCheck.word})`
             );
         }
         if (infractions.length === 0) return;
@@ -272,39 +272,42 @@
                 `**Member:** ${member.user.username} (<@${member.user.id}>)\n\n` +
                     infractions.map((element) => `${filter} ${element}`).join("\n")
             );
+        const buttons = [
+            new ButtonBuilder()
+                .setCustomId(`mod:warn:${member.user.id}`)
+                .setLabel("Warn")
+                .setStyle(ButtonStyle.Primary),
+            new ButtonBuilder()
+                .setCustomId(`mod:mute:${member.user.id}`)
+                .setLabel("Mute")
+                .setStyle(ButtonStyle.Primary),
+            new ButtonBuilder().setCustomId(`mod:kick:${member.user.id}`).setLabel("Kick").setStyle(ButtonStyle.Danger),
+            new ButtonBuilder().setCustomId(`mod:ban:${member.user.id}`).setLabel("Ban").setStyle(ButtonStyle.Danger)
+        ];
+        if (usernameCheck !== null || nicknameCheck !== null)
+            buttons.concat([
+                new ButtonBuilder()
+                    .setCustomId(`mod:nickname:${member.user.id}`)
+                    .setLabel("Change Name")
+                    .setStyle(ButtonStyle.Primary)
+            ]);
+        if (avatarCheck || avatarTextCheck !== null)
+            buttons.concat([
+                new ButtonBuilder().setURL(member.displayAvatarURL()).setLabel("View Avatar").setStyle(ButtonStyle.Link)
+            ]);
+        const components: ActionRowBuilder<ButtonBuilder>[] = [];
+
+        for (let i = 0; i < buttons.length; i += 5) {
+            components.push(
+                new ActionRowBuilder<ButtonBuilder>().addComponents(
+                    buttons.slice(i, Math.min(buttons.length - 1, i + 5))
+                )
+            );
+        }
+
         await channel.send({
             embeds: [embed],
-            components: [
-                new ActionRowBuilder<ButtonBuilder>().addComponents(
-                    ...[
-                        new ButtonBuilder()
-                            .setCustomId(`mod:warn:${member.user.id}`)
-                            .setLabel("Warn")
-                            .setStyle(ButtonStyle.Primary),
-                        new ButtonBuilder()
-                            .setCustomId(`mod:mute:${member.user.id}`)
-                            .setLabel("Mute")
-                            .setStyle(ButtonStyle.Primary),
-                        new ButtonBuilder()
-                            .setCustomId(`mod:kick:${member.user.id}`)
-                            .setLabel("Kick")
-                            .setStyle(ButtonStyle.Danger),
-                        new ButtonBuilder()
-                            .setCustomId(`mod:ban:${member.user.id}`)
-                            .setLabel("Ban")
-                            .setStyle(ButtonStyle.Danger)
-                    ].concat(
-                        usernameCheck !== null || nicknameCheck !== null || avatarTextCheck !== null
-                            ? [
-                                  new ButtonBuilder()
-                                      .setCustomId(`mod:nickname:${member.user.id}`)
-                                      .setLabel("Change Name")
-                                      .setStyle(ButtonStyle.Primary)
-                              ]
-                            : []
-                    )
-                )
-            ]
+            components: components
         });
     }
 }
diff --git a/src/reflex/statsChannelUpdate.ts b/src/reflex/statsChannelUpdate.ts
index e3c7a2a..1b9379b 100644
--- a/src/reflex/statsChannelUpdate.ts
+++ b/src/reflex/statsChannelUpdate.ts
@@ -12,34 +12,43 @@
 export async function callback(user: User, guild: Guild) {
     guild = await client.guilds.fetch(guild.id);
     const config = await client.database.guilds.read(guild.id);
-    Object.entries(config.stats).forEach(async ([channel, props]) => {
-        if ((props as PropSchema).enabled) {
-            let string = (props as PropSchema).name;
-            if (!string) return;
-            string = await convertCurlyBracketString(string, user!.id, user!.username, guild!.name, guild!.members);
-            let fetchedChannel;
-            try {
-                fetchedChannel = await guild.channels.fetch(channel);
-            } catch (e) {
-                fetchedChannel = null;
-            }
-            if (!fetchedChannel) {
-                const deleted = config.stats[channel];
-                await client.database.guilds.write(guild.id, null, `stats.${channel}`);
-                return singleNotify(
-                    "statsChannelDeleted",
-                    guild.id,
-                    `One or more of your stats channels have been deleted. You can use ${getCommandMentionByName(
-                        "settings/stats"
-                    )}.\n` + `The channels name was: ${deleted!.name}`,
-                    "Critical"
-                );
-            }
-            try {
-                await fetchedChannel.setName(string.slice(0, 100));
-            } catch (e) {
-                console.error(e);
-            }
-        }
-    });
+    Object.entries(config.stats).forEach(
+        ([channel, props]) =>
+            void (async () => {
+                if ((props as PropSchema).enabled) {
+                    let string = (props as PropSchema).name;
+                    if (!string) return;
+                    string = await convertCurlyBracketString(
+                        string,
+                        user!.id,
+                        user!.username,
+                        guild!.name,
+                        guild!.members
+                    );
+                    let fetchedChannel;
+                    try {
+                        fetchedChannel = await guild.channels.fetch(channel);
+                    } catch (e) {
+                        fetchedChannel = null;
+                    }
+                    if (!fetchedChannel) {
+                        const deleted = config.stats[channel];
+                        await client.database.guilds.write(guild.id, null, `stats.${channel}`);
+                        return singleNotify(
+                            "statsChannelDeleted",
+                            guild.id,
+                            `One or more of your stats channels have been deleted. You can use ${getCommandMentionByName(
+                                "settings/stats"
+                            )}.\n` + `The channels name was: ${deleted!.name}`,
+                            "Critical"
+                        );
+                    }
+                    try {
+                        await fetchedChannel.setName(string.slice(0, 100));
+                    } catch (e) {
+                        console.error(e);
+                    }
+                }
+            })()
+    );
 }
diff --git a/src/reflex/verify.ts b/src/reflex/verify.ts
index a5991de..540fb4d 100644
--- a/src/reflex/verify.ts
+++ b/src/reflex/verify.ts
@@ -208,7 +208,7 @@
                     .setEmoji("CONTROL.BLOCKCROSS")
             ]
         });
-        singleNotify(
+        await singleNotify(
             "verifyRoleDeleted",
             interaction.guild!.id,
             `The role given when a member is verified has been deleted. Use ${getCommandMentionByName(
diff --git a/src/reflex/welcome.ts b/src/reflex/welcome.ts
index 8e471c6..33f1651 100644
--- a/src/reflex/welcome.ts
+++ b/src/reflex/welcome.ts
@@ -45,7 +45,7 @@
                         content: (config.welcome.ping ? `<@&${config.welcome.ping}>` : "") + `<@${member.id}>`
                     });
                 } catch (err) {
-                    singleNotify(
+                    await singleNotify(
                         "welcomeChannelDeleted",
                         member.guild.id,
                         `The welcome channel has been deleted or is no longer accessible. Use ${getCommandMentionByName(
diff --git a/src/utils/client.ts b/src/utils/client.ts
index 43f8c5f..6899b90 100644
--- a/src/utils/client.ts
+++ b/src/utils/client.ts
@@ -6,6 +6,7 @@
 import EventScheduler from "../utils/eventScheduler.js";
 import type { RoleMenuSchema } from "../actions/roleMenu.js";
 import config from "../config/main.js";
+import { Octokit } from "octokit";
 
 class NucleusClient extends Client {
     logger = Logger;
@@ -24,6 +25,7 @@
         scanCache: ScanCache;
         transcripts: Transcript;
     };
+    GitHub = new Octokit({ auth: config.githubPAT });
     preloadPage: Record<string, { command: string; argument: string }> = {}; // e.g. { channelID: { command: privacy, page: 3}}
     commands: Record<
         string,
diff --git a/src/utils/commandRegistration/register.ts b/src/utils/commandRegistration/register.ts
index fbd052f..d76617c 100644
--- a/src/utils/commandRegistration/register.ts
+++ b/src/utils/commandRegistration/register.ts
@@ -181,11 +181,19 @@
     client.on("interactionCreate", async (interaction: Interaction) => {
         if (interaction.isUserContextMenuCommand()) {
             const commandName = "contextCommands/user/" + interaction.commandName;
-            execute(client.commands[commandName]![0]?.check, client.commands[commandName]![0]?.callback, interaction);
+            await execute(
+                client.commands[commandName]![0]?.check,
+                client.commands[commandName]![0]?.callback,
+                interaction
+            );
             return;
         } else if (interaction.isMessageContextMenuCommand()) {
             const commandName = "contextCommands/message/" + interaction.commandName;
-            execute(client.commands[commandName]![0]?.check, client.commands[commandName]![0]?.callback, interaction);
+            await execute(
+                client.commands[commandName]![0]?.check,
+                client.commands[commandName]![0]?.callback,
+                interaction
+            );
             return;
         } else if (interaction.isAutocomplete()) {
             const commandName = interaction.commandName;
@@ -203,7 +211,7 @@
             const formatted = (choices ?? []).map((choice) => {
                 return { name: choice, value: choice };
             });
-            interaction.respond(formatted);
+            await interaction.respond(formatted);
         } else if (interaction.isChatInputCommand()) {
             const commandName = interaction.commandName;
             const subcommandGroupName = interaction.options.getSubcommandGroup(false);
@@ -219,7 +227,7 @@
             const command = client.commands[fullCommandName]![0];
             const callback = command?.callback;
             const check = command?.check;
-            execute(check, callback, interaction);
+            await execute(check, callback, interaction);
         }
     });
 }
diff --git a/src/utils/confirmationMessage.ts b/src/utils/confirmationMessage.ts
index 7b3bd31..0e4a9b4 100644
--- a/src/utils/confirmationMessage.ts
+++ b/src/utils/confirmationMessage.ts
@@ -42,7 +42,7 @@
         emoji: string;
         customId: string;
         modal: Discord.ModalBuilder;
-        value: string | undefined;
+        values: Record<string, string>;
     }[] = [];
 
     constructor(interaction: CommandInteraction | ButtonInteraction) {
@@ -106,9 +106,15 @@
         this.reason = reason;
         return this;
     }
-    addModal(buttonText: string, emoji: string, customId: string, current: string, modal: Discord.ModalBuilder) {
+    addModal(
+        buttonText: string,
+        emoji: string,
+        customId: string,
+        current: Record<string, string>,
+        modal: Discord.ModalBuilder
+    ) {
         modal.setCustomId(customId);
-        this.modals.push({ buttonText, emoji, customId, modal, value: current });
+        this.modals.push({ buttonText, emoji, customId, modal, values: current });
         return this;
     }
     async send(editOnly?: boolean): Promise<{
@@ -121,7 +127,7 @@
             emoji: string;
             customId: string;
             modal: Discord.ModalBuilder;
-            value: string | undefined;
+            values: Record<string, string>;
         }[];
     }> {
         let cancelled = false;
@@ -131,19 +137,19 @@
 
         while (!cancelled && success === undefined && !returnComponents && !newReason) {
             const fullComponents = [
-                new Discord.ButtonBuilder()
+                new ButtonBuilder()
                     .setCustomId("yes")
                     .setLabel("Confirm")
                     .setStyle(this.inverted ? ButtonStyle.Success : ButtonStyle.Danger)
                     .setEmoji(getEmojiByName("CONTROL.TICK", "id")),
-                new Discord.ButtonBuilder()
+                new ButtonBuilder()
                     .setCustomId("no")
                     .setLabel("Cancel")
-                    .setStyle(ButtonStyle.Secondary)
+                    .setStyle(ButtonStyle.Danger)
                     .setEmoji(getEmojiByName("CONTROL.CROSS", "id"))
             ];
             Object.entries(this.customButtons).forEach(([k, v]) => {
-                const button = new Discord.ButtonBuilder()
+                const button = new ButtonBuilder()
                     .setCustomId(k)
                     .setLabel(v.title)
                     .setStyle(v.active ? ButtonStyle.Success : ButtonStyle.Primary)
@@ -153,7 +159,7 @@
             });
             for (const modal of this.modals) {
                 fullComponents.push(
-                    new Discord.ButtonBuilder()
+                    new ButtonBuilder()
                         .setCustomId(modal.customId)
                         .setLabel(modal.buttonText)
                         .setStyle(ButtonStyle.Primary)
@@ -163,7 +169,7 @@
             }
             if (this.reason !== null)
                 fullComponents.push(
-                    new Discord.ButtonBuilder()
+                    new ButtonBuilder()
                         .setCustomId("reason")
                         .setLabel("Edit Reason")
                         .setStyle(ButtonStyle.Primary)
@@ -174,7 +180,7 @@
             for (let i = 0; i < fullComponents.length; i += 5) {
                 components.push(
                     new ActionRowBuilder<
-                        | Discord.ButtonBuilder
+                        | ButtonBuilder
                         | Discord.StringSelectMenuBuilder
                         | Discord.RoleSelectMenuBuilder
                         | Discord.UserSelectMenuBuilder
@@ -228,7 +234,7 @@
                 break;
             }
             if (component.customId === "yes") {
-                component.deferUpdate();
+                await component.deferUpdate();
                 for (const v of Object.values(this.customButtons)) {
                     if (!v.active) continue;
                     try {
@@ -241,7 +247,7 @@
                 returnComponents = true;
                 continue;
             } else if (component.customId === "no") {
-                component.deferUpdate();
+                await component.deferUpdate();
                 success = false;
                 returnComponents = true;
                 continue;
@@ -272,7 +278,7 @@
                             .setEmoji(this.emoji)
                     ],
                     components: [
-                        new ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
+                        new ActionRowBuilder<ButtonBuilder>().addComponents(
                             new ButtonBuilder()
                                 .setLabel("Back")
                                 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
@@ -291,10 +297,13 @@
                     cancelled = true;
                     continue;
                 }
-                if (out === null || out.isButton()) {
+                if (out === null) {
                     cancelled = true;
                     continue;
                 }
+                if (out.isButton()) {
+                    continue;
+                }
                 if (out instanceof ModalSubmitInteraction) {
                     newReason = out.fields.getTextInputValue("reason");
                     continue;
@@ -319,7 +328,7 @@
                             .setEmoji(this.emoji)
                     ],
                     components: [
-                        new ActionRowBuilder<Discord.ButtonBuilder>().addComponents(
+                        new ActionRowBuilder<ButtonBuilder>().addComponents(
                             new ButtonBuilder()
                                 .setLabel("Back")
                                 .setEmoji(getEmojiByName("CONTROL.LEFT", "id"))
@@ -339,16 +348,22 @@
                     cancelled = true;
                     continue;
                 }
-                if (out === null || out.isButton()) {
+                if (out === null) {
+                    cancelled = true;
+                    continue;
+                }
+                if (out.isButton()) {
                     continue;
                 }
                 if (out instanceof ModalSubmitInteraction) {
-                    chosenModal!.value = out.fields.getTextInputValue("default");
+                    out.fields.fields.forEach((f, k) => {
+                        chosenModal!.values[k] = f.value;
+                    });
                 }
                 returnComponents = true;
                 continue;
             } else {
-                component.deferUpdate();
+                await component.deferUpdate();
                 this.customButtons[component.customId]!.active = !this.customButtons[component.customId]!.active;
                 returnComponents = true;
                 continue;
diff --git a/src/utils/database.ts b/src/utils/database.ts
index a107d06..abb638f 100644
--- a/src/utils/database.ts
+++ b/src/utils/database.ts
@@ -142,6 +142,22 @@
         // console.log("Guild delete")
         await this.guilds.deleteOne({ id: guild });
     }
+
+    async staffChannels(): Promise<string[]> {
+        const entries = (
+            await this.guilds
+                .find(
+                    { "logging.staff.channel": { $exists: true } },
+                    { projection: { "logging.staff.channel": 1, _id: 0 } }
+                )
+                .toArray()
+        ).map((e) => e.logging.staff.channel);
+        const out: string[] = [];
+        for (const entry of entries) {
+            if (entry) out.push(entry);
+        }
+        return out;
+    }
 }
 
 interface TranscriptEmbed {
@@ -258,7 +274,6 @@
             .replace(/=/g, "")
             .replace(/\//g, "_")
             .replace(/\+/g, "-");
-        console.log(iv);
         for (const message of transcript.messages) {
             if (message.content) {
                 const encCipher = crypto.createCipheriv("AES-256-CBC", key, iv);
@@ -268,7 +283,7 @@
 
         const doc = await this.transcripts.insertOne(Object.assign(transcript, { code: code }), collectionOptions);
         if (doc.acknowledged) {
-            client.database.eventScheduler.schedule(
+            await client.database.eventScheduler.schedule(
                 "deleteTranscript",
                 (Date.now() + 1000 * 60 * 60 * 24 * 7).toString(),
                 { guild: transcript.guild, code: code, iv: iv, key: key }
@@ -327,10 +342,8 @@
     }
 
     async read(code: string, key: string, iv: string) {
-        console.log("Transcript read");
         let doc: TranscriptSchema | null = await this.transcripts.findOne({ code: code });
         let findDoc: findDocSchema | null = null;
-        console.log(doc);
         if (!doc) findDoc = await this.messageToTranscript.findOne({ transcript: code });
         if (findDoc) {
             const message = await (
@@ -356,7 +369,6 @@
             if (!data) return null;
             doc = JSON.parse(Buffer.from(data).toString()) as TranscriptSchema;
         }
-        console.log(doc);
         if (!doc) return null;
         for (const message of doc.messages) {
             if (message.content) {
@@ -591,7 +603,7 @@
     nsfw?: boolean;
     malware?: boolean;
     bad_link?: boolean;
-    tags: string[];
+    tags?: string[];
 }
 
 export class ScanCache {
@@ -606,9 +618,30 @@
     }
 
     async write(hash: string, type: "nsfw" | "malware" | "bad_link", data: boolean, tags?: string[]) {
-        await this.scanCache.insertOne(
-            { hash: hash, [type]: data, tags: tags ?? [], addedAt: new Date() },
-            collectionOptions
+        await this.scanCache.updateOne(
+            { hash: hash },
+            {
+                $set: (() => {
+                    switch (type) {
+                        case "nsfw": {
+                            return { nsfw: data, addedAt: new Date() };
+                        }
+                        case "malware": {
+                            return { malware: data, addedAt: new Date() };
+                        }
+                        case "bad_link": {
+                            return { bad_link: data, tags: tags ?? [], addedAt: new Date() };
+                        }
+                        default: {
+                            throw new Error("Invalid type");
+                        }
+                    }
+                })()
+                // No you can't just do { [type]: data }, yes it's a typescript error, no I don't know how to fix it
+                // cleanly, yes it would be marginally more elegant, no it's not essential, yes I'd be happy to review
+                // PRs that did improve this snippet
+            },
+            Object.assign({ upsert: true }, collectionOptions)
         );
     }
 
diff --git a/src/utils/dualCollector.ts b/src/utils/dualCollector.ts
index bf9b0c0..e96ff5d 100644
--- a/src/utils/dualCollector.ts
+++ b/src/utils/dualCollector.ts
@@ -32,11 +32,7 @@
                     time: 300000
                 })
                 .on("collect", (m) => {
-                    try {
-                        m.delete();
-                    } catch (e) {
-                        client.emit("error", e as Error);
-                    }
+                    void m.delete().catch();
                     resolve(m);
                 });
             mes.on("end", () => {
diff --git a/src/utils/eventScheduler.ts b/src/utils/eventScheduler.ts
index 34bb28e..48eee63 100644
--- a/src/utils/eventScheduler.ts
+++ b/src/utils/eventScheduler.ts
@@ -79,13 +79,13 @@
                     guild: guild.id
                 }
             };
-            log(data);
+            await log(data);
         });
     }
 
     async start() {
         await new Promise((resolve) => this.agenda.once("ready", resolve));
-        this.agenda.start();
+        await this.agenda.start();
         return this;
     }
 
@@ -95,8 +95,8 @@
     }
 
     // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    cancel(name: string, data: any) {
-        this.agenda.cancel({ name, data });
+    async cancel(name: string, data: any) {
+        await this.agenda.cancel({ name, data });
     }
 }
 
diff --git a/src/utils/getCommandDataByName.ts b/src/utils/getCommandDataByName.ts
index 46f4362..dcf45ca 100644
--- a/src/utils/getCommandDataByName.ts
+++ b/src/utils/getCommandDataByName.ts
@@ -1,22 +1,40 @@
 import type Discord from "discord.js";
 import client from "./client.js";
 
+/**
+ * @param name The name of the command, not including a leading slash. This can be space or slash separated e.g. "mod/about" or "mod about"
+ * @returns A string which when put into Discord will mention the command if the command exists or a codeblock with the command name if it does not
+ *
+ * @throws Will throw an error if as empty string is passed
+ **/
 export const getCommandMentionByName = (name: string): string => {
     const split = name.replaceAll("/", " ").split(" ");
-    const commandName: string = split[0]!;
+    const commandName: string | undefined = split[0];
+    if (commandName === undefined) throw new RangeError(`Invalid command ${name} provided to getCommandByName`);
 
     const filterCommand = (command: Discord.ApplicationCommand) => command.name === commandName;
 
     const command = client.fetchedCommands.filter((c) => filterCommand(c));
-    if (command.size === 0) return `\`/${name.replaceAll("/", " ")}\``;
-    const commandID = command.first()!.id;
+    const commandID = command.first()?.id;
+
+    if (commandID === undefined) return `\`/${name.replaceAll("/", " ")}\``;
+
     return `</${split.join(" ")}:${commandID}>`;
 };
 
+/**
+ * @param name The name of the command, not including a leading slash. This can be space or slash separated e.g. "mod/about" or "mod about"
+ * @returns An object containing the command name, the command description and a string which when put into Discord will mention the command
+ *
+ * @throws Will throw an error if the command doesn't exist
+ * @throws Will throw an error if as empty string is passed
+ **/
 export const getCommandByName = (name: string): { name: string; description: string; mention: string } => {
     const split = name.replaceAll(" ", "/");
-    const command = client.commands["commands/" + split]!;
-    // console.log(command)
+    const command = client.commands["commands/" + split];
+
+    if (command === undefined) throw new RangeError(`Invalid command ${name} provided to getCommandByName`);
+
     const mention = getCommandMentionByName(name);
     return {
         name: command[1].name,
diff --git a/src/utils/getEmojiByName.ts b/src/utils/getEmojiByName.ts
index 99d1215..ebcb257 100644
--- a/src/utils/getEmojiByName.ts
+++ b/src/utils/getEmojiByName.ts
@@ -1,20 +1,31 @@
-import emojis from "../config/emojis.json" assert { type: "json" };
-import lodash from "lodash";
+import emojis from "../config/emojis.js";
+import _ from "lodash";
 
-const isArray = lodash.isArray;
 interface EmojisIndex {
     [key: string]: string | EmojisIndex | EmojisIndex[];
 }
 
-function getEmojiByName(name: string | null, format?: string): string {
-    if (!name) return "";
+const EMOJIPATHS: string[] = [];
+
+function getEmojiPaths(obj: EmojisIndex, path: string[] = []) {
+    for (const key in obj) {
+        if (typeof obj[key] === "string") {
+            EMOJIPATHS.push([...path, key].join("."));
+        } else {
+            getEmojiPaths(obj[key] as EmojisIndex, [...path, key]);
+        }
+    }
+}
+getEmojiPaths(emojis);
+
+function getEmojiByName(name: (typeof EMOJIPATHS)[number], format?: string): string {
     const parts = name.split(".");
     let id: string | EmojisIndex | EmojisIndex[] | undefined = emojis;
     for (const part of parts) {
         if (typeof id === "string" || id === undefined) {
             throw new Error(`Emoji ${name} not found`);
         }
-        if (isArray(id)) {
+        if (_.isArray(id)) {
             id = id[parseInt(part)];
         } else {
             id = id[part];
@@ -34,9 +45,9 @@
     if (id === undefined) {
         return "";
     } else if (id.toString().startsWith("a")) {
-        return `<a:_:${id.toString().slice(1, id.toString().length)}>`;
+        return `<a:N:${id.toString().slice(1, id.toString().length)}>`;
     }
-    return `<:_:${id}>`;
+    return `<:N:${id}>`;
 }
 
 export default getEmojiByName;
diff --git a/src/utils/log.ts b/src/utils/log.ts
index b29f365..3b6048a 100644
--- a/src/utils/log.ts
+++ b/src/utils/log.ts
@@ -99,9 +99,7 @@
     },
     async log(log: LoggerOptions): Promise<void> {
         if (!(await isLogging(log.hidden.guild, log.meta.calculateType))) return;
-        console.log(log.hidden.guild);
         const config = await client.database.guilds.read(log.hidden.guild);
-        console.log(config.logging.logs.channel);
 
         if (config.logging.logs.channel) {
             const channel = (await client.channels.fetch(config.logging.logs.channel)) as Discord.TextChannel | null;
@@ -127,7 +125,7 @@
                     )
                     .setTimestamp(log.meta.timestamp)
                     .setColor(log.meta.color);
-                channel.send({ embeds: [embed] });
+                await channel.send({ embeds: [embed] });
             }
         }
     },
diff --git a/src/utils/migration/migration.ts b/src/utils/migration/migration.ts
deleted file mode 100644
index 6286465..0000000
--- a/src/utils/migration/migration.ts
+++ /dev/null
@@ -1,80 +0,0 @@
-import * as fs from "fs";
-import client from "../client.js";
-import _ from "lodash";
-
-const dir = "./data";
-const files = fs.readdirSync(dir);
-
-for (const file of files) {
-    // eslint-disable-next-line @typescript-eslint/no-explicit-any
-    let rsmData: any;
-    try {
-        rsmData = JSON.parse(fs.readFileSync(`${dir}/${file}`, "utf8"));
-    } catch {
-        continue;
-    }
-    if (!rsmData.version || rsmData.version < 3) continue;
-    const nucleusData = await client.database.guilds.readOld(rsmData.guild_info.id);
-    const rsmToNucleus = {
-        id: rsmData.guild_info.id,
-        version: 1,
-        singleEventNotifications: {},
-        filters: {
-            images: {
-                NSFW: rsmData.images?.nsfw,
-                size: rsmData.images?.toosmall
-            },
-            malware: null,
-            wordFilter: {
-                enabled: true,
-                words: {
-                    strict: rsmData.wordfilter?.strict,
-                    loose: rsmData.wordfilter?.soft
-                },
-                allowed: {
-                    users: rsmData.wordfilter?.ignore?.members,
-                    roles: rsmData.wordfilter?.ignore?.roles,
-                    channels: rsmData.wordfilter?.ignore?.channels
-                }
-            },
-            invite: {
-                enabled: rsmData.invite?.enabled,
-                allowed: {
-                    channels: rsmData.invite?.whitelist?.members,
-                    roles: rsmData.invite?.whitelist?.roles,
-                    users: rsmData.invite?.whitelist?.channels
-                }
-            }
-        },
-        welcome: {
-            enabled: true,
-            role: rsmData.welcome?.role,
-            channel: rsmData.welcome?.message?.channel,
-            message: rsmData.welcome?.message?.text ?? null
-        },
-        logging: {
-            logs: {
-                enabled: true,
-                channel: rsmData.log_info?.log_channel
-            },
-            staff: {
-                channel: rsmData.log_info?.staff
-            }
-        },
-        verify: {
-            enabled: true,
-            role: rsmData.verify_role
-        },
-        tickets: {
-            enabled: true,
-            category: rsmData.modmail?.cat,
-            supportRole: rsmData.modmail?.mention,
-            maxTickets: rsmData.modmail?.max
-        },
-        tags: rsmData.tags
-    } as Partial<ReturnType<typeof client.database.guilds.read>>;
-    // console.log(rsmToNucleus)
-    const merged = _.merge(nucleusData, rsmToNucleus);
-    // console.log(merged)
-    await client.database.guilds.write(merged.id!, merged);
-}
diff --git a/src/utils/performanceTesting/record.ts b/src/utils/performanceTesting/record.ts
index 89f3ead..58246d0 100644
--- a/src/utils/performanceTesting/record.ts
+++ b/src/utils/performanceTesting/record.ts
@@ -14,7 +14,7 @@
     const user = guild.ownerId;
     const currentYear = new Date().getFullYear();
     const start = Date.now();
-    client.database.history.read(guild.id, user, currentYear - 1);
+    await client.database.history.read(guild.id, user, currentYear - 1);
     const end = Date.now();
     return end - start;
 };
@@ -34,25 +34,57 @@
         databaseRead: await databaseReadTime(),
         resources: await resources()
     };
-    if (results.discord > 1000 || results.databaseRead > 500 || results.resources.cpu > 100) {
-        singleNotify(
+    let bold: string;
+    switch (true) {
+        case results.discord > 1000:
+            bold = "DiscordPing";
+            break;
+        case results.databaseRead > 500:
+            bold = "DatabaseRead";
+            break;
+        case results.resources.cpu > 100:
+            bold = "CPUUsage";
+            break;
+        case results.resources.memory > 5000:
+            bold = "MemoryUsage";
+            break;
+        case results.resources.temperature > 80:
+            bold = "Temperature";
+            break;
+        default:
+            bold = "None";
+    }
+    if (
+        results.discord > 1000 ||
+        results.databaseRead > 500 ||
+        results.resources.cpu > 100 ||
+        results.resources.memory > 5000 ||
+        results.resources.temperature > 80
+    ) {
+        await singleNotify(
             "performanceTest",
             config.developmentGuildID,
-            `Discord ping time: \`${results.discord}ms\`\nDatabase read time: \`${
-                results.databaseRead
-            }ms\`\nCPU usage: \`${results.resources.cpu}%\`\nMemory usage: \`${Math.round(
-                results.resources.memory
-            )}MB\`\nCPU temperature: \`${results.resources.temperature}°C\``,
+            `${bold === "DiscordPing" ? "**Discord ping time:**" : "Discord ping time:"} \`${results.discord}ms\`\n` +
+                `${bold === "DatabaseRead" ? "**Database read time:**" : "Database read time:"} \`${
+                    results.databaseRead
+                }ms\`\n` +
+                `${bold === "CPUUsage" ? "**CPU usage:**" : "CPU usage:"} \`${results.resources.cpu}%\`\n` +
+                `${bold === "MemoryUsage" ? "**Memory usage:**" : "Memory usage:"} \`${Math.round(
+                    results.resources.memory
+                )}MB\`\n` +
+                `${bold === "Temperature" ? "**CPU temperature:**" : "CPU temperature:"} \`${
+                    results.resources.temperature
+                }°C\``,
             "Critical",
             config.owners
         );
     } else {
-        singleNotify("performanceTest", config.developmentGuildID, true);
+        await singleNotify("performanceTest", config.developmentGuildID, true);
     }
 
-    client.database.performanceTest.record(results);
-    setTimeout(async () => {
-        await record();
+    await client.database.performanceTest.record(results);
+    setTimeout(() => {
+        void record();
     }, 60 * 1000);
 };
 
diff --git a/src/utils/temp/generateFileName.ts b/src/utils/temp/generateFileName.ts
index 109478d..8feefbb 100644
--- a/src/utils/temp/generateFileName.ts
+++ b/src/utils/temp/generateFileName.ts
@@ -6,13 +6,13 @@
 const __filename = fileURLToPath(import.meta.url);
 const __dirname = path.dirname(__filename);
 
-export default function generateFileName(ending: string): string {
+export default async function generateFileName(ending: string): Promise<string> {
     let fileName = crypto.randomBytes(35).toString("hex");
     fileName = fileName.replace(/([a-zA-Z0-9]{8})/g, "$1-");
     if (fs.existsSync(`./${fileName}`)) {
-        fileName = generateFileName(ending);
+        fileName = await generateFileName(ending);
     }
-    client.database.eventScheduler.schedule("deleteFile", (Date.now() + 60 * 1000).toString(), {
+    await client.database.eventScheduler.schedule("deleteFile", (Date.now() + 60 * 1000).toString(), {
         fileName: `${fileName}.${ending}`
     });
     return path.join(__dirname, fileName + "." + ending);
diff --git a/src/utils/types/recursivePartial.d.ts b/src/utils/types/recursivePartial.d.ts
new file mode 100644
index 0000000..a578bb4
--- /dev/null
+++ b/src/utils/types/recursivePartial.d.ts
@@ -0,0 +1,7 @@
+type RecursivePartial<T> = {
+    [P in keyof T]?: T[P] extends (infer U)[]
+        ? RecursivePartial<U>[]
+        : T[P] extends object
+        ? RecursivePartial<T[P]>
+        : T[P];
+};
diff --git a/tsconfig.json b/tsconfig.json
index 8b0fe7d..1df2f7d 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -14,5 +14,5 @@
         "noImplicitReturns": false
     },
     "include": ["src/**/*", "src/*", "src/config/main.d.ts", "src/config/main.ts"],
-    "exclude": ["src/Unfinished/**/*"]
+    "exclude": ["src/Unfinished/**/*", "src/reflex/nsfwjs/**/*"]
 }