From de88eaaf71701b8d8a75450af8d9941edc9a0af9 Mon Sep 17 00:00:00 2001
From: AkimotoRyou <39645219+AkimotoRyou@users.noreply.github.com>
Date: Fri, 24 Apr 2020 12:29:04 +0700
Subject: [PATCH] Restructuring bot

---
 commands/aclose.js         |   67 ++
 commands/areply.js         |   70 ++
 commands/bind.js           |   50 +
 commands/block.js          |   53 +
 commands/blockinfo.js      |   53 +
 commands/blocklist.js      |   53 +
 commands/close.js          |   67 ++
 commands/commands.js       |  107 ++
 commands/configinfo.js     |   50 +
 commands/configuration.js  |   51 +
 commands/guilds.js         |   52 +
 commands/help.js           |   46 +
 commands/helpchs.js        |   20 +
 commands/helpcht.js        |   20 +
 commands/helpde.js         |   20 +
 commands/helpes.js         |   20 +
 commands/helpfr.js         |   20 +
 commands/helpkr.js         |   20 +
 commands/helppt.js         |   20 +
 commands/helpru.js         |   20 +
 commands/helptr.js         |   20 +
 commands/leave.js          |   38 +
 commands/new.js            |   44 +
 commands/ping.js           |   30 +
 commands/reload.js         |   43 +
 commands/reply.js          |   70 ++
 commands/reset.js          |   67 ++
 commands/restart.js        |   59 +
 commands/set.js            |   50 +
 commands/threadinfo.js     |   55 +
 commands/unblock.js        |   53 +
 config.json                |    6 +-
 functions/aclose.js        |   73 ++
 functions/areply.js        |   85 ++
 functions/bind.js          |   43 +
 functions/block.js         |   33 +
 functions/blockinfo.js     |   30 +
 functions/blocklist.js     |   41 +
 functions/close.js         |   73 ++
 functions/configInfo.js    |   96 ++
 functions/configSync.js    |   38 +
 functions/configuration.js |   48 +
 functions/getEmbed.js      |   12 +
 functions/isBlocked.js     |   13 +
 functions/isMember.js      |   15 +
 functions/newThread.js     |  106 ++
 functions/reply.js         |   85 ++
 functions/reset.js         |   27 +
 functions/roleCheck.js     |   12 +
 functions/set.js           |  119 ++
 functions/threadInfo.js    |   52 +
 functions/unblock.js       |   24 +
 functions/userReply.js     |   64 ++
 index.js                   | 2145 ++++++------------------------------
 54 files changed, 2826 insertions(+), 1822 deletions(-)
 create mode 100644 commands/aclose.js
 create mode 100644 commands/areply.js
 create mode 100644 commands/bind.js
 create mode 100644 commands/block.js
 create mode 100644 commands/blockinfo.js
 create mode 100644 commands/blocklist.js
 create mode 100644 commands/close.js
 create mode 100644 commands/commands.js
 create mode 100644 commands/configinfo.js
 create mode 100644 commands/configuration.js
 create mode 100644 commands/guilds.js
 create mode 100644 commands/help.js
 create mode 100644 commands/helpchs.js
 create mode 100644 commands/helpcht.js
 create mode 100644 commands/helpde.js
 create mode 100644 commands/helpes.js
 create mode 100644 commands/helpfr.js
 create mode 100644 commands/helpkr.js
 create mode 100644 commands/helppt.js
 create mode 100644 commands/helpru.js
 create mode 100644 commands/helptr.js
 create mode 100644 commands/leave.js
 create mode 100644 commands/new.js
 create mode 100644 commands/ping.js
 create mode 100644 commands/reload.js
 create mode 100644 commands/reply.js
 create mode 100644 commands/reset.js
 create mode 100644 commands/restart.js
 create mode 100644 commands/set.js
 create mode 100644 commands/threadinfo.js
 create mode 100644 commands/unblock.js
 create mode 100644 functions/aclose.js
 create mode 100644 functions/areply.js
 create mode 100644 functions/bind.js
 create mode 100644 functions/block.js
 create mode 100644 functions/blockinfo.js
 create mode 100644 functions/blocklist.js
 create mode 100644 functions/close.js
 create mode 100644 functions/configInfo.js
 create mode 100644 functions/configSync.js
 create mode 100644 functions/configuration.js
 create mode 100644 functions/getEmbed.js
 create mode 100644 functions/isBlocked.js
 create mode 100644 functions/isMember.js
 create mode 100644 functions/newThread.js
 create mode 100644 functions/reply.js
 create mode 100644 functions/reset.js
 create mode 100644 functions/roleCheck.js
 create mode 100644 functions/set.js
 create mode 100644 functions/threadInfo.js
 create mode 100644 functions/unblock.js
 create mode 100644 functions/userReply.js

diff --git a/commands/aclose.js b/commands/aclose.js
new file mode 100644
index 0000000..4dc9ae3
--- /dev/null
+++ b/commands/aclose.js
@@ -0,0 +1,67 @@
+module.exports = {
+	name: 'aclose',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '[reason]-[note]',
+	description: 'Anonymously close a user thread.',
+  note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const aclose = param.aclose;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+    const notChannelEmbed = getEmbed.execute(param, config.error_color, "Invalid Channel", `This isn\'t thread channel.`);
+
+    //Yes i know it's nasty to look at that many nested if else but it's needed @,@
+    if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      return message.channel.send(noServerEmbed);
+		} else {
+			if(message.guild.id == config.threadServerID){
+        //inside thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID or modRoleID empty
+					return message.channel.send(noAdminEmbed);
+				} else if(config.categoryID == "empty" || config.logChannelID == "empty"){
+          //categoryID or logChannelID empty
+          return message.channel.send(noChannelEmbed);
+        } else {
+          //adminRoleID, modRoleID, categoryID and logChannelID not empty
+          if (message.channel.parentID != config.categoryID || message.channel.id == config.logChannelID || message.channel.id == config.botChannelID) {
+            //the channel isn't under modmail category or it's a log channel or it's bot channel -_-
+            return message.channel.send(notChannelEmbed);
+          } else {
+            //the channel is under modmail category, it's not a log channel, and it's not bot channel
+						if(message.author.id == config.botOwnerID){
+              return aclose.execute(param, message, args);
+            } else if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+              //user has ADMINISTRATOR permission or has admin role
+              return aclose.execute(param, message, args);
+    				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+    					//user has moderator role
+              return aclose.execute(param, message, args);
+    				} else {
+    					//user didn't have ADMINISTRATOR permission nor has admin role
+    					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+    						return;
+    					} else {
+    						return message.channel.send(noPermEmbed);
+    					};
+    				}
+
+          }
+        }
+
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/areply.js b/commands/areply.js
new file mode 100644
index 0000000..cadb143
--- /dev/null
+++ b/commands/areply.js
@@ -0,0 +1,70 @@
+module.exports = {
+	name: 'areply',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: false,//in case only attachment no message
+  usage: '[reply message]',
+	description: 'Anonymously reply to a user thread.',
+  note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const areply = param.areply;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+    const notChannelEmbed = getEmbed.execute(param, config.error_color, "Invalid Channel", `This isn\'t thread channel.`);
+		const noArgsEmbed = param.getEmbed.execute(param, config.warning_color, "Missing Arguments", `You didn\'t provide any arguments nor attachments.`);
+
+    //Yes i know it's nasty to look at that many nested if else but it's needed @,@
+    if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      return message.channel.send(noServerEmbed);
+		} else {
+			if(message.guild.id == config.threadServerID){
+        //inside thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID or modRoleID empty
+					return message.channel.send(noAdminEmbed);
+				} else if(config.categoryID == "empty" || config.logChannelID == "empty"){
+          //categoryID or logChannelID empty
+          return message.channel.send(noChannelEmbed);
+        } else {
+          //adminRoleID, modRoleID, categoryID and logChannelID not empty
+          if (message.channel.parentID != config.categoryID || message.channel.id == config.logChannelID || message.channel.id == config.botChannelID) {
+            //the channel isn't under modmail category or it's a log channel or it's bot channel -_-
+            return message.channel.send(notChannelEmbed);
+          } else {
+            //the channel is under modmail category, it's not a log channel, and it's not bot channel
+						if(!args.length && message.attachments.size == 0){
+							return message.channel.send(noArgsEmbed);
+						} else if(message.author.id == config.botOwnerID){
+              return areply.execute(param, message, args);
+            } else if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+              //user has ADMINISTRATOR permission or has admin role
+              return areply.execute(param, message, args);
+    				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+    					//user has moderator role
+              return areply.execute(param, message, args);
+    				} else {
+    					//user didn't have ADMINISTRATOR permission nor has admin role
+    					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+    						return;
+    					} else {
+    						return message.channel.send(noPermEmbed);
+    					};
+    				}
+
+          }
+        }
+
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/bind.js b/commands/bind.js
new file mode 100644
index 0000000..b230556
--- /dev/null
+++ b/commands/bind.js
@@ -0,0 +1,50 @@
+module.exports = {
+  name: 'bind',
+  aliases: false,
+  level: 'Admin',
+  guildOnly: true,
+	args: true,
+  usage: '<userID> <channelID>',
+  description: 'Bind user thread to a channel.',
+	note: 'Only use under these circumtances : \n> There is an open thread from other bot.\n> The channel was accidentally deleted.\n> Category channel was accidentally deleted and changed.',
+  async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const bind = param.bind;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+			return bind.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+			return bind.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+					return bind.execute(param, message, args);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+          if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+      			return;
+      		} else {
+      			return message.channel.send(noPermEmbed);
+      		};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/block.js b/commands/block.js
new file mode 100644
index 0000000..6d8e659
--- /dev/null
+++ b/commands/block.js
@@ -0,0 +1,53 @@
+module.exports = {
+	name: 'block',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '<userID> [reason]',
+	description: 'Block a user from creating new thread and replying to a thread.',
+  note: 'User presence isn\'t checked to enable blocking users that are outside the server.',
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const block = param.block;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      return block.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      return block.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          return block.execute(param, message, args);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return block.execute(param, message, args);
+				} else {
+					//user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/blockinfo.js b/commands/blockinfo.js
new file mode 100644
index 0000000..1b54e1b
--- /dev/null
+++ b/commands/blockinfo.js
@@ -0,0 +1,53 @@
+module.exports = {
+	name: 'blockinfo',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '<userID>',
+	description: 'Information about a user\'s block.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const blockinfo = param.blockinfo;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      return blockinfo.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      return blockinfo.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          return blockinfo.execute(param, message, args);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return blockinfo.execute(param, message, args);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/blocklist.js b/commands/blocklist.js
new file mode 100644
index 0000000..84c0595
--- /dev/null
+++ b/commands/blocklist.js
@@ -0,0 +1,53 @@
+module.exports = {
+	name: 'blocklist',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: false,
+  usage: '[page number]',
+	description: 'List of blocked users.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const blocklist = param.blocklist;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      return blocklist.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      return blocklist.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          return blocklist.execute(param, message, args);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return blocklist.execute(param, message, args);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/close.js b/commands/close.js
new file mode 100644
index 0000000..31e8966
--- /dev/null
+++ b/commands/close.js
@@ -0,0 +1,67 @@
+module.exports = {
+	name: 'close',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '[reason]-[note]',
+	description: 'Close a user thread.',
+  note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const close = param.close;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+    const notChannelEmbed = getEmbed.execute(param, config.error_color, "Invalid Channel", `This isn\'t thread channel.`);
+
+    //Yes i know it's nasty to look at that many nested if else but it's needed @,@
+    if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      return message.channel.send(noServerEmbed);
+		} else {
+			if(message.guild.id == config.threadServerID){
+        //inside thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID or modRoleID empty
+					return message.channel.send(noAdminEmbed);
+				} else if(config.categoryID == "empty" || config.logChannelID == "empty"){
+          //categoryID or logChannelID empty
+          return message.channel.send(noChannelEmbed);
+        } else {
+          //adminRoleID, modRoleID, categoryID and logChannelID not empty
+          if (message.channel.parentID != config.categoryID || message.channel.id == config.logChannelID || message.channel.id == config.botChannelID) {
+            //the channel isn't under modmail category or it's a log channel or it's bot channel -_-
+            return message.channel.send(notChannelEmbed);
+          } else {
+            //the channel is under modmail category, it's not a log channel, and it's not bot channel
+						if(message.author.id == config.botOwnerID){
+              return close.execute(param, message, args);
+            } else if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+              //user has ADMINISTRATOR permission or has admin role
+              return close.execute(param, message, args);
+    				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+    					//user has moderator role
+              return close.execute(param, message, args);
+    				} else {
+    					//user didn't have ADMINISTRATOR permission nor has admin role
+    					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+    						return;
+    					} else {
+    						return message.channel.send(noPermEmbed);
+    					};
+    				}
+
+          }
+        }
+
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/commands.js b/commands/commands.js
new file mode 100644
index 0000000..ef61443
--- /dev/null
+++ b/commands/commands.js
@@ -0,0 +1,107 @@
+module.exports = {
+	name: 'commands',
+  aliases: ['cmd'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'List of all available commands according to your permission level.',
+	note: false,
+	async execute(param, message, args){
+    const Discord = param.Discord;
+    const client = param.client;
+    const config = param.config;
+		const getEmbed = param.getEmbed;
+    const commands = param.client.commands;
+
+		//collections
+    const ownerCollection = commands.filter(command => command.level === 'Owner');
+    const ownerLevel = ownerCollection.map(command => `**${command.name}** : ${command.description}`).join('\n');
+    const adminCollection = commands.filter(command => command.level === 'Admin');
+    const adminLevel = adminCollection.map(command => `**${command.name}** : ${command.description}`).join('\n');
+    const moderatorCollection = commands.filter(command => command.level === 'Moderator');
+    const moderatorLevel = moderatorCollection.map(command => `**${command.name}** : ${command.description}`).join('\n');
+    const userCollection = commands.filter(command => command.level === 'User');
+    const userLevel = userCollection.map(command => `**${command.name}** : ${command.description}`).join('\n');
+
+		//embeds
+    const ownerEmbed = new Discord.RichEmbed()
+      .setColor(config.info_color)
+      .setTitle("Commands")
+			.setDescription(`Use \`${config.prefix}help [command name]\` to get information for each command.`)
+      .addField("~ Owner Level ~", ownerLevel || "empty")
+      .addField("~ Admin Level ~", adminLevel || "empty")
+      .addField("~ Moderator Level ~", moderatorLevel || "empty")
+      .addField("~ User level ~", userLevel || "empty")
+      .setThumbnail(client.user.avatarURL)
+      .setFooter(client.user.tag, client.user.avatarURL)
+      .setTimestamp();
+    const adminEmbed = new Discord.RichEmbed()
+      .setColor(config.info_color)
+      .setTitle("Command List")
+			.setDescription(`Use \`${config.prefix}help [command name]\` to get information for each command.`)
+      .addField("~ Admin Level ~", adminLevel || "empty")
+      .addField("~ Moderator Level ~", moderatorLevel || "empty")
+      .addField("~ User level ~", userLevel || "empty")
+      .setThumbnail(client.user.avatarURL)
+      .setFooter(client.user.tag, client.user.avatarURL)
+      .setTimestamp();
+    const moderatorEmbed = new Discord.RichEmbed()
+      .setColor(config.info_color)
+      .setTitle("Command List")
+			.setDescription(`Use \`${config.prefix}help [command name]\` to get information for each command.`)
+      .addField("~ Moderator Level ~", moderatorLevel || "empty")
+      .addField("~ User level ~", userLevel || "empty")
+      .setThumbnail(client.user.avatarURL)
+      .setFooter(client.user.tag, client.user.avatarURL)
+      .setTimestamp();
+    const userEmbed = new Discord.RichEmbed()
+      .setColor(config.info_color)
+      .setTitle("Command List")
+			.setDescription(`Use \`${config.prefix}help [command name]\` to get information for each command.`)
+      .addField("~ User level ~", userLevel || "empty")
+      .setThumbnail(client.user.avatarURL)
+      .setFooter(client.user.tag, client.user.avatarURL)
+      .setTimestamp();
+
+		const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+		const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+
+		if (message.author.id === config.botOwnerID) {
+			//bot owner
+			return message.channel.send(ownerEmbed);
+		} else if(message.guild == null) {
+			//Direct Message not bot owner
+			return message.channel.send(userEmbed);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+			//mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+			message.channel.send(noServerEmbed);
+			return message.channel.send(adminEmbed)
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+				//inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+					//adminRoleID or modRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+					//user has ADMINISTRATOR permission or has admin role
+					return message.channel.send(adminEmbed);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return message.channel.send(moderatorEmbed);
+				} else {
+					//user didn't have ADMINISTRATOR permission, admin role, nor moderator role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(userEmbed);
+					};
+				}
+			} else {
+				//outside main server and thread server
+				return message.channel.send(userEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/configinfo.js b/commands/configinfo.js
new file mode 100644
index 0000000..c8f233a
--- /dev/null
+++ b/commands/configinfo.js
@@ -0,0 +1,50 @@
+module.exports = {
+	name: 'configinfo',
+  aliases: false,
+  level: 'Admin',
+  guildOnly: true,
+	args: true,
+  usage: '[config name]',
+	description: 'Show a configuration information.',
+	note: 'Config name case is sensitive (upper case and lower case are different).',
+	async execute(param, message, args){
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+    const configInfo = param.configInfo;
+
+		const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+
+    if (message.author.id === config.botOwnerID) {
+			//bot owner
+			return await configInfo.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+			//mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+			message.channel.send(noServerEmbed);
+			return await configInfo.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+				//inside main server or thread server
+				if (config.adminRoleID == "empty"){
+					//adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+					//user has ADMINISTRATOR permission or has admin role
+					return await configInfo.execute(param, message, args);
+				} else {
+					//user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+				//outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/configuration.js b/commands/configuration.js
new file mode 100644
index 0000000..2bb9033
--- /dev/null
+++ b/commands/configuration.js
@@ -0,0 +1,51 @@
+module.exports = {
+	name: 'configuration',
+  aliases: ['config', 'settings'],
+  level: 'Admin',
+  guildOnly: true,
+	args: false,
+  usage: false,
+	description: 'Bot configuration.',
+	note: 'If [mainServerID] and/or [threadServerID] config isn\'t empty, only administrator in that server can use this command.',
+	async execute(param, message, args){
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+    const configuration = param.configuration;
+
+		const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+		const configEmbed = await configuration.execute(param);
+
+    if (message.author.id === config.botOwnerID) {
+			//bot owner
+			return message.channel.send(configEmbed);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+			//mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+			message.channel.send(noServerEmbed);
+			return message.channel.send(configEmbed);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+				//inside main server or thread server
+				if (config.adminRoleID == "empty"){
+					//adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+					//user has ADMINISTRATOR permission or has admin role
+					return message.channel.send(configEmbed);
+				} else {
+					//user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+				//outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/guilds.js b/commands/guilds.js
new file mode 100644
index 0000000..d12640c
--- /dev/null
+++ b/commands/guilds.js
@@ -0,0 +1,52 @@
+module.exports = {
+	name: 'guilds',
+  aliases: ['servers', 'serverlist'],
+  level: 'Admin',
+  guildOnly: true,
+	args: false,
+  usage: false,
+	description: 'List of guilds (servers) that have this bot.',
+	note: 'If [mainServerID] and/or [threadServerID] config isn\'t empty, only administrator in that server can use this command.',
+	async execute(param, message, args){
+    const client = param.client;
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+
+		const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\`` value is empty.");
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const guildList = client.guilds.map(guild => `[**${guild.name}**] (\`${guild.id}\`)`).join("\n") || "This bot hasn't joined any guild yet.";
+    const listEmbed = getEmbed.execute(param, config.info_color, "Guilds", guildList);
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+			return message.channel.send(listEmbed);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+			return message.channel.send(listEmbed);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+					return message.channel.send(listEmbed);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/help.js b/commands/help.js
new file mode 100644
index 0000000..4962bc9
--- /dev/null
+++ b/commands/help.js
@@ -0,0 +1,46 @@
+module.exports = {
+	name: 'help',
+  aliases: false,
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: '[command name]',
+	description: 'Short instruction on how to create a new thread or info on a specific command.',
+	note: 'Command name case is insensitive (upper case and lower case are same).',
+	async execute(param, message, args){
+    const data = [];
+    const commands = param.client.commands;
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Instruction", `In Direct Message, use \`${prefix}new Your thread title here\` to create a new thread (**Thread Created!** will be displayed). You don't need to use any command after your thread created. Describe your issue afterward.`);
+		const notCmdEmbed = getEmbed.execute(param, config.warning_color, "Not a Command", `That\'s not a valid command name or alias.\nUse \`${prefix}commands\` to show available commands.`);
+
+    if(!args.length){
+      return message.channel.send(helpEmbed);
+    }
+
+    const name = args[0].toLowerCase();
+    const command = commands.get(name) || commands.find(cmd => cmd.aliases && cmd.aliases.includes(name));
+
+    if(!command){
+      return message.channel.send(notCmdEmbed);
+    }
+
+    data.push(`**Name** : ${command.name}`);
+    if (command.aliases) data.push(`**Aliases** : ${command.aliases.join(', ')}`);
+		if (command.level) data.push(`**Required Level** : ${command.level}`);
+		if(command.guildOnly){
+			data.push(`**Direct Message** : false`);
+		} else {
+			data.push(`**Direct Message** : true`);
+		}
+    if (command.usage) data.push(`**Usage** : \`${prefix}${command.name} ${command.usage}\``);
+    if (command.description) data.push(`**Description** : ${command.description}`);
+		if (command.note) data.push(`**Note** : \`${command.note}\``);
+
+    const dataEmbed = getEmbed.execute(param, config.info_color, "Command Info", data.join('\n'));
+    return message.channel.send(dataEmbed);
+  }
+};
diff --git a/commands/helpchs.js b/commands/helpchs.js
new file mode 100644
index 0000000..adec3bc
--- /dev/null
+++ b/commands/helpchs.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpchs',
+  aliases: ['助攻'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: '显示如何使用操作这个系统的说明.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "指令", `在“直接消息”中,使用\`${config.prefix}new 您的线程标题在这里\`创建一个新线程(显示“**Thread Created!**”)。创建线程后,无需使用任何命令。然后描述你的问题。`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpcht.js b/commands/helpcht.js
new file mode 100644
index 0000000..b7e9de4
--- /dev/null
+++ b/commands/helpcht.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpcht',
+  aliases: ['助攻'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: '顯示如何使用操作這個系統的說明.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "指令", `在“直接消息”中,使用\`${config.prefix}new 您的線程標題在這裡\`創建一個新線程(顯示“**Thread Created!**”)。創建線程後,無需使用任何命令。然後描述你的問題。`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpde.js b/commands/helpde.js
new file mode 100644
index 0000000..9c19dd4
--- /dev/null
+++ b/commands/helpde.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpde',
+  aliases: ['hilfe'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Anleitung zur Verwendung des Bots anzeigen.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Anweisung", `In Direktnachrichten, Verwenden Sie \`${config.prefix}new Dein Threadtitel hier\`, um einen neuen Thread zu erstellen (es wird **Thread Created!** Angezeigt). Sie müssen nach dem Erstellen Ihres Threads keinen Befehl mehr verwenden. Beschreiben Sie anschließend Ihr Problem.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpes.js b/commands/helpes.js
new file mode 100644
index 0000000..1d1f158
--- /dev/null
+++ b/commands/helpes.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpes',
+  aliases: ['ayuda'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Mostrar instrucciones sobre cómo usar el bot.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Instrucción", `En un mensaje privado, utilice \`${config.prefix}new el tema de su problema\` para crear un nuevo ticket (se muestra **Thread Created!**). No necesita usar ningún comando después de la creación del ticket. Luego describe su problema.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpfr.js b/commands/helpfr.js
new file mode 100644
index 0000000..c13dbc6
--- /dev/null
+++ b/commands/helpfr.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpfr',
+  aliases: ['aide'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Afficher les instructions sur l\'utilisation du bot.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Instruction", `En message privé, utilisez \`${config.prefix}new le sujet de votre problème\` pour créer un nouveau ticket (**Thread Created!** s'affiche). Vous n'avez pas besoin d'utiliser de commande après la création du ticket. Décrivez ensuite votre problème.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpkr.js b/commands/helpkr.js
new file mode 100644
index 0000000..4da61ea
--- /dev/null
+++ b/commands/helpkr.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpkr',
+  aliases: ['도움'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: '봇 사용 방법에 대한 지시 사항 표시.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "훈령", `직접 메시지에서\`${config.prefix}new 스레드 제목은 여기\`를 사용하여 새 스레드를 만듭니다 (**Thread Created!**가 표시됨). 스레드가 작성된 후 명령을 사용할 필요가 없습니다. 그런 다음 문제를 설명하십시오.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helppt.js b/commands/helppt.js
new file mode 100644
index 0000000..8e4e979
--- /dev/null
+++ b/commands/helppt.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helppt',
+  aliases: ['ajuda'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Mostrar instruções sobre como usar o bot.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Instrução", `Na mensagem direta, usar \`${config.prefix}new Título do assunto\` para criar um novo tópico (**Thread Created!** é exibido). Não precisa de usar nenhum comando depois de criar o seu tópico. Em seguida, descreva o seu problema.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helpru.js b/commands/helpru.js
new file mode 100644
index 0000000..af42863
--- /dev/null
+++ b/commands/helpru.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helpru',
+  aliases: ['помощь'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Показать инструкцию о том, как использовать бот.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "инструкция", `В прямом сообщении используйте \`${config.prefix}new Ваше название темы здесь\`, чтобы создать новую тему (**Thread Created!** Отображается). Вам не нужно использовать какую-либо команду после создания вашего потока. Тогда опишите свою проблему.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/helptr.js b/commands/helptr.js
new file mode 100644
index 0000000..6435489
--- /dev/null
+++ b/commands/helptr.js
@@ -0,0 +1,20 @@
+module.exports = {
+	name: 'helptr',
+  aliases: ['yardım'],
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Bot kullanımı hakkında talimat göster.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const prefix = config.prefix;
+    const getEmbed = param.getEmbed;
+
+		const helpEmbed = getEmbed.execute(param, config.info_color, "Talimat", `Doğrudan Mesaj'da, yeni bir bilet oluşturmak için \`${config.prefix}new konuyu buraya yazın\` yazın ve gönderin (**Thread Created!** görüntülenir). Konuyu oluşturduktan sonra herhangi bir komut kullanmanıza gerek yoktur. Daha sonra sorununuzu açıklayın.`);
+
+    return message.channel.send(helpEmbed);
+
+  }
+};
diff --git a/commands/leave.js b/commands/leave.js
new file mode 100644
index 0000000..0a7b3ec
--- /dev/null
+++ b/commands/leave.js
@@ -0,0 +1,38 @@
+module.exports = {
+  name: 'leave',
+  aliases: false,
+  level: 'Owner',
+  guildOnly: false,
+	args: true,
+  usage: '<guildID>',
+  description: 'Leave a guild (server).',
+	note: false,
+  async execute(param, message, args){
+    const client = param.client;
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+
+    const serverID = args.shift();
+    const getServer = client.guilds.get(serverID);
+
+    const notFoundEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Can\'t find guild with ID (\`${serverID}\`) in my collection.`);
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      if(getServer){
+        const successEmbed = getEmbed.execute(param, config.info_color, "Leaving", `Leaving [**${getServer.name}**] (\`${getServer.id}\`) guild.`);
+        console.log(`Leaving [${getServer.name}] guild.`);
+  			return getServer.leave().then(message.channel.send(successEmbed));
+      } else {
+        message.channel.send(notFoundEmbed);
+      }
+		} else {
+      if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+        return;
+      } else {
+        return message.channel.send(noPermEmbed);
+      };
+    };
+  }
+};
diff --git a/commands/new.js b/commands/new.js
new file mode 100644
index 0000000..f5812bd
--- /dev/null
+++ b/commands/new.js
@@ -0,0 +1,44 @@
+module.exports = {
+	name: 'new',
+  aliases: ['neu', 'yeni', '새로운', 'novo', 'nouveau', 'новый', '新', 'nuevo'],
+  level: 'User',
+  guildOnly: false,
+	args: true,
+  usage: '[thread title]',
+	description: 'Create new thread.',
+	note: false,
+	async execute(param, message, args){
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+    const newThread = param.newThread;
+
+    const mainServerID = config.mainServerID;
+    const threadServerID = config.threadServerID;
+    const botChannelID = config.botChannelID;
+    const categoryID = config.categoryID;
+    const logChannelID = config.logChannelID;
+
+    const noServerEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const notDMEmbed = getEmbed.execute(param, config.error_color, "Command Unavailable", "This command can only be used in Direct Message.")
+
+		if (message.guild != null && (message.guild.id == mainServerID || message.guild.id == threadServerID)) {
+      if(botChannelID != "empty" && message.channel.id == botChannelID){
+        return;
+      } else {
+				return message.channel.send(notDMEmbed);
+			}
+    } else if(message.guild != null){
+      return message.channel.send(notDMEmbed);
+    } else {
+      if(mainServerID == "empty" || threadServerID == "empty"){
+        return message.channel.send(noServerEmbed);
+      } else if (categoryID == "empty" || logChannelID == "empty"){
+        return message.channel.send(noChannelEmbed);
+      } else {
+        return newThread.execute(param, message, args);
+      }
+    }
+
+  }
+};
diff --git a/commands/ping.js b/commands/ping.js
new file mode 100644
index 0000000..4fb22f5
--- /dev/null
+++ b/commands/ping.js
@@ -0,0 +1,30 @@
+module.exports = {
+	name: 'ping',
+  aliases: false,
+  level: 'User',
+  guildOnly: false,
+	args: false,
+  usage: false,
+	description: 'Calculate bot latency.',
+	note: false,
+	async execute(param, message, args){
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+
+		if(config.mainServerID != "empty" && config.threadServerID != "empty"){
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+				if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+					return;
+				}
+			}
+		}
+
+
+    let pingEmbed = getEmbed.execute(param, config.info_color, "Pong", "Ping?");
+
+		message.channel.send(pingEmbed).then((msg) => {
+			let editEmbed = getEmbed.execute(param, config.info_color, "Pong", `**Response time** : **${msg.createdTimestamp - message.createdTimestamp}** ms\n**API latency** : **${Math.round(param.client.ping)}** ms`);
+			msg.edit(editEmbed);
+    });
+  }
+};
diff --git a/commands/reload.js b/commands/reload.js
new file mode 100644
index 0000000..829bda2
--- /dev/null
+++ b/commands/reload.js
@@ -0,0 +1,43 @@
+module.exports = {
+  name: 'reload',
+  aliases: false,
+  level: 'Owner',
+  guildOnly: false,
+	args: true,
+  usage: '[command name]',
+  description: 'Reload a command.',
+	note: false,
+  async execute(param, message, args){
+    const client = param.client;
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+
+    const commandName = args.shift().toLowerCase();
+    const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
+
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `Command \`${command.name}\` was reloaded.`);
+    const notCmdEmbed = getEmbed.execute(param, config.error_color, "Not a Command", `That\'s not a valid command name or alias.\nUse \`${config.prefix}commands\` to show available commands.`);
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      if(!command){
+        return message.channel.send(notCmdEmbed);
+      }
+      console.log(`Deleting ${command.name} cache.`);
+      delete require.cache[require.resolve(`./${command.name}.js`)];
+
+      console.log(`Loading ${command.name}...`)
+      const newCommand = require(`./${command.name}.js`);
+	    client.commands.set(newCommand.name, newCommand);
+
+			return message.channel.send(successEmbed);
+		} else {
+      if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+  			return;
+  		} else {
+  			return message.channel.send(noPermEmbed);
+  		};
+    }
+  }
+};
diff --git a/commands/reply.js b/commands/reply.js
new file mode 100644
index 0000000..e02733f
--- /dev/null
+++ b/commands/reply.js
@@ -0,0 +1,70 @@
+module.exports = {
+	name: 'reply',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: false,//in case only attachment no message
+  usage: '[reply message]',
+	description: 'Reply to a user thread.',
+  note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const reply = param.reply;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+    const notChannelEmbed = getEmbed.execute(param, config.error_color, "Invalid Channel", `This isn\'t thread channel.`);
+		const noArgsEmbed = param.getEmbed.execute(param, config.warning_color, "Missing Arguments", `You didn\'t provide any arguments nor attachments.`);
+
+    //Yes i know it's nasty to look at that many nested if else but it's needed @,@
+    if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      return message.channel.send(noServerEmbed);
+		} else {
+			if(message.guild.id == config.threadServerID){
+        //inside thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID or modRoleID empty
+					return message.channel.send(noAdminEmbed);
+				} else if(config.categoryID == "empty" || config.logChannelID == "empty"){
+          //categoryID or logChannelID empty
+          return message.channel.send(noChannelEmbed);
+        } else {
+          //adminRoleID, modRoleID, categoryID and logChannelID not empty
+          if (message.channel.parentID != config.categoryID || message.channel.id == config.logChannelID || message.channel.id == config.botChannelID) {
+            //the channel isn't under modmail category or it's a log channel or it's bot channel -_-
+            return message.channel.send(notChannelEmbed);
+          } else {
+            //the channel is under modmail category, it's not a log channel, and it's not bot channel
+						if(!args.length && message.attachments.size == 0){
+							return message.channel.send(noArgsEmbed);
+						} else if(message.author.id == config.botOwnerID){
+              return reply.execute(param, message, args);
+            } else if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+              //user has ADMINISTRATOR permission or has admin role
+              return reply.execute(param, message, args);
+    				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+    					//user has moderator role
+              return reply.execute(param, message, args);
+    				} else {
+    					//user didn't have ADMINISTRATOR permission nor has admin role
+    					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+    						return;
+    					} else {
+    						return message.channel.send(noPermEmbed);
+    					};
+    				}
+
+          }
+        }
+
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/reset.js b/commands/reset.js
new file mode 100644
index 0000000..38cd222
--- /dev/null
+++ b/commands/reset.js
@@ -0,0 +1,67 @@
+module.exports = {
+  name: 'reset',
+  aliases: false,
+  level: 'Admin',
+  guildOnly: true,
+	args: false,
+  usage: false,
+  description: 'Reset all configuration values.',
+	note: false,
+  async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const reset = param.reset;
+
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `All configuration value have been reset to default.`);
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      console.log("Resetting bot configuration...");
+			await reset.execute(param).then(()=>{
+        message.channel.send(successEmbed).then(() =>{
+          process.exit(1);
+        });
+      });
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      //reset and restart the bot
+      console.log("Resetting bot configuration...");
+			await reset.execute(param).then(()=>{
+        message.channel.send(successEmbed).then(() =>{
+          process.exit(1);
+        });
+      });
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          console.log("Resetting bot configuration...");
+					await reset.execute(param).then(()=>{
+            message.channel.send(successEmbed).then(() =>{
+              process.exit(1);
+            });
+          });
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+          if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+      			return;
+      		} else {
+      			return message.channel.send(noPermEmbed);
+      		};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/restart.js b/commands/restart.js
new file mode 100644
index 0000000..b3f4941
--- /dev/null
+++ b/commands/restart.js
@@ -0,0 +1,59 @@
+module.exports = {
+	name: 'restart',
+	aliases: ['reboot'],
+  level: 'Admin',
+  guildOnly: true,
+	args: false,
+  usage: false,
+	description: 'Restart the bot.',
+	note: false,
+	async execute(param, message, args) {
+		const config = param.config;
+		const getEmbed = param.getEmbed;
+
+		const successEmbed = getEmbed.execute(param, config.info_color, "Restarting", `**Restarting in** : **${Math.round(param.client.ping)}** ms`);
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+		const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+		const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+
+		if (message.author.id === config.botOwnerID) {
+			//bot owner
+      console.log("Restarting bot...");
+			message.channel.send(successEmbed).then(() => {
+				process.exit(1);
+			});
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+			//mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+			message.channel.send(noServerEmbed);
+      console.log("Restarting bot...");
+			message.channel.send(successEmbed).then(() => {
+				process.exit(1);
+			});
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+				//inside main server or thread server
+				if (config.adminRoleID == "empty"){
+					//adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+					//user has ADMINISTRATOR permission or has admin role
+		      console.log("Restarting bot...");
+					message.channel.send(successEmbed).then(() => {
+						process.exit(1);
+					});
+				} else {
+					//user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+				//outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+	}
+};
diff --git a/commands/set.js b/commands/set.js
new file mode 100644
index 0000000..4dfd8d5
--- /dev/null
+++ b/commands/set.js
@@ -0,0 +1,50 @@
+module.exports = {
+  name: 'set',
+  aliases: false,
+  level: 'Admin',
+  guildOnly: true,
+	args: true,
+  usage: '[config name] [value]',
+  description: 'Set specific configuration value.',
+	note: 'Config name case is sensitive (upper case and lower case are different).',
+  async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const set = param.set;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+			return await set.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+			//mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+			message.channel.send(noServerEmbed);
+			return await set.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty"){
+					//adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+					return await set.execute(param, message, args);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+          if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+      			return;
+      		} else {
+      			return message.channel.send(noPermEmbed);
+      		};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/threadinfo.js b/commands/threadinfo.js
new file mode 100644
index 0000000..e905773
--- /dev/null
+++ b/commands/threadinfo.js
@@ -0,0 +1,55 @@
+module.exports = {
+	name: 'threadinfo',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '[<userID> or <channelID>]',
+	description: 'Show a user thread information.',
+  note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const threadInfo = param.threadInfo;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Configuration Needed", "\`categoryID\` and/or \`logChannelID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+    const notChannelEmbed = getEmbed.execute(param, config.error_color, "Invalid Channel", `This isn\'t thread channel.`);
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      return threadInfo.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      return threadInfo.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          return threadInfo.execute(param, message, args);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return threadInfo.execute(param, message, args);
+				} else {
+					//user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/commands/unblock.js b/commands/unblock.js
new file mode 100644
index 0000000..febd103
--- /dev/null
+++ b/commands/unblock.js
@@ -0,0 +1,53 @@
+module.exports = {
+	name: 'unblock',
+  aliases: false,
+  level: 'Moderator',
+  guildOnly: true,
+	args: true,
+  usage: '<userID>',
+	description: 'Unblock user from creating new thread.',
+	note: false,
+	async execute(param, message, args){
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const unblock = param.unblock;
+
+		const noPermEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", "You don\'t have permission to run this command.");
+    const noServerEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noAdminEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", "\`adminRoleID\` and/or \`modRoleID\` value is empty.");
+
+    if (message.author.id === config.botOwnerID) {
+      //bot owner
+      return unblock.execute(param, message, args);
+		} else if (config.mainServerID == "empty" && config.threadServerID == "empty" && message.member.hasPermission("ADMINISTRATOR")) {
+      //mainServerID and threadServerID empty and user has ADMINISTRATOR permission
+      message.channel.send(noServerEmbed);
+      return unblock.execute(param, message, args);
+		} else {
+			if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+        //inside main server or thread server
+				if (config.adminRoleID == "empty" || config.modRoleID == "empty"){
+          //adminRoleID empty
+					message.channel.send(noAdminEmbed);
+				}
+				if (message.member.hasPermission("ADMINISTRATOR") || await param.roleCheck.execute(message, config.adminRoleID)){
+          //user has ADMINISTRATOR permission or has admin role
+          return unblock.execute(param, message, args);
+				} else if (await param.roleCheck.execute(message, config.modRoleID)){
+					//user has moderator role
+					return unblock.execute(param, message, args);
+				} else {
+          //user didn't have ADMINISTRATOR permission nor has admin role
+					if (config.botChannelID != "empty" && message.channel.id != config.botChannelID) {
+						return;
+					} else {
+						return message.channel.send(noPermEmbed);
+					};
+				}
+			} else {
+        //outside main server and thread server
+				return message.channel.send(noPermEmbed);
+			}
+		};
+  }
+};
diff --git a/config.json b/config.json
index 53caf73..ac52a5b 100644
--- a/config.json
+++ b/config.json
@@ -1,12 +1,14 @@
 {
 	"prefix" : "=",
-	"botOwnerID" : "",
-	"serverID" : "",
+	"botOwnerID" : "384304943516876801",
+  "mainServerID" : "",
+  "threadServerID" : "",
 	"categoryID" : "",
 	"logChannelID" : "",
 	"adminRoleID" : "",
 	"modRoleID" : "",
 	"mentionedRoleID" : "here",
+	"botChannelID" : "",
 	"maintenance" : "0",
 	"info_color" : "#add8e6",
 	"warning_color" : "#ffff00",
diff --git a/functions/aclose.js b/functions/aclose.js
new file mode 100644
index 0000000..9a3f3db
--- /dev/null
+++ b/functions/aclose.js
@@ -0,0 +1,73 @@
+module.exports = {
+  name: "aclose",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const categoryID = config.categoryID;
+    const logChannelID = config.logChannelID;
+    const logChannel = await threadServer.channels.get(logChannelID);
+    const author = message.author;
+    const channel = message.channel;
+
+    const isThread = await ThreadDB.findOne({where: {channelID: channel.id}});
+    let addSpace = args.join(' ');
+    let deleteSeparator = addSpace.split(/-+/);
+    const reason = deleteSeparator.shift();
+    const note = deleteSeparator.shift() || "empty";
+
+    const noThreadEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find any thread asociated with this channel.`);
+
+    if (!isThread) {
+      return channel.send(noThreadEmbed);
+    } else {
+      const user = await client.users.get(isThread.userID);
+      const logDescription = `${isThread.threadTitle}\n**Reason** : ${reason}\n**Note** : ${note}`;
+      const userDescription = `${isThread.threadTitle}\n**Reason** : ${reason}`;
+
+      var logEmbed;
+      const userDMEmbed = new Discord.RichEmbed()
+        .setColor(config.warning_color)
+        .setAuthor("[Anonymous]")
+        .setTitle("Thread Closed")
+        .setDescription(userDescription)
+        .setFooter(mainServer.name, mainServer.avatarURL)
+        .setTimestamp();
+
+      if (user) {
+        logEmbed = new Discord.RichEmbed()
+          .setColor(config.warning_color)
+          .setAuthor(`[Anonymous] | ${author.tag}`, author.avatarURL)
+          .setTitle("Thread Closed")
+          .setDescription(logDescription)
+          .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
+          .setTimestamp();
+        await user.send(userDMEmbed);
+        await logChannel.send(logEmbed);
+      } else {
+        logEmbed = new Discord.RichEmbed()
+          .setColor(config.warning_color)
+          .setAuthor(`[Anonymous] | ${author.tag}`, author.avatarURL)
+          .setTitle("Thread Closed")
+          .setDescription(logDescription)
+          .setFooter(`Can\'t find user | ${isThread.userID}`)
+          .setTimestamp();
+        await logChannel.send(logEmbed);
+      }
+
+      const rowCount = await ThreadDB.destroy({ where: {userID: isThread.userID} });
+      if (rowCount > 0) {
+        console.log(`Closing Thread.`);
+      }
+      return channel.delete();
+    };
+
+  }
+};
diff --git a/functions/areply.js b/functions/areply.js
new file mode 100644
index 0000000..a11c5c5
--- /dev/null
+++ b/functions/areply.js
@@ -0,0 +1,85 @@
+module.exports = {
+  name: "areply",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const Attachment = param.Attachment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+    const isMember = param.isMember;
+    const isBlocked = param.isBlocked;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const categoryID = config.categoryID;
+    const author = message.author;
+    const channel = message.channel;
+
+    const isThread = await ThreadDB.findOne({where: {channelID: channel.id}});
+    const checkIsBlocked = await isBlocked.execute(param, author.id);
+
+    const blockedEmbed = getEmbed.execute(param, config.error_color, "Blocked", `User blocked.`);
+    const noDMEmbed = getEmbed.execute(param, config.error_color, "Not Sent", `User disabled Direct Message.`);
+    const noUserEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find user in my collection.`);
+    const noThreadEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find any thread asociated with this channel.`);
+
+    if (!isThread) {
+      return channel.send(noThreadEmbed);
+    } else {
+      const checkIsMember = await isMember.execute(param, author.id);
+      const notMemberEmbed = getEmbed.execute(param, config.error_color, "Not a Member", `User aren\'t inside [**${mainServer.name}**] guild.`);
+
+      if (!checkIsMember) {
+        return channel.send(notMemberEmbed);
+      } else if (checkIsBlocked){
+        return channel.send(blockedEmbed);
+      } else {
+        const userID = isThread.userID;
+        const member = await mainServer.members.get(userID);
+
+        if (!member) {
+          return channel.send(noUserEmbed);
+        } else {
+          const user = member.user;
+          const description = args.join(' ');
+          const userDMEmbed = new Discord.RichEmbed()
+            .setColor(config.sent_color)
+            .setAuthor("[Anonymous]")
+            .setTitle("Message Received")
+            .setDescription(description)
+            .setFooter(mainServer.name, mainServer.avatarURL)
+            .setTimestamp();
+          const threadChannelEmbed = new Discord.RichEmbed()
+            .setColor(config.sent_color)
+            .setAuthor(`[Anonymous] | ${author.tag}`, author.avatarURL)
+            .setTitle("Message Sent")
+            .setDescription(description)
+            .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
+            .setTimestamp();
+
+          try{
+            await user.send(userDMEmbed);
+          } catch (error){
+            if(error.message == "Cannot send messages to this user"){
+              return channel.send(noDMEmbed);
+            }
+          }
+          await channel.send(threadChannelEmbed);
+          if (message.attachments.size > 0) {
+            await message.attachments.forEach(async atch => {
+              let attachment = new Attachment(atch.url);
+              await user.send(attachment);
+              await channel.send(attachment);
+            });
+          }
+          return message.delete();
+        }
+
+      };
+    };
+
+  }
+};
diff --git a/functions/bind.js b/functions/bind.js
new file mode 100644
index 0000000..5ce9621
--- /dev/null
+++ b/functions/bind.js
@@ -0,0 +1,43 @@
+module.exports = {
+  name: "bind",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const moment = param.moment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+    const bind = param.bind;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+
+    const userID = args.shift();
+    const channelID = args.shift();
+    const isThread = await ThreadDB.findOne({where: {userID: userID}});
+    const isSame = await ThreadDB.findOne({where: {channelID: channelID}});
+
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `Binded <@${userID}> (\`${userID}\`) thread to <#${channelID}>.`);
+    const sameChannelEmbed = getEmbed.execute(param, config.error_color, "Failed", `Channel <#${channelID}> binded with a thread already.`);
+
+    if (isSame) {
+      return message.channel.send(sameChannelEmbed);
+    } else if(!isThread){
+      const newThread = await ThreadDB.create({
+        userID: userID,
+        channelID: channelID,
+        threadTitle: "empty"
+      });
+      return message.channel.send(successEmbed);
+    } else {
+      await ThreadDB.update(
+        { channelID: channelID },
+        { where: { userID: userID } }
+      );
+      return message.channel.send(successEmbed);
+    };
+
+  }
+};
diff --git a/functions/block.js b/functions/block.js
new file mode 100644
index 0000000..5cd46fa
--- /dev/null
+++ b/functions/block.js
@@ -0,0 +1,33 @@
+module.exports = {
+	name: "block",
+	async execute(param, message, args){
+    const client = param.client;
+    const config = param.config;
+    const BlockedDB = param.BlockedDB;
+		const getEmbed = param.getEmbed;
+
+    const modID = message.author.id;
+    const userID = args.shift();
+    const reason = args.join(' ') || "empty";
+
+    const duplicatedEmbed = getEmbed.execute(param, config.error_color, "Duplicated", `<@${userID}> (\`${userID}\`) already blocked.`);
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `Succesfully block <@${userID}> (\`${userID}\`).`);
+
+    try{
+      const blockThis = await BlockedDB.create({
+        userID: userID,
+        modID: modID,
+        reason: reason
+      });
+      if(blockThis){
+        console.log(`Blocked [${userID}]`);
+        return message.channel.send(successEmbed);
+      }
+    } catch (error) {
+      if(error.name == "SequelizeUniqueConstraintError"){
+        return message.channel.send(duplicatedEmbed);
+      }
+    };
+
+  }
+};
diff --git a/functions/blockinfo.js b/functions/blockinfo.js
new file mode 100644
index 0000000..32c7951
--- /dev/null
+++ b/functions/blockinfo.js
@@ -0,0 +1,30 @@
+module.exports = {
+	name: "blockinfo",
+	async execute(param, message, args){
+    const moment = param.moment;
+    const client = param.client;
+    const config = param.config;
+    const BlockedDB = param.BlockedDB;
+		const getEmbed = param.getEmbed;
+
+    const userID = args.shift();
+
+    const notFoundEmbed = getEmbed.execute(param, config.error_color, "Not Found", `<@${userID}> (\`${userID}\`) isn\'t blocked.`);
+
+    const findUser = await BlockedDB.findOne({where: {userID: userID}});
+    if(findUser){
+      const data = [];
+      data.push(`**User** : <@${findUser.userID}>`);
+      data.push(`**User ID** : \`${findUser.userID}\``);
+      data.push(`**Blocked at** : ${moment(findUser.createdAt).format("D MMMM YYYY, **HH:mm:ss** UTC")}`);
+      data.push(`**Moderator** : <@${findUser.modID}>`);
+      data.push(`**Moderator ID** : \`${findUser.modID}\``);
+      data.push(`**Reason** : ${findUser.reason}`);
+      const infoEmbed = getEmbed.execute(param, config.info_color, "Block Info", data.join('\n'));
+      return message.channel.send(infoEmbed);
+    } else {
+      return message.channel.send(notFoundEmbed);
+    }
+
+  }
+};
diff --git a/functions/blocklist.js b/functions/blocklist.js
new file mode 100644
index 0000000..f05549c
--- /dev/null
+++ b/functions/blocklist.js
@@ -0,0 +1,41 @@
+module.exports = {
+	name: "blocklist",
+	async execute(param, message, args){
+    const moment = param.moment;
+    const client = param.client;
+    const config = param.config;
+    const BlockedDB = param.BlockedDB;
+		const getEmbed = param.getEmbed;
+
+    var pageNumber = args.shift();
+
+    const blocklist = await BlockedDB.findAll({ attributes: ["userID", "createdAt"] });
+    var pages = Math.floor(blocklist.length / 20);
+    if (blocklist.length % 20 != 0) {
+      //add 1 number of pages if residual quotient is not 0 (15%10=5 -> 5 > 0)
+      pages += 1;
+    }
+    if (blocklist.length == 0) {
+      pageNumber = 0;
+    } else if(!pageNumber || isNaN(pageNumber) || pageNumber <= 0) {
+      //user didn't gave input or input is not a number or input is below or same as 0
+      pageNumber = 1;
+    } else if(pageNumber > pages){
+      //input is higher than the number of pages
+      pageNumber = pages;
+    }
+
+    const listArray = blocklist.map(block =>`**[${moment(block.createdAt).format("D MMM YYYY")}]** <@${block.userID}> \`(${block.userID})\``);
+    const firstIndex = Math.abs((pageNumber-1) * 20);
+    let listString = listArray.slice(firstIndex, firstIndex + 20).join("\n") || `\`List empty.\``;
+    if (pages > 1) {
+      listString += `\n\`Page ${pageNumber} from ${pages} pages\``;
+    } else {
+      listString += `\n\`Page ${pageNumber} from ${pages} page\``;
+    }
+
+    const listEmbed = getEmbed.execute(param, config.info_color, "Blocked Users", listString);
+    return message.channel.send(listEmbed);
+
+  }
+};
diff --git a/functions/close.js b/functions/close.js
new file mode 100644
index 0000000..7cbe8dd
--- /dev/null
+++ b/functions/close.js
@@ -0,0 +1,73 @@
+module.exports = {
+  name: "close",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const categoryID = config.categoryID;
+    const logChannelID = config.logChannelID;
+    const logChannel = await threadServer.channels.get(logChannelID);
+    const author = message.author;
+    const channel = message.channel;
+
+    const isThread = await ThreadDB.findOne({where: {channelID: channel.id}});
+    let addSpace = args.join(' ');
+    let deleteSeparator = addSpace.split(/-+/);
+    const reason = deleteSeparator.shift();
+    const note = deleteSeparator.shift() || "empty";
+
+    const noThreadEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find any thread asociated with this channel.`);
+
+    if (!isThread) {
+      return channel.send(noThreadEmbed);
+    } else {
+      const user = await client.users.get(isThread.userID);
+      const logDescription = `${isThread.threadTitle}\n**Reason** : ${reason}\n**Note** : ${note}`;
+      const userDescription = `${isThread.threadTitle}\n**Reason** : ${reason}`;
+
+      var logEmbed;
+      const userDMEmbed = new Discord.RichEmbed()
+        .setColor(config.warning_color)
+        .setAuthor(author.tag, author.avatarURL)
+        .setTitle("Thread Closed")
+        .setDescription(userDescription)
+        .setFooter(mainServer.name, mainServer.avatarURL)
+        .setTimestamp();
+
+      if (user) {
+        logEmbed = new Discord.RichEmbed()
+          .setColor(config.warning_color)
+          .setAuthor(author.tag, author.avatarURL)
+          .setTitle("Thread Closed")
+          .setDescription(logDescription)
+          .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
+          .setTimestamp();
+        await user.send(userDMEmbed);
+        await logChannel.send(logEmbed);
+      } else {
+        logEmbed = new Discord.RichEmbed()
+          .setColor(config.warning_color)
+          .setAuthor(author.tag, author.avatarURL)
+          .setTitle("Thread Closed")
+          .setDescription(logDescription)
+          .setFooter(`Can\'t find user | ${isThread.userID}`)
+          .setTimestamp();
+        await logChannel.send(logEmbed);
+      }
+
+      const rowCount = await ThreadDB.destroy({ where: {userID: isThread.userID} });
+      if (rowCount > 0) {
+        console.log(`Closing Thread.`);
+      }
+      return channel.delete();
+    };
+
+  }
+};
diff --git a/functions/configInfo.js b/functions/configInfo.js
new file mode 100644
index 0000000..a157714
--- /dev/null
+++ b/functions/configInfo.js
@@ -0,0 +1,96 @@
+module.exports = {
+  name: "configInfo",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const moment = param.moment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ConfigDB = param.ConfigDB;
+
+    const configName = args.shift();
+    const isConfig = await ConfigDB.findOne({where: {name: configName}});
+    const configCollection = await ConfigDB.findAll({ attributes: ["name"] });
+    const configList = configCollection.map(conf => `\`${conf.name}\``).join(', ');
+
+    const noConfigEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find config named \`${configName}\`.\nAvailable names : ${configList}`);
+
+    var configData = [];
+    if (configName == "prefix") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : To differentiate between a command and non command.`);
+      configData.push(`**Requirements** : \n\`> Any input that didn\'t have [space] as it\'ll be ignored.\``);
+    } else if(configName == "botOwnerID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : An owner of this bot can use any commands anywhere.`);
+      configData.push(`**Requirements** : \n\`> Only bot owner can change this value.\n> Input can\'t be empty.\``);
+    } else if(configName == "mainServerID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : The server that is used by users who will use this bot to ask moderators.`);
+      configData.push(`**Requirements** : \n\`> Any server that have this bot.\n> Value can be same as [threadServerID].\``);
+    } else if(configName == "threadServerID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : The server where thread channels will be on.`);
+      configData.push(`**Requirements** : \n\`> Any server that have this bot.\n> Value can be same as [mainServerID].\``);
+    } else if(configName == "categoryID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Category channel where thread channels will be created.`);
+      configData.push(`**Requirements** : \n\`> Any category channel that are inside thread server.\n> [threadServerID] value can\'t be empty.\``);
+      configData.push(`**Note** : To understand what category channel is, check (<https://support.discordapp.com/hc/en-us/articles/115001580171-Channel-Categories-101>).`);
+      configData.push(`\`ps. Discord.js treat it as channel that\'s why i use this term too.\``);
+    } else if(configName == "logChannelID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Channel where thread logs will be sent.`);
+      configData.push(`**Requirements** : \n\`> Any channel inside thread server.\n> [threadServerID] value can\'t be empty.\``);
+    } else if(configName == "adminRoleID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Role that will have administrator permission level.`);
+      configData.push(`**Requirements** : \n\`> Any role inside thread server.\n> [threadServerID] value can\'t be empty.\``);
+    } else if(configName == "modRoleID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Role that will have moderator permission level.`);
+      configData.push(`**Requirements** : \n\`> Any role inside thread server.\n> [threadServerID] value can\'t be empty.\``);
+    } else if(configName == "mentionedRoleID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : The role that will be mentioned on new thread.`);
+      configData.push(`**Requirements** : \n\`> Can be empty (no one mentioned).\n> Any role at thread server including here and everyone [set mentionedRoleID everyone].\``);
+    } else if(configName == "botChannelID") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Channel where user can only use to execute commands (any commands in other channels will be ignored except help commands).`);
+      configData.push(`**Requirements** : \n\`> Can be empty (everyone can use any commands anywhere).\n> Any channels inside main server.\n> Should\'t be a category channel (Discord.js treat categories as a channel too).\``);
+    } else if(configName == "maintenance") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Maintenance mode toggle. Config changed according previous value.`);
+    } else if(configName == "info_color") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Color used for any information related embeds.`);
+      configData.push(`**Requirements** : \n\`> Hex code color input.\``);
+    } else if(configName == "warning_color") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Color used for any warning related embeds.`);
+      configData.push(`**Requirements** : \`.\``);
+    } else if(configName == "error_color") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Color used for any error related embeds.`);
+      configData.push(`**Requirements** : \`.\``);
+    } else if(configName == "sent_color") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Color used for any message sent on threads related embeds.`);
+      configData.push(`**Requirements** : \`.\``);
+    } else if(configName == "received_color") {
+      configData.push(`**Name** : ${configName}`);
+      configData.push(`**Description** : Color used for any message received on threads related embeds.`);
+      configData.push(`**Requirements** : \`.\``);
+    } else {
+      configData.push(`\`Information is still not available.\``);
+    }
+    const dataEmbed = await getEmbed.execute(param, config.info_color, "Configuration Information", configData.join('\n'));
+
+    if (!isConfig) {
+      return message.channel.send(noConfigEmbed);
+    } else {
+      return message.channel.send(dataEmbed);
+    };
+
+  }
+};
diff --git a/functions/configSync.js b/functions/configSync.js
new file mode 100644
index 0000000..0314d9c
--- /dev/null
+++ b/functions/configSync.js
@@ -0,0 +1,38 @@
+module.exports = {
+  name: "configSync",
+  async execute(param){
+    const config = param.config;
+    const ConfigDB = param.ConfigDB;
+    const user = param.client.user;
+
+    console.log("[Syncing Configuration]")
+    user.setActivity("Syncing...", { type: "WATCHING" });
+    let configKeys = Object.keys(config);
+    var syncPromise = new Promise(resolve => {
+      try {
+        async function forLoop(){
+          for (var i = 0; i < configKeys .length; i++) {
+            let getConfig = await ConfigDB.findOne({ where: { name: configKeys[i] } });
+            if(getConfig){
+              console.log(`Syncing ${getConfig.name}...`)
+              config[configKeys[i]] = getConfig.input || "empty";
+            } else {
+              //resolved too cause im still confused with reject()
+              console.log("Calling reset function...")
+              await param.reset.execute(param);
+              break;
+            }
+          }
+          resolve();
+        }
+        forLoop();
+      } catch (error) {
+        return console.log(error);
+      }
+    });
+    syncPromise.then(() => {
+      console.log("[Synced]");
+      user.setActivity("[Ready]", { type: "WATCHING" });
+    });
+  }
+};
diff --git a/functions/configuration.js b/functions/configuration.js
new file mode 100644
index 0000000..3eb2cb3
--- /dev/null
+++ b/functions/configuration.js
@@ -0,0 +1,48 @@
+module.exports = {
+  name: "configuration",
+  async execute(param){
+    const Discord = param.Discord;
+    const client = param.client;
+    const config = param.config;
+    const configKeys = Object.keys(config); //getting the name of each config (prefix, botOwnerID, etc)
+    let botConfig = [];
+    let serverConfig = [];
+    let embedColorConfig = [];
+    let botOwnerIDIndex = ""; //As separator for server related config and bot config.
+    let maintenanceIndex = ""; //As separator for server related config and embed color config.
+
+    //getting the index first for separator
+    for (var i = 0; i < configKeys.length; i++) {
+      if(configKeys[i] == "botOwnerID"){
+        botOwnerIDIndex = i;
+      } else if(configKeys[i] == "maintenance"){
+        maintenanceIndex = i;
+      }
+    };
+
+    for (var i = 0; i < configKeys.length; i++) {
+      if(configKeys[i] == "prefix"){
+        botConfig.push(`${configKeys[i]} : \`${config[configKeys[i]]}\``);
+      } else if(configKeys[i] == "botOwnerID"){
+        botConfig.push(`${configKeys[i]} : \`${config[configKeys[i]]}\``);
+      } else if(i > botOwnerIDIndex && i < maintenanceIndex){
+        serverConfig.push(`${configKeys[i]} : \`${config[configKeys[i]]}\``);
+      } else if(configKeys[i] == "maintenance"){
+        botConfig.push(`${configKeys[i]} : \`${config[configKeys[i]]}\``);
+      } else if(i > maintenanceIndex && i < configKeys.length){
+        embedColorConfig.push(`${configKeys[i]} : \`${config[configKeys[i]]}\``);
+      }
+    };
+
+    const configEmbed = new Discord.RichEmbed()
+      .setColor(config.info_color)
+      .setTitle("Configuration")
+      .addField("~ Bot ~", botConfig)
+      .addField("~ Server ~", serverConfig)
+      .addField("~ Embed Color ~", embedColorConfig)
+      .setThumbnail(client.user.avatarURL)
+      .setFooter(client.user.tag, client.user.avatarURL)
+      .setTimestamp();
+    return configEmbed;
+  }
+};
diff --git a/functions/getEmbed.js b/functions/getEmbed.js
new file mode 100644
index 0000000..c4b5ecb
--- /dev/null
+++ b/functions/getEmbed.js
@@ -0,0 +1,12 @@
+module.exports = {
+  name: "getEmbed",
+  execute(param, color, title, description){
+    const embed = new param.Discord.RichEmbed()
+      .setColor(color)
+      .setTitle(title)
+      .setDescription(description)
+      .setFooter(param.client.user.tag, param.client.user.avatarURL)
+      .setTimestamp();
+    return embed;
+  }
+};
diff --git a/functions/isBlocked.js b/functions/isBlocked.js
new file mode 100644
index 0000000..b1258c5
--- /dev/null
+++ b/functions/isBlocked.js
@@ -0,0 +1,13 @@
+module.exports = {
+  name: "isBlocked",
+  async execute(param, userID){
+    const BlockedDB = param.BlockedDB;
+    const isBlocked = await BlockedDB.findOne({ where: {userID: userID} });
+
+    if(isBlocked){
+      return true;
+    } else {
+      return false;
+    }
+  }
+};
diff --git a/functions/isMember.js b/functions/isMember.js
new file mode 100644
index 0000000..2f99878
--- /dev/null
+++ b/functions/isMember.js
@@ -0,0 +1,15 @@
+module.exports = {
+  name: "isMember",
+  async execute(param, userID){
+    const client = param.client;
+    const mainServerID = param.config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const isMember = await mainServer.members.get(userID);
+
+    if(isMember){
+      return true;
+    } else {
+      return false;
+    }
+  }
+};
diff --git a/functions/newThread.js b/functions/newThread.js
new file mode 100644
index 0000000..dcf6e85
--- /dev/null
+++ b/functions/newThread.js
@@ -0,0 +1,106 @@
+module.exports = {
+  name: "newThread",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const Attachment = param.Attachment;
+    const moment = param.moment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+    const isMember = param.isMember;
+    const isBlocked = param.isBlocked;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const categoryID = config.categoryID;
+    const categoryChannel = await threadServer.channels.get(categoryID);
+    const logChannelID = config.logChannelID;
+    const logChannel = await threadServer.channels.get(logChannelID);
+    const author = message.author;
+    const mentionedRoleID = config.mentionedRoleID;
+
+    let mentionedRole = "";
+    if (mentionedRoleID == "everyone" || mentionedRoleID == "here") {
+      mentionedRole = "@" + mentionedRoleID;
+    } else if (config.mentionedRoleID != null && config.mentionedRoleID != "empty") {
+      mentionedRole = "<@&" + mentionedRoleID + ">";
+    }
+
+    const isThread = await ThreadDB.findOne({where: {userID: author.id}});
+    const checkIsMember = await isMember.execute(param, author.id);
+    const checkIsBlocked = await isBlocked.execute(param, author.id);
+
+    const notMemberEmbed = getEmbed.execute(param, config.error_color, "Not a Member", `You aren\'t inside [**${mainServer.name}**] guild.`);
+    const blockedEmbed = getEmbed.execute(param, config.error_color, "Blocked", `You are blocked from creating new thread.`);
+    const isThreadEmbed = getEmbed.execute(param, config.error_color, "Thread Detected", `You still have open thread.`);
+
+    if (isThread) {
+      return message.channel.send(isThreadEmbed);
+    } else {
+      if (!checkIsMember) {
+        return message.channel.send(notMemberEmbed);
+      } else if (checkIsBlocked){
+        return message.channel.send(blockedEmbed);
+      } else {
+        const newChannel = await threadServer.createChannel(author.tag.replace("#", "-"), { type: "text" });
+        await newChannel.setParent(categoryID); //move the channel under category channel
+        await newChannel.lockPermissions(); //inherit category channel permission
+
+        let logEmbed = new Discord.RichEmbed()
+          .setColor(config.info_color)
+          .setTitle("New Thread")
+          .setDescription(`${args.join(' ')}`)
+          .setFooter(`${author.tag} | ${author.id}`, author.avatarURL)
+          .setTimestamp();
+        logChannel.send(logEmbed);
+
+        let dmEmbed = new Discord.RichEmbed()
+          .setColor(config.info_color)
+          .setTitle("Thread Created!")
+          .setDescription(
+            `**Title** : ${args.join(' ')}\n\`Please describe your issue. (No command needed.)\``
+          )
+          .setFooter(mainServer.name, mainServer.iconURL)
+          .setTimestamp();
+        author.send(dmEmbed);
+
+        const member = await mainServer.members.get(author.id);
+        const memberRoles = await member.roles.map(role => `${role.name}`).join(', ');
+        let userData = [];
+        userData.push(`**User Tag** : \`${author.tag}\``);
+        userData.push(`**User ID** : \`${author.id}\``);
+        userData.push(`**Created at** : ${moment(author.createdAt).format("D MMM YYYY, HH:mm")}`);
+        userData.push(`**Joined at** : ${moment(member.joinedAt).format("D MMM YYYY, HH:mm")}`);
+        userData.push(`**Roles** : ${memberRoles}`);
+        let newThreadEmbed = new Discord.RichEmbed()
+          .setColor(config.info_color)
+          .setTitle("New Thread")
+          .setDescription(args.join(' '))
+          .addField("User Info", userData.join('\n'))
+          .setThumbnail(author.avatarURL)
+          .setFooter(`${author.tag} | ${author.id}`, author.avatarURL)
+          .setTimestamp();
+        newChannel.send(newThreadEmbed);
+
+        if (message.attachments.size > 0) {
+          await message.attachments.forEach(async atch => {
+            let attachment = new Attachment(atch.url);
+            await newChannel.send(attachment);
+          });
+        }
+
+        const newThread = await ThreadDB.create({
+        	userID: author.id,
+        	channelID: newChannel.id,
+        	threadTitle: args.join(' ')
+        });
+        console.log(`${author.tag} created thread.`);
+
+      }
+    };
+
+  }
+};
diff --git a/functions/reply.js b/functions/reply.js
new file mode 100644
index 0000000..6d1c261
--- /dev/null
+++ b/functions/reply.js
@@ -0,0 +1,85 @@
+module.exports = {
+  name: "reply",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const Attachment = param.Attachment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+    const isMember = param.isMember;
+    const isBlocked = param.isBlocked;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const categoryID = config.categoryID;
+    const author = message.author;
+    const channel = message.channel;
+
+    const isThread = await ThreadDB.findOne({where: {channelID: channel.id}});
+    const checkIsBlocked = await isBlocked.execute(param, author.id);
+
+    const blockedEmbed = getEmbed.execute(param, config.error_color, "Blocked", `User blocked.`);
+    const noDMEmbed = getEmbed.execute(param, config.error_color, "Not Sent", `User disabled Direct Message.`);
+    const noUserEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find user in my collection.`);
+    const noThreadEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find any thread asociated with this channel.`);
+
+    if (!isThread) {
+      return channel.send(noThreadEmbed);
+    } else {
+      const checkIsMember = await isMember.execute(param, author.id);
+      const notMemberEmbed = getEmbed.execute(param, config.error_color, "Not a Member", `User aren\'t inside [**${mainServer.name}**] guild.`);
+
+      if (!checkIsMember) {
+        return channel.send(notMemberEmbed);
+      } else if (checkIsBlocked){
+        return channel.send(blockedEmbed);
+      } else {
+        const userID = isThread.userID;
+        const member = await mainServer.members.get(userID);
+
+        if (!member) {
+          return channel.send(noUserEmbed);
+        } else {
+          const user = member.user;
+          const description = args.join(' ');
+          const userDMEmbed = new Discord.RichEmbed()
+            .setColor(config.sent_color)
+            .setAuthor(author.tag, author.avatarURL)
+            .setTitle("Message Received")
+            .setDescription(description)
+            .setFooter(mainServer.name, mainServer.avatarURL)
+            .setTimestamp();
+          const threadChannelEmbed = new Discord.RichEmbed()
+            .setColor(config.sent_color)
+            .setAuthor(author.tag, author.avatarURL)
+            .setTitle("Message Sent")
+            .setDescription(description)
+            .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
+            .setTimestamp();
+
+          try{
+            await user.send(userDMEmbed);
+          } catch (error){
+            if(error.message == "Cannot send messages to this user"){
+              return channel.send(noDMEmbed);
+            }
+          }
+          await channel.send(threadChannelEmbed);
+          if (message.attachments.size > 0) {
+            await message.attachments.forEach(async atch => {
+              let attachment = new Attachment(atch.url);
+              await user.send(attachment);
+              await channel.send(attachment);
+            });
+          }
+          return message.delete();
+        }
+
+      };
+    };
+
+  }
+};
diff --git a/functions/reset.js b/functions/reset.js
new file mode 100644
index 0000000..90e2fd4
--- /dev/null
+++ b/functions/reset.js
@@ -0,0 +1,27 @@
+module.exports = {
+  name: "reset",
+  async execute(param){
+    const defConfig = param.defConfig;
+    const ConfigDB = param.ConfigDB;
+    const configKeys = Object.keys(param.config);
+
+    configKeys.forEach(async aKey => {
+      try {
+        //Create new row on config.sqlite
+        const newConfig = await ConfigDB.create({
+          name: aKey,
+          input: defConfig[aKey]
+        });
+      } catch (error) {
+        //Edit the value in config.sqlite with the one from config.js
+        if (error.name === "SequelizeUniqueConstraintError") {
+          await ConfigDB.update(
+            { input: defConfig[aKey] },
+            { where: { name: aKey } }
+          );
+        }
+      }
+    });
+    return param.configSync.execute(param);
+  }
+};
diff --git a/functions/roleCheck.js b/functions/roleCheck.js
new file mode 100644
index 0000000..408f838
--- /dev/null
+++ b/functions/roleCheck.js
@@ -0,0 +1,12 @@
+module.exports = {
+  name: "roleCheck",
+  async execute(message, roleID){
+    const isRole = message.member.roles.get(roleID);
+
+    if(isRole){
+      return true;
+    } else {
+      return false;
+    }
+  }
+};
diff --git a/functions/set.js b/functions/set.js
new file mode 100644
index 0000000..47b88a0
--- /dev/null
+++ b/functions/set.js
@@ -0,0 +1,119 @@
+module.exports = {
+  name: "set",
+  async execute(param, message, args){
+    const client = param.client;
+    const config = param.config;
+    const getEmbed = param.getEmbed;
+    const configSync = param.configSync;
+    const ConfigDB = param.ConfigDB;
+    const configName = args.shift();
+    var inputValue = args.shift() || "empty";
+
+    //manual toggle since i set database to String, can't store boolean for maintenance config.
+    if(configName == "maintenance"){
+     if(config.maintenance == "0"){
+       inputValue = "1";
+     } else {
+       inputValue = "0";
+     }
+    }
+
+    const notOwnerEmbed = getEmbed.execute(param, config.warning_color, "Missing Permission", `Only bot owner [<@${config.botOwnerID}>] can change this value.`);
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `The value of \`${configName}\` changed to \`${inputValue}\``);
+    const notSetEmbed = getEmbed.execute(param, config.warning_color, "Configuration Needed", `Please set \`threadServerID\` to change this config.`);
+    const emptyValueEmbed = getEmbed.execute(param, config.warning_color, "Invalid Value", "This config value can\'t be empty.");
+    const invalidUserEmbed = getEmbed.execute(param, config.warning_color, "Invalid User", `Can\'t find that user.`);
+    const invalidServerEmbed = getEmbed.execute(param, config.warning_color, "Invalid Server", `Can\'t find that server.\n\`Make sure the bot joined the server already\``);
+    const invalidChannelMainEmbed = getEmbed.execute(param, config.warning_color, "Invalid Channel", `Can\'t find that channel.\n\`Make sure the channel is inside Main Server.\``);
+    const invalidChannelThreadEmbed = getEmbed.execute(param, config.warning_color, "Invalid Channel", `Can\'t find that channel.\n\`Make sure the channel is inside Thread Server.\``);
+    const invalidRoleEmbed = getEmbed.execute(param, config.warning_color, "Invalid Role", `Can\'t find that role.\n\`Make sure the role is inside Thread Server.\``);
+    const invalidColorEmbed = getEmbed.execute(param, config.warning_color, "Invalid Color", `Use hex code for input.\nCheck : <https://html-color.codes/>`);
+
+    //elimination for invalid input
+    if(configName == "botOwnerID"){
+
+      if(message.author.id != config.botOwnerID){
+        return message.channel.send(notOwnerEmbed);
+      } else if(inputValue == "empty"){
+        return message.channel.send(emptyValueEmbed);
+      } else if(!client.users.get(inputValue)){
+        return message.channel.send(invalidUserEmbed);
+      };
+
+    } else if(configName == "mainServerID" && inputValue != "empty"){
+
+      if(!client.guilds.get(inputValue)) {
+        return message.channel.send(invalidServerEmbed);
+      };
+
+    } else if(configName == "threadServerID" && inputValue != "empty"){
+
+      if(!client.guilds.get(inputValue)) {
+        return message.channel.send(invalidServerEmbed);
+      };
+
+    } else if((configName == "categoryID" || configName == "logChannelID") && inputValue != "empty"){
+
+      if(config.threadServerID == "empty"){
+        return message.channel.send(notSetEmbed);
+      } else if(!client.guilds.get(config.threadServerID).channels.get(inputValue)){
+        return message.channel.send(invalidChannelThreadEmbed);
+      };
+
+    } else if(configName == "botChannelID" && inputValue != "empty"){
+
+      if(config.mainServerID == "empty"){
+        return message.channel.send(notSetEmbed);
+      } else if(!client.guilds.get(config.mainServerID).channels.get(inputValue)){
+        return message.channel.send(invalidChannelMainEmbed);
+      };
+
+    } else if((configName == "adminRoleID" || configName == "modRoleID") && inputValue != "empty"){
+
+      if(config.threadServerID == "empty"){
+        return message.channel.send(notSetEmbed);
+      } else if(!client.guilds.get(config.threadServerID).roles.get(inputValue)){
+        return message.channel.send(invalidRoleEmbed);
+      };
+
+    } else if(configName == "mentionedRoleID" && inputValue != "empty" && inputValue != "everyone" && inputValue != "here"){
+
+      if(config.threadServerID == "empty"){
+        return message.channel.send(notSetEmbed);
+      } else if(!client.guilds.get(config.threadServerID).roles.get(inputValue)){
+        return message.channel.send(invalidRoleEmbed);
+      }
+
+    } else if(configName == "info_color" || configName == "warning_color" || configName == "error_color" || configName == "sent_color" || configName == "received_color"){
+
+      const colorTest = /^#[0-9A-F]{6}$/i;
+      if(inputValue == "empty"){
+        return message.channel.send(emptyValueEmbed);
+      } else if(colorTest.test(inputValue) == false){
+        return message.channel.send(invalidColorEmbed);
+      }
+
+    }
+
+    //getting all the config name from Database
+    const configCollection = await ConfigDB.findAll({ attributes: ["name"] });
+    const configList = configCollection.map(conf => `\`${conf.name}\``).join(', ');
+
+    //trying to edit the Database
+    const affectedRows = await ConfigDB.update({input: inputValue}, {where: {name:configName}});
+    if(affectedRows > 0){
+      console.log(`[${configName}] value changed to [${inputValue}]`);
+      await message.channel.send(successEmbed).then(async () => {
+        if(configName == "maintenance" || configName == "prefix"){
+          process.exit(1);
+        } else {
+          return await configSync.execute(param);
+        }
+      });
+    } else {
+      const notFoundEmbed = getEmbed.execute(param, config.error_color, "Failed", `Can\'t find config named \`${configName}\`.\nAvailable names : ${configList}`);
+      return message.channel.send(notFoundEmbed)
+    }
+
+  }
+};
diff --git a/functions/threadInfo.js b/functions/threadInfo.js
new file mode 100644
index 0000000..6261419
--- /dev/null
+++ b/functions/threadInfo.js
@@ -0,0 +1,52 @@
+module.exports = {
+  name: "threadInfo",
+  async execute(param, message, args){
+    const Discord = param.Discord;
+    const moment = param.moment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const ThreadDB = param.ThreadDB;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+
+    const input = args.shift();
+    const isThreadUser = await ThreadDB.findOne({where: {userID: input}});
+    const isThreadChannel = await ThreadDB.findOne({where: {channelID: input}});
+    let isThread = false;
+
+    var noThreadEmbed = getEmbed.execute(param, config.error_color, "Not Found", `Couldn\'t find any thread asociated with that user id or channel id.`);
+
+    if (isThreadUser) {
+      isThread = isThreadUser;
+    } else if(isThreadChannel){
+      isThread = isThreadChannel;
+    }
+
+    if (!isThread) {
+      return message.channel.send(noThreadEmbed);
+    } else {
+      let threadData = [];
+      const member = mainServer.members.get(isThread.userID);
+
+      threadData.push(`${isThread.threadTitle}`);
+      if (member) {
+        threadData.push(`**User Tag** : \`${member.user.tag}\``);
+      } else {
+        threadData.push(`**User Tag** : \`Couldn\'t find user at main server.\``);
+      }
+      threadData.push(`**User ID** : \`${isThread.userID}\``);
+      threadData.push(`**Thread Channel** : <#${isThread.channelID}>`);
+      threadData.push(`**Created at** : ${moment(isThread.createdAt).format("D MMMM YYYY, **HH:mm:ss** UTC")}`);
+      threadData.push(`**Updated at** : ${moment(isThread.updatedAt).format("D MMMM YYYY, **HH:mm:ss** UTC")}`);
+
+      const threadInfoEmbed = getEmbed.execute(param, config.info_color, "Thread Information", threadData.join('\n'));
+      return message.channel.send(threadInfoEmbed);
+
+    };
+
+  }
+};
diff --git a/functions/unblock.js b/functions/unblock.js
new file mode 100644
index 0000000..1d5c2da
--- /dev/null
+++ b/functions/unblock.js
@@ -0,0 +1,24 @@
+module.exports = {
+	name: "unblock",
+	async execute(param, message, args){
+    const moment = param.moment;
+    const client = param.client;
+    const config = param.config;
+    const BlockedDB = param.BlockedDB;
+		const getEmbed = param.getEmbed;
+
+    const userID = args.shift();
+
+    const notFoundEmbed = getEmbed.execute(param, config.error_color, "Not Found", `<@${userID}> (\`${userID}\`) isn\'t blocked.`);
+    const successEmbed = getEmbed.execute(param, config.info_color, "Success", `Succesfully unblock <@${userID}> (\`${userID}\`).`);
+
+    const rowCount = await BlockedDB.destroy({ where: {userID: userID} });
+    if (rowCount > 0) {
+      console.log(`Unblocked ${userID}`);
+      return message.channel.send(successEmbed);
+    } else {
+      return message.channel.send(notFoundEmbed);
+    }
+
+  }
+};
diff --git a/functions/userReply.js b/functions/userReply.js
new file mode 100644
index 0000000..a99f5d4
--- /dev/null
+++ b/functions/userReply.js
@@ -0,0 +1,64 @@
+module.exports = {
+  name: "userReply",
+  async execute(param, message, thread){
+    const Discord = param.Discord;
+    const Attachment = param.Attachment;
+    const client = param.client;
+    const getEmbed = param.getEmbed;
+    const config = param.config;
+    const isMember = param.isMember;
+    const isBlocked = param.isBlocked;
+
+    const mainServerID = config.mainServerID;
+    const mainServer = await client.guilds.get(mainServerID);
+    const threadServerID = config.threadServerID;
+    const threadServer = await client.guilds.get(threadServerID);
+    const author = message.author;
+
+    const checkIsBlocked = await isBlocked.execute(param, author.id);
+
+    const blockedEmbed = getEmbed.execute(param, config.error_color, "Blocked", `You are blocked from replying to a thread.`);
+    const noServerEmbed = getEmbed.execute(param, config.error_color, "Contact Admin", "\`mainServerID\` and/or \`threadServerID\` value is empty.");
+    const noChannelEmbed = getEmbed.execute(param, config.error_color, "Channel Not Found", `Couldn\'t find your thread channel, ask admin to use \`${config.prefix}bind\` command.`);
+
+    if(checkIsBlocked){
+      return message.channel.send(blockedEmbed);
+    } else if (!mainServer || !threadServer) {
+      //Can't find main server or thread server
+      return message.channel.send(noServerEmbed);
+    } else {
+      const checkIsMember = await isMember.execute(param, author.id);
+      const notMemberEmbed = getEmbed.execute(param, config.error_color, "Not a Member", `User aren\'t inside [**${mainServer.name}**] guild.`);
+      const threadChannel = await threadServer.channels.get(thread.channelID);
+
+      if(!checkIsMember){
+        return message.channel.send(notMemberEmbed);
+      } else {
+        if(!threadChannel){
+          return message.channel.send(noChannelEmbed);
+        } else {
+          const sendPromise = new Promise(async resolve => {
+            let userReplyEmbed = new Discord.RichEmbed()
+              .setColor(config.received_color)
+              .setTitle("Message Received")
+              .setDescription(message.content)
+              .setFooter(`${author.tag} | ${author.id}`, author.avatarURL)
+              .setTimestamp();
+            await threadChannel.send(userReplyEmbed);
+
+            if (message.attachments.size > 0) {
+              await message.attachments.forEach(async atch => {
+                let attachment = new Attachment(atch.url);
+                await threadChannel.send(attachment);
+              });
+            }
+            resolve();
+          });
+          sendPromise.then(message.react("✅"));
+
+        }
+      }
+    };
+
+  }
+};
diff --git a/index.js b/index.js
index 14c6586..20fa4b1 100644
--- a/index.js
+++ b/index.js
@@ -1,1820 +1,325 @@
-/*
-
-*/
-
-//===============================DEPENDECIES====================================
-
-//#dependencies
-console.log("Loading Dependencies");
-const Discord = require("discord.js");
-const { Util, Attachment } = require("discord.js");
-const client = new Discord.Client();
-const server = require("./server.js");
-const Sequelize = require("sequelize");
-const fs = require("fs");
-const moment = require("moment");
-const defConfig = require("./config.json");
-require("dotenv").config();
-
-//==============================================================================
-//================================VARIABLES=====================================
-
-console.log("Loading Variables");
-//#config
-//Config used by bot (synced from database everytime bot ready).
-//Use same variable name on config.json or it won't be able to reseted on reset.
-var config = {
-  prefix: "",
-  botOwnerID: "",
-  serverID: "",
-  categoryID: "",
-  logChannelID: "",
-  adminRoleID: "",
-  modRoleID: "",
-  mentionedRoleID: "",
-  maintenance: "",
-  info_color: "",
-  warning_color: "",
-  error_color: "",
-  received_color: "",
-  sent_color: ""
-};
-
-//----Activity List----
-//#activities
-var activities = [
-  `Glitch.com | ${defConfig.prefix}commands`,
-  `DM to contact Staff | ${defConfig.prefix}help`,
-  `DM, um Mitarbeiter zu kontaktieren | ${defConfig.prefix}helpDE`,
-  `Personel ile irtibata geçmek için DM | ${defConfig.prefix}helpTR`,
-  `직원에게 연락하는 DM | ${defConfig.prefix}helpKO`,
-  `DM para entrar em contato com a equipe | ${defConfig.prefix}helpPT`,
-  `DM contacte le personnel | ${defConfig.prefix}helpFR`,
-  `DM связаться с персоналом | ${defConfig.prefix}helpRU`,
-  `DM 与官方人员联系 | ${defConfig.prefix}helpCHS`,
-  `DM 與官方人員聯繫 | ${defConfig.prefix}helpCHT`,
-  `DM para contactar al personal | ${defConfig.prefix}helpES`
-];
-
-//----Database----
-//#db
-const blockedDB = new Sequelize("database", "user", "password", {
-  host: "localhost",
-  dialect: "sqlite",
-  logging: false,
-  // SQLite only
-  storage: "blocked.sqlite"
-});
-const BlockedDB = blockedDB.define("blocked", {
-  name: {
-    type: Sequelize.STRING,
-    unique: true
-  }
-});
-
-const configDB = new Sequelize("database", "user", "password", {
-  host: "localhost",
-  dialect: "sqlite",
-  logging: false,
-  // SQLite only
-  storage: "config.sqlite"
-});
-const ConfigDB = configDB.define("config", {
-  name: {
-    type: Sequelize.STRING,
-    unique: true
-  },
-  input: Sequelize.STRING
-});
-
-//==============================================================================
-//===============================FUNCTIONS======================================
-
-console.log("Loading Functions");
-
-//----------------------------------Get Embed-----------------------------------
-//#embed
-function getEmbed(color, title, description) {
-  var embed = new Discord.RichEmbed()
-    .setColor(color)
-    .setTitle(title)
-    .setDescription(description)
-    .setFooter(client.user.tag, client.user.avatarURL)
-    .setTimestamp();
-  return embed;
-}
-
-//------------------------------Guild Member Check------------------------------
-//#isMemberFn
-async function isMember(msg) {
-  if (
-    config.serverID == "empty" ||
-    config.categoryID == "empty" ||
-    config.logChannelID == "empty"
-  ) {
-    msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Error!",
-        "Bot configuration has not been set. Use =setup command."
-      )
-    );
-    return false;
-  }
-  let searchMember =
-    (await client.guilds.get(config.serverID).members.get(msg.author.id)) ||
-    false;
-  if (searchMember) {
-    return true;
-  } else {
-    await msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Not Member!",
-        `You aren't member of **${
-          client.guilds.get(config.serverID).name
-        }** server.`
-      )
-    );
-    return false;
-  }
-}
-
-//------------------------------Blocked User Check------------------------------
-//#isBlockedFn
-async function isBlocked(msg) {
-  if (
-    config.serverID == "empty" ||
-    config.categoryID == "empty" ||
-    config.logChannelID == "empty"
-  ) {
-    msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Error!",
-        "Bot configuration has not been set. Use =setup command."
-      )
-    );
-    return false;
-  }
-  let findInBlock = await BlockedDB.findOne({ where: { name: msg.author.id } });
-  if (!findInBlock) {
-    return false;
-  } else {
-    return await msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Blocked!",
-        `You are blocked in **${
-          client.guilds.get(config.serverID).name
-        }** server.`
-      )
-    );
-    return true;
-  }
-}
-
-//-------------------------------Permission Check-------------------------------
-//#permissionCheckFn
-async function permissionCheck(msg, permission) {
-  let result = false;
-  if (msg.member.hasPermission(permission)) {
-    result = true;
-  } else {
-    result = false;
-  }
-  return result;
-}
-
-//---------------------------------Role Check-----------------------------------
-//#roleCheckFn
-async function roleCheck(msg, roleID) {
-  let result = false;
-  if (roleID == "empty") {
-    if (config.adminRoleID == "empty" && config.modRoleID == "empty") {
-      msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Warning!",
-          `Value of \`adminRoleID\` and \`modRoleID\` is empty. Use =setup to change it.`
-        )
-      );
-      return result;
-    } else if (config.adminRoleID == "empty") {
-      msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Warning!",
-          `Value of \`adminRoleID\` is empty. Use =setup to change it.`
-        )
-      );
-      return result;
-    } else if (config.modRoleID == "empty") {
-      msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Warning!",
-          `Value of \`modRoleID\` is empty. Use =setup to change it.`
-        )
-      );
-      return result;
-    }
-  }
-  let role = msg.guild.roles.get(roleID);
-  if (msg.member.roles.find(r => r.id == roleID)) {
-    result = true;
-  } else {
-    result = false;
-  }
-  return result;
-}
-
-//++++++++++++++++++++++++++++++Command Functions+++++++++++++++++++++++++++++++
-//-----------------------------New Thread Function------------------------------
-//#newThreadFn
-async function newThread(msg, args) {
-  if (
-    config.serverID == "empty" ||
-    config.categoryID == "empty" ||
-    config.logChannelID == "empty"
-  ) {
-    return msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Error!",
-        "Bot configuration has not been set. Use =setup command."
-      )
-    );
-  }
-  let IsMember = await isMember(msg);
-  let IsBlocked = await isBlocked(msg);
-  let HaveThread = await client.guilds
-    .get(config.serverID)
-    .channels.find(ch => ch.name == msg.author.id);
-  let MentionedRole = "";
-  if (
-    config.mentionedRoleID == "everyone" ||
-    config.mentionedRoleID == "here"
-  ) {
-    MentionedRole = "@" + config.mentionedRoleID;
-  } else if (
-    config.mentionedRoleID != null &&
-    config.mentionedRoleID != "empty"
-  ) {
-    MentionedRole = "<@&" + config.mentionedRoleID + ">";
-  }
-  if (HaveThread) {
-    return await msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Open Thread Exist!",
-        `You still have open thread.`
-      )
-    );
-  }
-  if (IsMember && !IsBlocked && !HaveThread) {
-    let newChannel = await client.guilds
-      .get(config.serverID)
-      .createChannel(msg.author.id, { type: "text" });
-    await newChannel.setParent(config.categoryID);
-    await newChannel.lockPermissions().catch(console.error);
-
-    let user = client.users.get(msg.author.id);
-    let memberRoles = await client.guilds
-      .get(config.serverID)
-      .members.get(msg.author.id)
-      .roles.filter(r => r.name !== "@everyone")
-      .map(role => `<@&${role.id}>`)
-      .join(", ");
-    let description = `**Nickname** : \`${user.tag}\`\n**ID** : \`${
-      user.id
-    }\`\n**Created at** : ${moment(user.createdAt).format(
-      "DD MMM YYYY, HH:mm"
-    )}\n**Joined at** : ${moment(
-      client.guilds.get(config.serverID).members.get(msg.author.id).joinedAt
-    ).format("DD MMM YYYY, HH:mm")}\n**Roles** : ${memberRoles}`;
-    let newThreadEmbed = new Discord.RichEmbed()
-      .setColor(config.info_color)
-      .setAuthor("New Thread!")
-      .setTitle(`"${args}"`)
-      .setDescription(description)
-      .setThumbnail(msg.author.avatarURL)
-      .setFooter(`${msg.author.tag} | ${msg.author.id}`, msg.author.avatarURL)
-      .setTimestamp();
-    newChannel.send(`${MentionedRole}`, newThreadEmbed);
-
-    let logEmbed = new Discord.RichEmbed()
-      .setColor(config.info_color)
-      .setAuthor("New Thread!")
-      .setTitle(`"${args}"`)
-      .setFooter(`${msg.author.tag} | ${msg.author.id}`, msg.author.avatarURL)
-      .setTimestamp();
-    let logChannel = await client.guilds
-      .get(config.serverID)
-      .channels.get(config.logChannelID);
-    logChannel.send(logEmbed);
-
-    let mainServer = client.guilds.get(config.serverID);
-    let dmEmbed = new Discord.RichEmbed()
-      .setColor(config.info_color)
-      .setTitle("Thread Created!")
-      .setDescription(
-        `**Title : "${args}"**\n\n\`Please describe your issue. (No command needed.)\``
-      )
-      .setFooter(mainServer.name, mainServer.iconURL)
-      .setTimestamp();
-    msg.channel.send(dmEmbed);
-  }
-}
-
-//----------------------------User Response Function----------------------------
-//#userResponseFn
-async function userResponse(msg, channel) {
-  let chatEmbed = new Discord.RichEmbed()
-    .setColor(config.received_color)
-    .setTitle("Message Received")
-    .setDescription(msg.content)
-    .setFooter(`${msg.author.tag} | ${msg.author.id}`, msg.author.avatarURL)
-    .setTimestamp();
-  if (msg.attachments.size == 0) {
-    channel.send(chatEmbed).then(msg.react("✅"));
-  } else if (msg.attachments.size == 1) {
-    await msg.attachments.forEach(a => {
-      let attachment = new Attachment(a.url);
-      channel.send(chatEmbed.attachFile(attachment)).then(msg.react("✅"));
-    });
-  } else {
-    await msg.attachments.forEach(a => {
-      let attachment = new Attachment(a.url);
-      channel.send(attachment);
-    });
-    channel.send(chatEmbed).then(msg.react("✅"));
-  }
-}
-
-//------------------------------User Block Function-----------------------------
-//#blockFn
-async function block(msg, arg) {
-  if (!arg) {
-    msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Missing Argument",
-        "**Usage** : `block [user-id]`\n\n`Note : The bot didn't check user existence to enable blocking someone outside the server. Please double check the ID before using this command.`"
-      )
-    );
-  } else {
-    try {
-      const block = await BlockedDB.create({
-        name: arg
-      });
-      return msg.channel.send(
-        getEmbed(
-          config.error_color,
-          "Blocked!",
-          `<@${block.name}> (${block.name}) has been blocked.`
-        )
-      );
-    } catch (e) {
-      if (e.name === "SequelizeUniqueConstraintError") {
-        return msg.channel.send(
-          getEmbed(
-            config.warning_color,
-            "Duplicated!",
-            `<@${arg}> (${arg}) already blocked.`
-          )
-        );
-      } else {
-        return msg.channel.send(
-          getEmbed(config.error_color, "Error", `${e.name}`)
-        );
-      }
-    }
-  }
-}
-
-//----------------------------Users Blocklist Function--------------------------
-//#blockListFn
-async function blocklist(msg, arg) {
-  const list = await BlockedDB.findAll({ attributes: ["name", "createdAt"] });
-  var pages = Math.floor(list.length / 20);
-  if (list.length % 20 != 0) {
-    pages += 1;
-  }
-  if (!arg || isNaN(arg) || arg < 0) {
-    arg = 1;
-  }
-  if (list.length == 0) {
-    arg = 0;
-  }
-  const string =
-    list
-      .map(
-        b =>
-          `**[${moment(b.createdAt).format("DD/MM/YYYY")}]** <@${b.name}> \`(${
-            b.name
-          })\``
-      )
-      .slice(Math.abs((arg - 1) * 20))
-      .slice(0, 20)
-      .join("\n") || "Blocklist empty.";
-  return msg.channel.send(
-    getEmbed(
-      config.info_color,
-      "**List of blocked user :**",
-      `${string}\n\n\`Page ${arg} from ${pages} pages.\``
-    )
-  );
-}
-
-//----------------------------User Unblock Function----------------------------
-//#unblockFn
-async function unblock(msg, arg) {
-  if (!arg) {
-    msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Missing Argument",
-        "**Usage** : `unblock [user-id]`"
-      )
-    );
-  } else {
-    const rowCount = await BlockedDB.destroy({ where: { name: arg } });
-    if (!rowCount)
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found!", "That user isn't blocked.")
-      );
-
-    return msg.channel.send(
-      getEmbed(config.info_color, "Success!", `<@${arg}> (${arg}) unblocked.`)
-    );
-  }
-}
-
-//-----------------------------Thread Reply Function----------------------------
-//#replyFn
-async function reply(msg, arg) {
-  if (
-    config.serverID == "empty" ||
-    config.categoryID == "empty" ||
-    config.logChannelID == "empty"
-  ) {
-    return msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Error!",
-        "Bot configuration has not been set. Use =setup command."
-      )
-    );
-  }
-  if (!arg && msg.attachments.size == 0) {
-    let embed = getEmbed(
-      config.warning_color,
-      "Missing Argument",
-      `**Usage** : \`reply [reply message]\``
-    );
-    return msg.channel.send(embed);
-  } else {
-    let text = msg.content
-      .split(/ +/)
-      .slice(1)
-      .join(" ");
-    let channelName = await msg.channel.name;
-    let user
-    try{
-      user = await client.guilds.get(config.serverID).members.get(channelName).user;
-    }catch(e){
-      if(e.message == "Cannot read property 'user' of undefined"){
-        return msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "User Not Found!",
-          `Can\'t find <@${channelName}>.`
-        )
-      );
-      } else {
-        return msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Error",
-          e.message
-        )
-      );
-      }
-    }
-    let moderator = msg.author;
-    
-      let mainServer = client.guilds.get(config.serverID);
-      let chatGuildEmbed = new Discord.RichEmbed()
-        .setColor(config.sent_color)
-        .setAuthor(moderator.tag, moderator.avatarURL)
-        .setTitle("Message sent")
-        .setDescription(text)
-        .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
-        .setTimestamp();
-      let chatDMEmbed = new Discord.RichEmbed()
-        .setColor(config.sent_color)
-        .setAuthor(moderator.tag, moderator.avatarURL)
-        .setDescription(text)
-        .setFooter(mainServer.name, mainServer.iconURL)
-        .setTimestamp();
-    let disabledDM = getEmbed(config.error_color, "Failed!", "User disabled Direct Message.")
-      if (msg.attachments.size == 0) {
-        try{
-        await user.send(chatDMEmbed);
-        } catch (e){
-          if(e.message == "Cannot send messages to this user"){
-            return msg.channel.send(disabledDM);
-          } else {
-            return msg.channel.send(getEmbed(config.error_color, "Error!", e.message))
-          }
-        }
-        msg.channel.send(chatGuildEmbed);
-        msg.delete();
-      } else {
-        try {
-        await user.send(chatDMEmbed);
-        } catch (e){
-          if(e.message == "Cannot send messages to this user"){
-            return msg.channel.send(disabledDM);
-          } else {
-            return msg.channel.send(getEmbed(config.error_color, "Error!", e.message))
-          }
-        }
-        msg.channel.send(chatGuildEmbed);
-        await msg.attachments.forEach(a => {
-          let attachment = new Attachment(a.url);
-          user.send(attachment).then(msg.channel.send(attachment));
-          
-        });
-        msg.delete();
-      }
-    
-  }
-}
-
-//----------------------------Thread Close Function-----------------------------
-//#closeFn
-async function close(msg, arg) {
-  if (
-    config.serverID == "empty" ||
-    config.categoryID == "empty" ||
-    config.logChannelID == "empty"
-  ) {
-    return msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Error!",
-        "Bot configuration has not been set. Use =setup command."
-      )
-    );
-  }
-  if (
-    msg.channel.parentID != config.categoryID ||
-    msg.channel.id == config.logChannelID
-  ) {
-    let embed = getEmbed(
-      config.warning_color,
-      "Not Thread Channel",
-      "This is not thread channel."
-    );
-    msg.channel.send(embed);
-  } else if (!arg) {
-    let embed = getEmbed(
-      config.warning_color,
-      "Missing Argument",
-      `**Usage** : \`close [reason] - [note]\``
-    );
-    return msg.channel.send(embed);
-  } else {
-    let temp = arg.split(/-+/);
-    let reason = temp[0];
-    let note = temp[1] || "Empty";
-    let logChannel = await client.guilds
-      .get(config.serverID)
-      .channels.get(config.logChannelID);
-    let channelName = await msg.channel.name;
-    let user = await client.guilds.get(config.serverID).members.get(channelName)
-      .user;
-    let moderator = msg.author;
-
-    let logEmbed = new Discord.RichEmbed()
-      .setColor(config.error_color)
-      .setAuthor(moderator.tag, moderator.avatarURL)
-      .setTitle("Thread closed!")
-      .setDescription(`**Reason** : ${reason}\n**Note** : ${note}`)
-      .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
-      .setTimestamp();
-    let dmEmbed = new Discord.RichEmbed()
-      .setColor(config.error_color)
-      .setAuthor(
-        client.guilds.get(config.serverID).name,
-        client.guilds.get(config.serverID).iconURL
-      )
-      .setTitle("Thread closed!")
-      .setDescription(`**Reason** : ${reason}`)
-      .setFooter(`${user.tag} | ${user.id}`, user.avatarURL)
-      .setTimestamp();
-    msg.channel.delete().catch(console.error);
-    logChannel.send(logEmbed);
-    user.send(dmEmbed).catch(console.error.message);
-  }
-}
-
-//-----------------------------Reset Config Function----------------------------
-//#resetFn
-//Using variables at config.js as default.
-//I've tried to reverse this to (update > error > create) it can't find the row, didn't throw any error, and keep searching indefinitely.
-async function resetConfig() {
-  let configKeys = Object.keys(config);
-  configKeys.forEach(async aKey => {
-    try {
-      //Create new row on config.sqlite
-      const newConfig = await ConfigDB.create({
-        name: aKey,
-        input: defConfig[aKey]
-      });
-    } catch (e) {
-      //Edit the value in config.sqlite with the one from config.js
-      if (e.name === "SequelizeUniqueConstraintError") {
-        await ConfigDB.update(
-          { input: defConfig[aKey] },
-          { where: { name: aKey } }
-        );
-      } else {
-        console.log(e);
-      }
-    }
-  });
-  return await configSync();
-}
-
-//-----------------------------Config Setup Function----------------------------
-//#setupFn
-async function setup(msg, configName, configValue) {
-  if (configName == "botOwnerID") {
-    if (msg.author.id != config.botOwnerID) {
-      return msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Missing Permission",
-          "Only bot owner can change this value."
-        )
-      );
-    } else if (!client.users.get(configValue)) {
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found!", "Can't find that user")
-      );
-    }
-  } else if (configName == "serverID" && configValue != "empty") {
-    if (!client.guilds.get(configValue))
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found!", "Cannot find that server.")
-      );
-  } else if (!config.serverID || config.serverID == "empty") {
-    return msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Cannot find ServerID!",
-        "Please set `serverID` to change this value. `setup serverID [serverID]`"
-      )
-    );
-  } else if (configName == "categoryID" && configValue != "empty") {
-    if (!client.guilds.get(config.serverID).channels.get(configValue))
-      return msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Not Found",
-          "Can't find that category channel."
-        )
-      );
-  } else if (configName == "logChannelID" && configValue != "empty") {
-    if (!client.guilds.get(config.serverID).channels.get(configValue))
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found", "Can't find that channel.")
-      );
-  } else if (configName == "adminRoleID" && configValue != "empty") {
-    if (!client.guilds.get(config.serverID).roles.get(configValue))
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found", "Can't find that role.")
-      );
-  } else if (configName == "modRoleID" && configValue != "empty") {
-    if (!client.guilds.get(config.serverID).roles.get(configValue))
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found", "Can't find that role.")
-      );
-  } else if (
-    configName == "mentionedRoleID" &&
-    configValue != "everyone" &&
-    configValue != "here" &&
-    configValue != "empty"
-  ) {
-    if (!client.guilds.get(config.serverID).roles.get(configValue))
-      return msg.channel.send(
-        getEmbed(config.warning_color, "Not Found", "Can't find that role.")
-      );
-  } else if (configName == "maintenance") {
-    if (config.maintenance == "0") {
-      configValue = "1";
-    } else {
-      configValue = "0";
-    }
-  } else if (
-    configName == "info_color" ||
-    configName == "warning_color" ||
-    configName == "error_color" ||
-    configName == "received_color" ||
-    configName == "sent_color"
-  ) {
-    var colorTest = /^#[0-9A-F]{6}$/i; //check if input is a hex color code. Search "JavaScript how to check hex code" for explanation.
-    if (colorTest.test(configValue) == false) {
-      return msg.channel.send(
-        getEmbed(
-          config.warning_color,
-          "Invalid Input",
-          "Use hex code for input.\n\nExample : `#ffffff`, `#000000`\n\nColor picker site will be helpful https://html-color.codes/"
-        )
-      );
-    }
-  }
-  let checkDB = await ConfigDB.findOne({ where: { name: configName } });
-  if (!checkDB) {
-    const configList = await ConfigDB.findAll({ attributes: ["name"] });
-    const configString =
-      configList.map(c => `\`${c.name}\``).join(", ") ||
-      "Database empty, use =reset command.";
-    return msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Failed",
-        `Could not find a config with name \`${configName}\`.\n\nAvailable config : ${configString}`
-      )
-    );
-  } else {
-    const affectedRows = await ConfigDB.update(
-      { input: configValue },
-      { where: { name: configName } }
-    );
-    if (affectedRows > 0) {
-      await configSync();
-      await msg.channel.send(
-        getEmbed(
-          config.error_color,
-          "Success",
-          `Value of \`${configName}\` was edited to \`${configValue}\`.`
-        )
-      );
-      if (configName == "maintenance") {
-        process.exit(1);
-      }
-    }
-  }
-}
-
-//-----------------------------Config List Function-----------------------------
-//#configlistFn
-async function configList(msg) {
-  let configKeys = Object.keys(config);
-  let serverSet = "",
-    colorSet = "";
-  for (var i = 1; i < 8; i++) {
-    serverSet += `${configKeys[i]} : \`${config[configKeys[i]]}\`\n`;
-  }
-  for (var i = 9; i < 14; i++) {
-    colorSet += `${configKeys[i]} : \`${config[configKeys[i]]}\`\n`;
-  }
-  var embed = new Discord.RichEmbed()
-    .setColor(config.info_color)
-    .setTitle("Config List")
-    .addField(
-      configKeys[0][0].toUpperCase() + configKeys[0].slice(1),
-      config[configKeys[0]]
-    ) //Get config.prefix name and it's value
-    .addField("Server Config", serverSet)
-    .addField(
-      configKeys[8][0].toUpperCase() + configKeys[8].slice(1),
-      config[configKeys[8]]
-    ) //Get config.maintenance name and it's value
-    .addField("Color Config", colorSet)
-    .setFooter(client.user.tag, client.user.avatarURL)
-    .setTimestamp();
-  return msg.channel.send(embed);
-}
-
-//-----------------------------Server List Function-----------------------------
-//#serverlistFn
-async function serverList(msg) {
-  let list =
-    client.guilds.map(g => `**${g.name}** \`(${g.id})\``).join("\n") ||
-    "The bot hasn't joined any server yet.";
-  return msg.channel.send(getEmbed(config.info_color, "Server List", list));
-}
-
-//----------------------------Leave Server Function-----------------------------
-//#leaveFn
-async function leaveServer(msg, server_ID) {
-  if (!server_ID) {
-    return msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Missing Argument",
-        "Usage : `leave [serverID]`"
-      )
-    );
-  }
-  let server = client.guilds.get(server_ID);
-  if (!server) {
-    return msg.channel.send(
-      getEmbed(
-        config.warning_color,
-        "Unidentified!",
-        `The bot isn't inside the server with serverID of \`(${server_ID})\`.`
-      )
-    );
-  } else {
-    server.leave();
-    return msg.channel.send(
-      getEmbed(
-        config.error_color,
-        "Leaving Server.",
-        `Leaving from **"${server.name}"** server.`
-      )
-    );
-  }
-}
-
-//+++++++++++++++++++++++++++Config Sync Function+++++++++++++++++++++++++++++++
-//#configSyncFn
-//syncing the variables value at #config with the database file
-async function configSync() {
-  client.user.setActivity("Syncing...", { type: "WATCHING" });
-  let configKeys = Object.keys(config);
-  var syncPromise = new Promise(resolve => {
-    configKeys.forEach(async aKey => {
-      try {
-        let getConfig = await ConfigDB.findOne({ where: { name: aKey } }).catch(
-          console.error
-        );
-        config[aKey] = getConfig.input || "empty";
-        resolve();
-      } catch (e) {
-        if (e.message == "Cannot read property 'input' of null") {
-          await resetConfig();
-          resolve();
-        }
-        return console.log(e);
-      }
-    });
-  });
-  syncPromise.then(() => {
-    console.log("Sync done.");
-  });
-}
-
-//==============================================================================
-//==================================READY=======================================
-//#botReady
-client.on("ready", async () => {
-  console.log("Syncing database....");
-  await BlockedDB.sync();
-  await ConfigDB.sync();
-  await configSync();
-  console.log(`Logged in as ${client.user.tag}!`);
-  client.user.setActivity("Ready.", { type: "WATCHING" });
-  //when i use local variable (config.maintenance), the configSync() is still in process.
-  let getMT = await ConfigDB.findOne({ where: { name: "maintenance" } }).catch(
-    console.error
-  );
-  if (getMT.input == "0") {
-    let index = 0;
-    setInterval(() => {
-      client.user.setActivity(activities[index], { type: "WATCHING" });
-      index++;
-      if (index == activities.length) index = 0;
-    }, 7000);
-  } else {
-    client.user.setActivity("Under Maintenance.", { type: "WATCHING" });
-  }
-});
-
-//==============================================================================
-//=================================NEW GUILD====================================
-//#botJoin
-client.on("guildCreate", async guild => {
-  client.users
-    .get(config.botOwnerID)
-    .send(
-      getEmbed(
-        config.info_color,
-        "Joined a Server",
-        `Joined \`${guild.name}\` server.\nServerID : \`${guild.id}\``
-      )
-    );
-});
-
-//==============================================================================
-//=================================MESSAGES=====================================
-//#newMessage
-client.on("message", async msg => {
-  if (msg.author.bot) return;
-
-  //----------------------------Local Variables---------------------------------
-
-  let cmd = msg.content
-    .slice(config.prefix.length)
-    .split(/ +/, 1)
-    .join(" ")
-    .toLowerCase();
-  let arg = msg.content
-    .split(/ +/)
-    .slice(1)
-    .join(" ");
-
-  //------------------------Command Message Handler-----------------------------
-  //checking from default config first so that you can always use default prefix to run any commands
-  if (
-    msg.content.indexOf(defConfig.prefix) == 0 ||
-    msg.content.indexOf(config.prefix) == 0
-  ) {
-    //-------------------------Restart Command----------------------------------
-    //#restartCmd
-    if (cmd == "restart") {
-      const embed = new Discord.RichEmbed()
-        .setTitle("Done.")
-        .setDescription(`Restarted in **${Math.floor(client.ping)}**ms`);
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner and Admin can use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          msg.channel.send(embed).then(() => {
-            process.exit(1);
-          });
-        } else {
-          return msg.channel.send(errorEmbed);
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          msg.channel.send(embed).then(() => {
-            process.exit(1);
-          });
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            msg.channel.send(embed).then(() => {
-              process.exit(1);
-            });
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //--------------------------Server List Command-----------------------------
-    //#serverlistCmd
-    else if (cmd == "serverlist") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner and Admin can use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await serverList(msg);
-        } else {
-          return msg.channel.send(errorEmbed);
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await serverList(msg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await serverList(msg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //--------------------------Leave Server Command----------------------------
-    //#leaveCmd
-    else if (cmd == "leave") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner can use this command."
-      );
-      if (msg.author.id === config.botOwnerID) {
-        await leaveServer(msg, arg);
-      } else {
-        return msg.channel.send(errorEmbed);
-      }
-    }
-
-    //---------------------------Command list Command---------------------------
-    //#cmdlistCmd
-    else if (cmd == "commands") {
-      let ownerLevel = "**leave** : Make the bot leave a specified server.";
-      let adminLevel =
-        "**restart** : Restart the bot.\n" +
-        "**reset** : Reset config values to default.\n" +
-        "**setup** : Setup config values.\n" +
-        "**configlist** : Show current config setting.\n" +
-        "**serverlist** : Show a list of servers that have this bot.";
-      let modLevel =
-        "**reply** : Reply to a user thread.\n" +
-        "**close** : Close a thread.\n" +
-        "**block** : Block a user.\n" +
-        "**blocklist** : Show list of blocked user.\n" +
-        "**unblock** : Remove a user from blocked list.";
-      let userLevel =
-        "**new** : Create a new thread.\n" +
-        "**help** : Show instruction about how to use the bot.\n" +
-        "**helpde** : Anleitung zur Verwendung des Bots anzeigen.\n" +
-        "**helptr** : Bot kullanımı hakkında talimat göster.\n" +
-        "**helpko** : 봇 사용 방법에 대한 지시 사항 표시.\n" +
-        "**helppt** : Mostrar instruções sobre como usar o bot.\n" +
-        "**helpfr** : Afficher les instructions sur l'utilisation du bot.\n" +
-        "**helpru** : Показать инструкцию о том, как использовать бот.\n" +
-        "**helpchs** : 显示如何使用操作这个系统的说明.\n" +
-        "**helpcht** : 顯示如何使用操作這個系統的說明.\n" +
-        "**helpes** : Mostrar instrucciones sobre cómo usar el bot.";
-      let ownerEmbed = new Discord.RichEmbed()
-        .setColor(config.info_color)
-        .setTitle("Command List")
-        .addField("Owner Level", ownerLevel)
-        .addField("Admin Level", adminLevel)
-        .addField("Moderator Level", modLevel)
-        .addField("User level", userLevel)
-        .setThumbnail(client.user.avatarURL)
-        .setFooter(client.user.tag, client.user.avatarURL)
-        .setTimestamp();
-      let adminEmbed = new Discord.RichEmbed()
-        .setColor(config.info_color)
-        .setTitle("Command List")
-        .addField("Admin Level", adminLevel)
-        .addField("Moderator Level", modLevel)
-        .addField("User level", userLevel)
-        .setThumbnail(client.user.avatarURL)
-        .setFooter(client.user.tag, client.user.avatarURL)
-        .setTimestamp();
-      let moderatorEmbed = new Discord.RichEmbed()
-        .setColor(config.info_color)
-        .setTitle("Command List")
-        .addField("Moderator Level", modLevel)
-        .addField("User level", userLevel)
-        .setThumbnail(client.user.avatarURL)
-        .setFooter(client.user.tag, client.user.avatarURL)
-        .setTimestamp();
-      let userEmbed = new Discord.RichEmbed()
-        .setColor(config.info_color)
-        .setTitle("Command List")
-        .addField("User level", userLevel)
-        .setThumbnail(client.user.avatarURL)
-        .setFooter(client.user.tag, client.user.avatarURL)
-        .setTimestamp();
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          msg.channel.send(ownerEmbed);
-        } else {
-          return msg.channel.send(userEmbed);
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          msg.channel.send(ownerEmbed);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            msg.channel.send(adminEmbed);
-          } else if (await roleCheck(msg, config.modRoleID)) {
-            msg.channel.send(moderatorEmbed);
-          } else {
-            msg.channel.send(userEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //-------------------------------Help Commands------------------------------
-    //#helpCmd
-    else if (cmd == "help") {
-      let embed = getEmbed(
-        config.info_color,
-        "Instruction",
-        "Use `=new Your thread title here` to create a new thread. You don't need to use any command after your thread created. Describe your issue afterward."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpde") {
-      let embed = getEmbed(
-        config.info_color,
-        "Anweisung",
-        "Verwenden Sie `=new Dein Threadtitel hier`, um einen neuen Thread zu erstellen (es wird **Thread Created!** Angezeigt). Sie müssen nach dem Erstellen Ihres Threads keinen Befehl mehr verwenden. Beschreiben Sie anschließend Ihr Problem."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helptr") {
-      let embed = getEmbed(
-        config.info_color,
-        "Talimat",
-        "Yeni bir bilet oluşturmak için `=new konuyu buraya yazın` kullanın (şu mesajı alırsınız: **Thread Created!**). Konuyu oluşturduktan sonra herhangi bir komut kullanmanıza gerek yoktur. Daha sonra sorununuzu açıklayın."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpko") {
-      let embed = getEmbed(
-        config.info_color,
-        "교수",
-        "`=new 스레드 제목을 여기에 사용하십시오` 새 스레드를 만들려면 **Thread Created!** 라고합니다. 스레드가 생성 된 후에는 명령을 사용할 필요가 없습니다. 나중에 문제를 설명하십시오."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helppt") {
-      let embed = getEmbed(
-        config.info_color,
-        "Instrução",
-        "Digite `=new O título do seu tópico aqui`. para criar um novo tópico (ele dirá **Thread Created!**). Você não precisa usar nenhum comando após a criação do seu thread. Descreva seu problema posteriormente."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpfr") {
-      let embed = getEmbed(
-        config.info_color,
-        "Instruction",
-        "Taper `=new le titre de votre sujet de discussion  ici` pour créer un nouveau sujet (ça va dire **Thread Created!**). Vous n'avez plus besoin d'utiliser de commande après la création du sujet. Décrivez simplement votre problème."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpru") {
-      let embed = getEmbed(
-        config.info_color,
-        "инструкция",
-        "Введите `=new заголовок вашей темы здесь`. создать новую тему (будет сказано **Thread Created!**). Вам не нужно использовать какую-либо команду после создания вашего потока. Опишите вашу проблему позже."
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpchs") {
-      let embed = getEmbed(
-        config.info_color,
-        "指令",
-        "在此处输入`=new 您的线程标题`。 创建一个新线程(它将显示为 **Thread Created!**)。 创建线程后,无需使用任何命令。 之后描述您的问题。"
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpcht") {
-      let embed = getEmbed(
-        config.info_color,
-        "指令",
-        "在此處輸入 `=new 您的線程標題`。 創建一個新線程(它將顯示為 **Thread Created!**)。 創建線程後,無需使用任何命令。 之後描述您的問題。"
-      );
-      msg.channel.send(embed);
-    } else if (cmd == "helpes") {
-      let embed = getEmbed(
-        config.info_color,
-        "Instrucción",
-        "Escribe `=new el título de su tema de discusión aquí` para crear un nuevo tema (esto mostrará **Thread Created!**). Ya no necesita usar un comando después de crear el asunto. Sólo tiene que describir su problema."
-      );
-      msg.channel.send(embed);
-    }
-
-    //----------------------------New Thread Command----------------------------
-    //#newThreadCmd
-    else if (cmd == "new") {
-      if (msg.guild == null) {
-        if (!arg) {
-          let embed = getEmbed(
-            config.warning_color,
-            "Missing Argument",
-            "Usage : `new [Thread Title]`"
-          );
-          return msg.channel.send(embed);
-        } else {
-          await newThread(msg, arg);
-        }
-      } else {
-        msg.channel.send(
-          getEmbed(
-            config.error_color,
-            "Command Unavailable",
-            "This command can only be used in Direct Message."
-          )
-        );
-      }
-    }
-
-    //----------------------------Thred Reply Command---------------------------
-    //#replyCmd
-    else if (cmd == "reply") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "You need to have moderator role to use this command."
-      );
-      if (msg.guild == null) {
-        return msg.channel.send(
-          getEmbed(
-            config.warning_color,
-            "Command Unavailable",
-            "You can't use this command in DM."
-          )
-        );
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await reply(msg, arg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.modRoleID)) ||
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await reply(msg, arg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //---------------------------Thread Close Command---------------------------
-    //#closeCmd
-    else if (cmd == "close") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "You need to have moderator role to use this command."
-      );
-      if (msg.guild == null) {
-        return msg.channel.send(
-          getEmbed(
-            config.warning_color,
-            "Command Unavailable",
-            "You can't use this command in DM."
-          )
-        );
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await close(msg, arg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.modRoleID)) ||
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await close(msg, arg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //---------------------------User Blocklist Command-------------------------
-    //#blocklistCmd
-    else if (cmd == "blocklist") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "You need to have moderator role to use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await blocklist(msg, arg);
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await blocklist(msg, arg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.modRoleID)) ||
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await blocklist(msg, arg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //---------------------------User Block Command-----------------------------
-    //#blockCmd
-    else if (cmd == "block") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "You need to have moderator role to use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await block(msg, arg);
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await block(msg, arg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.modRoleID)) ||
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await block(msg, arg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //----------------------------Unblock Command-------------------------------
-    //#unblockCmd
-    else if (cmd == "unblock") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "You need to have moderator role to use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await unblock(msg, arg);
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await unblock(msg, arg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.modRoleID)) ||
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await unblock(msg, arg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //-----------------------------Reset Config Command-------------------------
-    //#resetCmd
-    else if (cmd == "reset") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner and Admin can use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await resetConfig();
-          await configSync();
-          msg.channel.send(
-            getEmbed(
-              config.error_color,
-              "Success",
-              "Config values has been reseted."
-            )
-          );
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await resetConfig();
-          await configSync();
-          msg.channel.send(
-            getEmbed(
-              config.error_color,
-              "Success",
-              "Config values has been reseted."
-            )
-          );
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await resetConfig();
-            await configSync();
-            msg.channel.send(
-              getEmbed(
-                config.error_color,
-                "Success",
-                "Config values has been reseted."
-              )
-            );
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-
-    //----------------------------Config Setup Command--------------------------
-    //#setupCmd
-    else if (cmd == "setup") {
-      const noArgs = getEmbed(
-        config.warning_color,
-        "Missing Argument",
-        "Usage : `setup [config name] [config value]`\n\n`Note : The bot didn't check the value given please set correctly to avoid errors.`"
-      );
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner and Admin can use this command."
-      );
-      let tempArg,
-        configName,
-        configValue = "";
-      if (arg) {
-        tempArg = arg.split(/ +/);
-        configName = tempArg[0];
-        configValue = tempArg[1] || "empty";
-        configValue = configValue.toLowerCase();
-      }
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          if (!arg || !configName || !configValue) {
-            msg.channel.send(noArgs);
-          } else {
-            await setup(msg, configName, configValue);
-          }
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          if (!arg || !configName || !configValue) {
-            msg.channel.send(noArgs);
-          } else {
-            await setup(msg, configName, configValue);
-          }
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            if (!arg || !configName || !configValue) {
-              msg.channel.send(noArgs);
-            } else {
-              await setup(msg, configName, configValue);
-            }
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-    //----------------------------Config List Command---------------------------
-    //#configlistCmd
-    else if (cmd == "configlist") {
-      const errorEmbed = getEmbed(
-        config.error_color,
-        "Missing Permission",
-        "Only Owner and Admin can use this command."
-      );
-      if (msg.guild == null) {
-        if (msg.author.id === config.botOwnerID) {
-          await configList(msg);
-        } else {
-          return msg.channel.send(
-            getEmbed(
-              config.warning_color,
-              "Command Unavailable",
-              "You can't use this command in DM."
-            )
-          );
-        }
-      } else {
-        if (msg.author.id === config.botOwnerID) {
-          await configList(msg);
-        } else if (
-          msg.guild.id == config.serverID ||
-          (await permissionCheck(msg, "ADMINISTRATOR"))
-        ) {
-          if (
-            (await roleCheck(msg, config.adminRoleID)) ||
-            (await permissionCheck(msg, "ADMINISTRATOR"))
-          ) {
-            await configList(msg);
-          } else {
-            return msg.channel.send(errorEmbed);
-          }
-        } else {
-          if (config.serverID == "empty") {
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Warning!",
-                "The `serverID` value has not been set."
-              )
-            );
-          } else {
-            let serverName = await client.guilds.get(config.serverID).name;
-            msg.channel.send(
-              getEmbed(
-                config.warning_color,
-                "Not Main Server!",
-                `You need to be in **${serverName}** to use this command.`
-              )
-            );
-          }
-        }
-      }
-    }
-  }
-  //---------------------------UserDM Message Handler---------------------------
-  //#userDM
-  else if (msg.guild == null) {
-    try {
-      let getChannel = await client.guilds
-        .get(config.serverID)
-        .channels.find(ch => ch.name == msg.author.id);
-      if (getChannel) {
-        let IsMember = await isMember(msg);
-        let IsBlocked = await isBlocked(msg);
-        if (IsMember && !IsBlocked) {
-          userResponse(msg, getChannel);
-        }
-      }
-    } catch (e) {
-      if (e.message == "Cannot read property 'channels' of undefined")
-        return msg.channel.send(
-          getEmbed(
-            config.error_color,
-            "Error!",
-            "Bot configuration has not been set."
-          )
-        );
-      console.log(e);
-    }
-  }
-});
-
-//==============================================================================
-//==================================LOGIN=======================================
-
-client.login(process.env.TOKEN);
-require("http")
-  .createServer()
-  .listen();
-
-//==============================================================================
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DEPENDENCIES~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+//#dependencies
+console.log("[Loading Dependencies]");
+const Discord = require("discord.js");
+const { Util, Attachment } = require("discord.js");
+const client = new Discord.Client();
+const server = require("./server.js");
+const Sequelize = require("sequelize");
+const fs = require("fs");
+const moment = require("moment");
+const defConfig = require("./config.json");
+require("dotenv").config();
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~VARIABLES~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+console.log("[Loading Variables]");
+
+//#config (synced with database)
+var config = {
+  prefix: "",
+  botOwnerID: "",
+  mainServerID: "",
+  threadServerID: "",
+  categoryID: "",
+  logChannelID: "",
+  botChannelID: "",
+  adminRoleID: "",
+  modRoleID: "",
+  mentionedRoleID: "",
+  maintenance: "",
+  info_color: "",
+  warning_color: "",
+  error_color: "",
+  received_color: "",
+  sent_color: ""
+};
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~DATABASE~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+//#configDB
+const configDB = new Sequelize("database", "user", "password", {
+  host: "localhost",
+  dialect: "sqlite",
+  logging: false,
+  storage: "config.sqlite"
+});
+const ConfigDB = configDB.define("config", {
+  name: {
+    type: Sequelize.STRING,
+    unique: true
+  },
+  input: Sequelize.STRING
+});
+
+//#blockedDB
+const blockedDB = new Sequelize("database", "user", "password", {
+  host: "localhost",
+  dialect: "sqlite",
+  logging: false,
+  storage: "blocked.sqlite"
+});
+const BlockedDB = blockedDB.define("blocked", {
+  userID: {
+    type: Sequelize.STRING,
+    unique: true
+  },
+  modID: Sequelize.STRING,
+  reason: Sequelize.STRING
+});
+
+//#threadDB
+const threadDB = new Sequelize("database", "user", "password", {
+  host: "localhost",
+  dialect: "sqlite",
+  logging: false,
+  storage: "thread.sqlite"
+});
+const ThreadDB = configDB.define("thread", {
+  userID: {
+    type: Sequelize.STRING,
+    unique: true
+  },
+  channelID: {
+    type: Sequelize.STRING,
+    unique: true
+  },
+  threadTitle: Sequelize.STRING
+});
+
+//#commandsCollection
+client.commands = new Discord.Collection();
+const commandFiles = fs.readdirSync('./commands').filter(file => file.endsWith('.js'));
+for (const file of commandFiles) {
+	const cmd = require(`./commands/${file}`);
+	client.commands.set(cmd.name, cmd);
+}
+
+//#functionsCollection
+client.functions = new Discord.Collection();
+const functionFiles = fs.readdirSync('./functions').filter(file => file.endsWith('.js'));
+for (const file of functionFiles) {
+	const func = require(`./functions/${file}`);
+	client.functions.set(func.name, func);
+}
+
+//#parameter
+const param = {
+  Discord,
+  Attachment,
+  moment,
+  client,
+  ConfigDB,
+  ThreadDB,
+  BlockedDB,
+  config,
+  defConfig,
+  configSync: client.functions.get("configSync"),
+  getEmbed: client.functions.get("getEmbed"),
+  roleCheck: client.functions.get("roleCheck"),
+  isBlocked: client.functions.get("isBlocked"),
+  isMember: client.functions.get("isMember"),
+  reset: client.functions.get("reset"),
+  configuration: client.functions.get("configuration"),
+  configInfo: client.functions.get("configInfo"),
+  set: client.functions.get("set"),
+  bind: client.functions.get("bind"),
+  newThread: client.functions.get("newThread"),
+  threadInfo: client.functions.get("threadInfo"),
+  reply: client.functions.get("reply"),
+  areply: client.functions.get("areply"),
+  userReply: client.functions.get("userReply"),
+  close: client.functions.get("close"),
+  aclose: client.functions.get("aclose"),
+  block: client.functions.get("block"),
+  unblock: client.functions.get("unblock"),
+  blockinfo: client.functions.get("blockinfo"),
+  blocklist: client.functions.get("blocklist")
+}
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~READY~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+client.on('ready', async () => {
+  console.log("[Syncing Database]");
+  await BlockedDB.sync();
+  await ConfigDB.sync();
+  await ThreadDB.sync();
+  await param.configSync.execute(param); //cant make the bot waiting this guy to finish pfft
+
+  console.log(`Logged in as ${client.user.tag}!`);
+  //when i use local variable (config.maintenance), the configSync() is still in process that's why i use database value for this.
+  const getMaintenance = await ConfigDB.findOne({ where: { name: "maintenance" } }).catch(
+    error => {console.log(error)}
+  );
+  const getPrefix = await ConfigDB.findOne({ where: { name: "prefix" } }).catch(
+    error => {console.log(error)}
+  );
+
+  let isMaintenance
+  if(!getMaintenance){
+    isMaintenance = "0";
+  } else {
+    isMaintenance = await getMaintenance.input;
+  }
+
+  //#activities
+  let activities = []
+  if(getPrefix){
+    activities.push(`Glitch.com | ${getPrefix.input}commands`);
+    activities.push(`DM to contact Staff | ${getPrefix.input }help`);
+    activities.push(`DM, um Mitarbeiter zu kontaktieren | ${getPrefix.input}helpDE`);
+    activities.push(`Personel ile irtibata geçmek için DM | ${getPrefix.input}helpTR`);
+    activities.push(`직원에게 연락하는 DM | ${getPrefix.input}helpKR`);
+    activities.push(`DM para entrar em contato com a equipe | ${getPrefix.input}helpPT`);
+    activities.push(`DM contacte le personnel | ${getPrefix.input}helpFR`);
+    activities.push(`DM связаться с персоналом | ${getPrefix.input}helpRU`);
+    activities.push(`DM 与官方人员联系 | ${getPrefix.input}helpCHS`);
+    activities.push(`DM 與官方人員聯繫 | ${getPrefix.input}helpCHT`);
+    activities.push(`DM para contactar al personal | ${getPrefix.input}helpES`);
+  } else {
+    activities.push(`- Restart Me -`);
+  }
+
+  if (isMaintenance == "0") {
+    let index = 0;
+    setInterval(() => {
+      client.user.setActivity(activities[index], { type: "WATCHING" });
+      index++;
+      if (index == activities.length) index = 0;
+    }, 7000);
+  } else {
+    //using timeout since i can't make the bot wait for configSync() function to finish :(
+    setTimeout(()=> {
+      client.user.setActivity("~ Under Maintenance ~", { type: "STREAMING" });
+    }, 10000);
+  }
+});
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~NEW GUILD~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+client.on('guildCreate', async guild => {
+  const ownerID = config.botOwnerID;
+  if(ownerID){
+    const newServerEmbed = param.getEmbed.execute(param, config.info_color, "Joined a Guild", `[**${guild.name}**] (\`${guild.id}\`)`);
+    client.users.get(ownerID).send(newServerEmbed);
+  }
+  console.log(`Joined [${guild.name}] guild.`);
+});
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~MESSSAGES~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+client.on('message', async message => {
+	if(message.author.bot) return;
+  try {
+    //maintenance mode
+    if(config.maintenance == "1"){
+
+      const authorID = message.author.id;
+      const botOwnerID = config.botOwnerID;
+      const maintenanceEmbed = param.getEmbed.execute(param, config.error_color, "Maintenance", "All commands are disabled.");
+
+      if(message.guild == null && authorID != botOwnerID){
+        //in Direct Message and not bot owner
+        return message.channel.send(maintenanceEmbed);
+      } else if(config.mainServerID == "empty" && config.threadServerID == "empty") {
+        //the mainServerID and threadServerID empty
+        if(authorID != botOwnerID && !message.member.hasPermission('ADMINISTRATOR')){
+          //not bot owner and doesn't have ADMINISTRATOR permission
+          return message.channel.send(maintenanceEmbed);
+        };
+      } else if(config.mainServerID != "empty" && config.threadServerID != "empty"){
+        //mainServerID and threadServerID isn't empty
+        if(message.guild.id == config.mainServerID || message.guild.id == config.threadServerID){
+          //inside mainServerID or threadServerID
+          if(authorID != botOwnerID && !message.member.hasPermission('ADMINISTRATOR') && !param.roleCheck.execute(message, config.adminRoleID)){
+            //not bot owner and user doesn't have ADMINISTRATOR permission nor have Admin role
+            return message.channel.send(maintenanceEmbed);
+          }
+        } else {
+          //outside mainServerID and threadServerID
+          if(authorID != botOwnerID){
+            //not bot owner
+            return message.channel.send(maintenanceEmbed);
+          };
+        };
+      }
+    };
+
+  	let args, commandName = "";
+
+  	//checking wheter user use prefix or mention the bot
+  	let prefixIndex = message.content.indexOf(config.prefix);
+  	let botMentionIndex = message.content.indexOf("<@"+client.user.id+">");
+  	if (prefixIndex !== 0 && botMentionIndex !== 0){
+      if(message.guild != null){
+        return;
+      } else {
+        const isThread = await ThreadDB.findOne({where: {userID: message.author.id}});
+        if(!isThread){
+          return;
+        } else {
+          return param.userReply.execute(param, message, isThread);
+        }
+      }
+  	} else if (prefixIndex === 0){
+  		args = message.content.slice(config.prefix.length).split(/ +/);
+  		commandName = args.shift().toLowerCase();
+  	} else if (botMentionIndex === 0){
+  		args = message.content.slice(("<@"+client.user.id+">").length).split(/ +/);
+  		commandName = args.shift().toLowerCase();
+  	}
+
+    //finding command that was triggered
+    const command = client.commands.get(commandName) || client.commands.find(cmd => cmd.aliases && cmd.aliases.includes(commandName));
+
+    //user using prefix or mention bot, command name is invalid
+    if ((prefixIndex == 0 || botMentionIndex == 0) && !command) return;
+
+    //command is guildOnly, user trigger it inside Direct Message
+    if(command.guildOnly && message.channel.type !== 'text' && message.author.id != config.botOwnerID){
+      let noDMEmbed = param.getEmbed.execute(param, config.error_color, "Command Unavailable", "This command can\'t be used inside Direct Message.");
+      return message.channel.send(noDMEmbed);
+    }
+
+    //command need arguments to run, user did't gave any
+    if(command.args && !args.length){
+      let description = "You didn\'t provide any arguments."
+
+      if(command.usage) {
+        description += `\n**Usage** : \`${config.prefix}${command.name} ${command.usage}\``;
+      }
+      if(command.note){
+        description += `\n**Note** : \`${command.note}\``;
+      }
+
+      let noArgsEmbed = param.getEmbed.execute(param, config.warning_color, "Missing Arguments", description);
+      return message.channel.send(noArgsEmbed);
+    }
+
+    //command handler
+    //trying to execute the command
+  	await command.execute(param, message, args);
+	} catch (error) {
+    //catching error -> log it in console -> send error message to user
+		console.log(error);
+    let errorEmbed = param.getEmbed.execute(param, config.error_color, "An Error Occured.", `**Contact bot Owner** : <@${config.botOwnerID}>\n**Error Message** : \`${error.message}\``);
+		return message.channel.send(errorEmbed);
+	}
+
+});
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~LOGIN~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+client.login(process.env.TOKEN);
+require("https")
+  .createServer()
+  .listen();
+
+//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~