From 7b1fd7b4630fbac7161415f5ae7b82d9d3019582 Mon Sep 17 00:00:00 2001
From: Romain J <romain.ordi@gmail.com>
Date: Sat, 4 Jan 2020 21:16:37 +0100
Subject: [PATCH] refactor(cogs): prepare the env for new help command

---
 bot.py                                        |   9 +-
 cogs/Admin.py                                 |  48 ++--
 cogs/Help.py                                  | 217 +++---------------
 cogs/Logs.py                                  |   6 +-
 cogs/Polls.py                                 |   4 +-
 cogs/Useful.py                                | 100 ++++----
 cogs/User.py                                  |   8 +-
 extras/locales/en/LC_MESSAGES/admin_help.po   |  92 ++++++++
 extras/locales/en/LC_MESSAGES/basics.mo       | Bin 363 -> 0 bytes
 extras/locales/en/LC_MESSAGES/commands.mo     | Bin 28 -> 0 bytes
 .../en/LC_MESSAGES/{basics.po => help.po}     |  41 +---
 extras/locales/en/LC_MESSAGES/logs.po         |  17 ++
 extras/locales/en/LC_MESSAGES/poll_help.po    |  17 ++
 .../en/LC_MESSAGES/{utility.po => useful.po}  |  39 ++++
 extras/locales/en/LC_MESSAGES/useful_help.po  |  17 ++
 .../en/LC_MESSAGES/{commands.po => user.po}   |   0
 extras/locales/en/LC_MESSAGES/user_help.po    |  17 ++
 extras/locales/en/LC_MESSAGES/utility.mo      | Bin 669 -> 0 bytes
 extras/locales/fr/LC_MESSAGES/admin.mo        | Bin 1299 -> 1304 bytes
 extras/locales/fr/LC_MESSAGES/admin_help.po   |  92 ++++++++
 extras/locales/fr/LC_MESSAGES/basics.mo       | Bin 933 -> 0 bytes
 extras/locales/fr/LC_MESSAGES/basics.po       |  55 -----
 extras/locales/fr/LC_MESSAGES/commands.mo     | Bin 28 -> 0 bytes
 extras/locales/fr/LC_MESSAGES/help.po         |  22 ++
 extras/locales/fr/LC_MESSAGES/logs.po         |  17 ++
 extras/locales/fr/LC_MESSAGES/logs_help.po    |  17 ++
 extras/locales/fr/LC_MESSAGES/poll_help.po    |  17 ++
 .../fr/LC_MESSAGES/{utility.po => useful.po}  |  39 ++++
 extras/locales/fr/LC_MESSAGES/useful_help.po  |  17 ++
 .../fr/LC_MESSAGES/{commands.po => user.po}   |   0
 extras/locales/fr/LC_MESSAGES/user_help.po    |  17 ++
 extras/locales/fr/LC_MESSAGES/utility.mo      | Bin 1035 -> 0 bytes
 generate_locales.sh                           |  17 ++
 logs/tuxbot.log                               |  60 +++++
 venv/bin/activate                             |   2 +-
 venv/bin/activate.csh                         |   2 +-
 venv/bin/activate.fish                        |   2 +-
 venv/bin/chardetect                           |   2 +-
 venv/bin/easy_install                         |   2 +-
 venv/bin/import_expression                    |   2 +-
 venv/bin/pip                                  |   2 +-
 venv/bin/pip3                                 |   2 +-
 venv/bin/tcp-latency                          |   2 +-
 43 files changed, 657 insertions(+), 363 deletions(-)
 create mode 100644 extras/locales/en/LC_MESSAGES/admin_help.po
 delete mode 100644 extras/locales/en/LC_MESSAGES/basics.mo
 delete mode 100644 extras/locales/en/LC_MESSAGES/commands.mo
 rename extras/locales/en/LC_MESSAGES/{basics.po => help.po} (53%)
 create mode 100644 extras/locales/en/LC_MESSAGES/logs.po
 create mode 100644 extras/locales/en/LC_MESSAGES/poll_help.po
 rename extras/locales/en/LC_MESSAGES/{utility.po => useful.po} (70%)
 create mode 100644 extras/locales/en/LC_MESSAGES/useful_help.po
 rename extras/locales/en/LC_MESSAGES/{commands.po => user.po} (100%)
 create mode 100644 extras/locales/en/LC_MESSAGES/user_help.po
 delete mode 100644 extras/locales/en/LC_MESSAGES/utility.mo
 create mode 100644 extras/locales/fr/LC_MESSAGES/admin_help.po
 delete mode 100644 extras/locales/fr/LC_MESSAGES/basics.mo
 delete mode 100644 extras/locales/fr/LC_MESSAGES/basics.po
 delete mode 100644 extras/locales/fr/LC_MESSAGES/commands.mo
 create mode 100644 extras/locales/fr/LC_MESSAGES/help.po
 create mode 100644 extras/locales/fr/LC_MESSAGES/logs.po
 create mode 100644 extras/locales/fr/LC_MESSAGES/logs_help.po
 create mode 100644 extras/locales/fr/LC_MESSAGES/poll_help.po
 rename extras/locales/fr/LC_MESSAGES/{utility.po => useful.po} (66%)
 create mode 100644 extras/locales/fr/LC_MESSAGES/useful_help.po
 rename extras/locales/fr/LC_MESSAGES/{commands.po => user.po} (100%)
 create mode 100644 extras/locales/fr/LC_MESSAGES/user_help.po
 delete mode 100644 extras/locales/fr/LC_MESSAGES/utility.mo
 create mode 100755 generate_locales.sh

diff --git a/bot.py b/bot.py
index 10e78f9..5aa91d1 100755
--- a/bot.py
+++ b/bot.py
@@ -28,7 +28,7 @@ l_extensions: List[str] = [
     'cogs.Admin',
     'cogs.Help',
     'cogs.Logs',
-    'cogs.Monitoring',
+    # 'cogs.Monitoring',
     'cogs.Polls',
     'cogs.Useful',
     'cogs.User',
@@ -74,7 +74,8 @@ class TuxBot(commands.AutoShardedBot):
         self.cluster = self.fallbacks.find('True', key='This', first=True)
 
         self.version = Version(*version, pre_release='a5', build=build)
-        self.owner = int
+        self.owner: discord.User = discord.User
+        self.owners: List[discord.User] = []
 
         for extension in l_extensions:
             try:
@@ -153,6 +154,10 @@ class TuxBot(commands.AutoShardedBot):
         self.owner = await self.fetch_user(
             int(self.config.get('permissions', 'Owners').split(', ')[0])
         )
+        for owner in self.config.get('permissions', 'Owners').split(', '):
+            self.owners.append(
+                await self.fetch_user(int(owner))
+            )
 
     @staticmethod
     async def on_resumed():
diff --git a/cogs/Admin.py b/cogs/Admin.py
index 9be576b..d8dc58d 100644
--- a/cogs/Admin.py
+++ b/cogs/Admin.py
@@ -66,7 +66,7 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @groupExtra(name='say', invoke_without_command=True, category='admin',
-                description=Texts('commands').get('admin._say'))
+                description=Texts('admin_help').get('_say'))
     async def _say(self, ctx: commands.Context, *, content: str):
         if ctx.invoked_subcommand is None:
             try:
@@ -77,7 +77,7 @@ class Admin(commands.Cog):
             await ctx.send(content)
 
     @_say.command(name='edit',
-                  description=Texts('commands').get('admin._say_edit'))
+                  description=Texts('admin_help').get('_say_edit'))
     async def _say_edit(self, ctx: commands.Context, message_id: int, *,
                         content: str):
         try:
@@ -95,7 +95,7 @@ class Admin(commands.Cog):
                 delete_after=5)
 
     @_say.command(name='to',
-                  description=Texts('commands').get('admin._say_to'))
+                  description=Texts('admin_help').get('_say_to'))
     async def _say_to(self, ctx: commands.Context,
                       channel: Union[discord.TextChannel, discord.User], *,
                       content):
@@ -109,7 +109,7 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @commandExtra(name='ban', category='admin',
-                  description=Texts('commands').get('admin._ban'))
+                  description=Texts('admin_help').get('_ban'))
     async def _ban(self, ctx: commands.Context, user: discord.Member, *,
                    reason=""):
         try:
@@ -137,7 +137,7 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @commandExtra(name='kick', category='admin',
-                  description=Texts('commands').get('admin._kick'))
+                  description=Texts('admin_help').get('_kick'))
     async def _kick(self, ctx: commands.Context, user: discord.Member, *,
                     reason=""):
         try:
@@ -165,7 +165,7 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @commandExtra(name='clear', category='admin',
-                  description=Texts('commands').get('admin._clear'))
+                  description=Texts('admin_help').get('_clear'))
     async def _clear(self, ctx: commands.Context, count: int):
         try:
             await ctx.message.delete()
@@ -176,13 +176,13 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @groupExtra(name='react', category='admin',
-                description=Texts('commands').get('admin._react'))
+                description=Texts('admin_help').get('_react'))
     async def _react(self, ctx: commands.Context):
         if ctx.invoked_subcommand is None:
             await ctx.send_help('react')
 
     @_react.command(name='add',
-                    description=Texts('commands').get('admin._react_add'))
+                    description=Texts('admin_help').get('admin._react_add'))
     async def _react_add(self, ctx: commands.Context, message_id: int, *,
                          emojis: str):
         emojis: list = emojis.split(' ')
@@ -199,7 +199,7 @@ class Admin(commands.Cog):
                 delete_after=5)
 
     @_react.command(name='clear',
-                    description=Texts('commands').get('admin._react_remove'))
+                    description=Texts('admin_help').get('_react_remove'))
     async def _react_remove(self, ctx: commands.Context, message_id: int):
         try:
             message: discord.Message = await ctx.channel.fetch_message(
@@ -214,7 +214,7 @@ class Admin(commands.Cog):
 
     @groupExtra(name='delete', invoke_without_command=True,
                 category='admin',
-                description=Texts('commands').get('admin._delete'))
+                description=Texts('admin_help').get('_delete'))
     async def _delete(self, ctx: commands.Context, message_id: int):
         try:
             await ctx.message.delete()
@@ -231,7 +231,7 @@ class Admin(commands.Cog):
                 delete_after=5)
 
     @_delete.command(name='from', aliases=['to', 'in'],
-                     description=Texts('commands').get('admin._delete_from'))
+                     description=Texts('admin_help').get('_delete_from'))
     async def _delete_from(self, ctx: commands.Context,
                            channel: discord.TextChannel, message_id: int):
         try:
@@ -294,7 +294,7 @@ class Admin(commands.Cog):
         self.bot.database.session.commit()
 
     @groupExtra(name='warn', aliases=['warns'], category='admin',
-                description=Texts('commands').get('admin._warn'))
+                description=Texts('admin_help').get('_warn'))
     async def _warn(self, ctx: commands.Context):
         await ctx.trigger_typing()
         if ctx.invoked_subcommand is None:
@@ -307,7 +307,7 @@ class Admin(commands.Cog):
             await ctx.send(embed=e)
 
     @_warn.command(name='add', aliases=['new'],
-                   description=Texts('commands').get('admin._warn_new'))
+                   description=Texts('admin_help').get('_warn_new'))
     async def _warn_new(self, ctx: commands.Context, member: discord.Member,
                         *, reason="N/A"):
         member = await ctx.guild.fetch_member(member.id)
@@ -386,8 +386,8 @@ class Admin(commands.Cog):
                     f"\n**{Texts('admin', ctx).get('Reason')}:** `{reason}`"
         )
 
-    @_warn.command(name='remove', aliases=['revoke'],
-                   description=Texts('commands').get('admin._warn_remove'))
+    @_warn.command(name='remove', aliases=['revoke', 'del', 'delete'],
+                   description=Texts('admin_help').get('_warn_remove'))
     async def _warn_remove(self, ctx: commands.Context, warn_id: int):
         warn = self.bot.database.session \
             .query(WarnModel) \
@@ -399,8 +399,8 @@ class Admin(commands.Cog):
         await ctx.send(f"{Texts('admin', ctx).get('Warn with id')} `{warn_id}`"
                        f" {Texts('admin', ctx).get('successfully removed')}")
 
-    @_warn.command(name='show', aliases=['list'],
-                   description=Texts('commands').get('admin._warn_show'))
+    @_warn.command(name='show', aliases=['list', 'all'],
+                   description=Texts('admin_help').get('_warn_show'))
     async def _warn_show(self, ctx: commands.Context, member: discord.Member):
         warns_list, warns = await self.get_warn(ctx, member)
 
@@ -411,8 +411,8 @@ class Admin(commands.Cog):
 
         await ctx.send(embed=e)
 
-    @_warn.command(name='edit', aliases=['change'],
-                   description=Texts('commands').get('admin._warn_edit'))
+    @_warn.command(name='edit', aliases=['change', 'modify'],
+                   description=Texts('admin_help').get('_warn_edit'))
     async def _warn_edit(self, ctx: commands.Context, warn_id: int, *, reason):
         warn = self.bot.database.session \
             .query(WarnModel) \
@@ -429,7 +429,7 @@ class Admin(commands.Cog):
 
     @commandExtra(name='language', aliases=['lang', 'langue', 'langage'],
                   category='admin',
-                  description=Texts('commands').get('admin._language'))
+                  description=Texts('admin_help').get('_language'))
     async def _language(self, ctx: commands.Context, locale: str):
         available = self.bot.database.session \
             .query(LangModel.value) \
@@ -460,13 +460,13 @@ class Admin(commands.Cog):
     ###########################################################################
 
     @groupExtra(name='prefix', aliases=['prefixes'], category='admin',
-                description=Texts('commands').get('admin._prefix'))
+                description=Texts('admin_help').get('_prefix'))
     async def _prefix(self, ctx: commands.Context):
         if ctx.invoked_subcommand is None:
             await ctx.send_help('prefix')
 
     @_prefix.command(name='add', aliases=['set', 'new'],
-                     description=Texts('commands').get('admin._prefix_add'))
+                     description=Texts('admin_help').get('_prefix_add'))
     async def _prefix_add(self, ctx: commands.Context, prefix: str):
         if str(ctx.guild.id) in self.bot.prefixes:
             prefixes = self.bot.prefixes.get(
@@ -500,7 +500,7 @@ class Admin(commands.Cog):
         )
 
     @_prefix.command(name='remove', aliases=['drop', 'del', 'delete'],
-                     description=Texts('commands').get('admin._prefix_remove'))
+                     description=Texts('admin_help').get('_prefix_remove'))
     async def _prefix_remove(self, ctx: commands.Context, prefix: str):
         if str(ctx.guild.id) in self.bot.prefixes:
             prefixes = self.bot.prefixes.get(
@@ -529,7 +529,7 @@ class Admin(commands.Cog):
         )
 
     @_prefix.command(name='list', aliases=['show', 'all'],
-                     description=Texts('commands').get('admin._prefix_list'))
+                     description=Texts('admin_help').get('_prefix_list'))
     async def _prefix_list(self, ctx: commands.Context):
         extras = ['.']
         if ctx.message.guild is not None:
diff --git a/cogs/Help.py b/cogs/Help.py
index 1fd2794..64ba6a9 100644
--- a/cogs/Help.py
+++ b/cogs/Help.py
@@ -6,8 +6,7 @@ import discord
 from discord.ext import commands
 
 from bot import TuxBot
-from utils import FieldPages
-from utils import commandsPlus
+from utils import Texts
 
 log = logging.getLogger(__name__)
 
@@ -18,197 +17,51 @@ class HelpCommand(commands.HelpCommand):
         self.ignore_cogs = ["Monitoring", "Help", "Logs"]
         self.owner_cogs = []
 
-    def get_command_signature(self, command):
-        return f"[{command.cog.qualified_name.upper()}] > {command.qualified_name}"
-
-    def common_command_formatting(self, emb, command):
-        emb.title = self.get_command_signature(command)
-        if command.cog_name != "Jishaku":
-            emb.set_thumbnail(url=command.cog.big_icon)
-        try:
-            emb.description = f"{command.cog.qualified_name.lower()}_help " \
-                              f"{command.parent}_{command.name}_description"
-        except:
-            emb.description = f"{command.cog.qualified_name.lower()}_help " \
-                              f"{command.name}_description"
-        usage = "help.command_help.usage"
-        try:
-            if command.parent:
-                try:
-                    usg = f"{command.cog.qualified_name.lower()}_help " \
-                          f"{command.parent}_{command.name}_usage"
-                except:
-                    usg = f"{command.cog.qualified_name.lower()}_help " \
-                          f"{command.name}_usage"
-            else:
-                usg = f"{command.cog.qualified_name.lower()}_help " \
-                      f"{command.name}_usage"
-
-            emb.add_field(name=usage,
-                          value=f"{self.context.prefix}{command.qualified_name} " + usg)
-        except KeyError:
-            emb.add_field(name=usage,
-                          value=f"{self.context.prefix}{command.qualified_name}")
-        aliases = "`" + '`, `'.join(command.aliases) + "`"
-        if aliases == "``":
-            aliases = "help " \
-                      "help.command_help.no_aliases"
-
-        emb.add_field(name="help "
-                           "help.command_help.aliases",
-                      value=aliases)
-        return emb
-
-    async def command_callback(self, ctx, *, command=None):
-        await self.prepare_help_command(ctx, command)
-
-        if command is None:
-            mapping = self.get_bot_mapping()
-            return await self.send_bot_help(mapping)
-
-        cog = ctx.bot.get_cog(command.title())
-        if cog is not None:
-            return await self.send_cog_help(cog)
-
-        maybe_coro = discord.utils.maybe_coroutine
-
-        keys = command.split(' ')
-        cmd = ctx.bot.all_commands.get(keys[0])
-        if cmd is None:
-            string = await maybe_coro(self.command_not_found,
-                                      self.remove_mentions(keys[0]))
-            return await self.send_error_message(string)
-
-        for key in keys[1:]:
-            try:
-                found = cmd.all_commands.get(key)
-            except AttributeError:
-                string = await maybe_coro(self.subcommand_not_found, cmd,
-                                          self.remove_mentions(key))
-                return await self.send_error_message(string)
-            else:
-                if found is None:
-                    string = await maybe_coro(self.subcommand_not_found,
-                                              cmd,
-                                              self.remove_mentions(key))
-                    return await self.send_error_message(string)
-                cmd = found
-
-        if isinstance(cmd, commands.Group):
-            return await self.send_group_help(cmd)
-        else:
-            return await self.send_command_help(cmd)
-
     async def send_bot_help(self, mapping):
-        owner = self.context.bot.owner
-        emb = discord.Embed(color=discord.colour.Color.blue())
-        emb.description = "help " \
-                          "help.main_page.description".format(owner)
-        emb.set_author(icon_url=self.context.author.avatar_url,
-                       name=self.context.author)
+        owners = self.context.bot.owners
+        owners_name = [
+            f"{owner.name}#{owner.discriminator}"
+            for owner in owners
+        ]
+
+        e = discord.Embed(
+            color=discord.colour.Color.blue(),
+            description=Texts(
+                'help', self.context
+            ).get(
+                'main_page.description'
+            ).format(
+                ', '.join(owners_name[:-1]) + ' & ' + owners_name[-1]
+            )
+        )
+
+        e.set_author(
+            icon_url=self.context.author.avatar_url_as(format='png'),
+            name=self.context.author
+        )
 
         cogs = ""
         for extension in self.context.bot.cogs.values():
-            if self.context.author != owner and extension.qualified_name.upper() in self.owner_cogs:
+            if self.context.author not in owners \
+                    and extension.qualified_name in self.owner_cogs:
                 continue
-            if self.context.author == owner and extension.qualified_name in self.ignore_cogs:
+            if self.context.author in owners \
+                    and extension.qualified_name in self.ignore_cogs:
                 continue
             if extension.qualified_name == "Jishaku":
                 continue
             cogs += f"• {extension.icon} **{extension.qualified_name}**\n"
 
-        emb.add_field(name="help "
-                           "help.main_page.field_title.categories",
-                      value=cogs)
+        e.add_field(
+            name=Texts(
+                'help', self.context
+            ).get(
+                'main_page.categories'
+            ),
+            value=cogs
+        )
 
-        await self.context.send(embed=emb)
-
-    async def send_command_help(self, command):
-        if command.cog_name in self.ignore_cogs:
-            return await self.send_error_message(
-                self.command_not_found(command.name))
-
-        if isinstance(command, commandsPlus):
-            if command.name == "jishaku":
-                pass
-
-        formatted = self.common_command_formatting(
-            discord.Embed(color=discord.colour.Color.blue()), command)
-        await self.context.send(embed=formatted)
-
-    async def send_group_help(self, group):
-        if group.cog_name in self.ignore_cogs:
-            return await self.send_error_message(
-                self.command_not_found(group.name))
-
-        formatted = self.common_command_formatting(
-            discord.Embed(color=discord.colour.Color.blue()), group)
-        sub_cmd_list = ""
-        for group_command in group.commands:
-            try:
-                sub_cmd_list += f"`╚╡` **{group_command.name}** - " \
-                                f"{group.cog.qualified_name.lower()}_help " \
-                                f"{group_command.parent}_{group_command.name}_brief\n"
-            except Exception:
-                sub_cmd_list += f"`╚╡` **{group_command.name}** - " \
-                                f"{group.cog.qualified_name.lower()}_help" \
-                                f"{group_command.name}_brief\n"
-        subcommands = "help.command_help.subcommands"
-        formatted.add_field(name=subcommands, value=sub_cmd_list,
-                            inline=False)
-        await self.context.send(embed=formatted)
-
-    async def send_cog_help(self, cog):
-        if (
-                cog.qualified_name.upper() in self.owner_cogs
-                and not await self.context.bot.is_owner(self.context.author)
-        ) or cog.qualified_name.upper() in self.ignore_cogs:
-            return
-        if cog.qualified_name == "Jishaku":
-            return
-        if cog.qualified_name in self.ignore_cogs:
-            return
-
-        pages = {}
-        for cmd in cog.get_commands():
-            if not await self.context.bot.is_owner(
-                    self.context.author) and (
-                    cmd.hidden or cmd.category == "Hidden"):
-                continue
-            if cmd.category not in pages:
-                pages[cmd.category] = "```asciidoc\n"
-            cmd_brief = f"{cog.qualified_name.lower()}_help " \
-                        f"{cmd.name}_brief"
-            pages[
-                cmd.category] += f"{cmd.name}{' ' * int(17 - len(cmd.name))}:: {cmd_brief}\n"
-            if isinstance(cmd, commands.Group):
-                for group_command in cmd.commands:
-                    try:
-                        cmd_brief = f"{cog.qualified_name.lower()}_help " \
-                                    f"{group_command.parent}_{group_command.name}_brief"
-                    except Exception:
-                        cmd_brief = f"{cog.qualified_name.lower()}_help " \
-                                    f"{group_command.name}_brief"
-                    pages[
-                        cmd.category] += f"━ {group_command.name}{' ' * int(15 - len(group_command.name))}:: {cmd_brief}\n"
-        for e in pages:
-            pages[e] += "```"
-        formatted = []
-        for name, cont in pages.items():
-            formatted.append((name, cont))
-        footer_text = "help " \
-                      "help.category_page.footer_info".format(self.context.prefix)
-        pages = FieldPages(self.context,
-                           embed_color=discord.colour.Color.blue(),
-                           entries=formatted,
-                           title=cog.qualified_name.upper(),
-                           thumbnail=cog.big_icon,
-                           footertext=footer_text,
-                           per_page=1)
-        await pages.paginate()
-
-    def command_not_found(self, string):
-        return 'No command called "{}" found.'.format(string)
+        await self.context.send(embed=e)
 
 
 class Help(commands.Cog):
diff --git a/cogs/Logs.py b/cogs/Logs.py
index b8f50a9..2a551f2 100644
--- a/cogs/Logs.py
+++ b/cogs/Logs.py
@@ -241,7 +241,7 @@ class Logs(commands.Cog):
         await self.webhook.send(msg)
 
     @commandExtra(name='commandstats', hidden=True, category='logs',
-                  description=Texts('commands').get('logs._commandstats'))
+                  description=Texts('logs_help').get('_commandstats'))
     @commands.is_owner()
     async def _commandstats(self, ctx, limit=20):
         counter = self.bot.command_stats
@@ -257,7 +257,7 @@ class Logs(commands.Cog):
         await ctx.send(f'```\n{output}\n```')
 
     @commandExtra(name='socketstats', hidden=True, category='logs',
-                  description=Texts('commands').get('logs._socketstats'))
+                  description=Texts('logs_help').get('_socketstats'))
     @commands.is_owner()
     async def _socketstats(self, ctx):
         delta = datetime.datetime.utcnow() - self.bot.uptime
@@ -268,7 +268,7 @@ class Logs(commands.Cog):
             f'{total} socket events observed ({cpm:.2f}/minute):\n{self.bot.socket_stats}')
 
     @commandExtra(name='uptime', category='logs',
-                  description=Texts('commands').get('logs._uptime'))
+                  description=Texts('logs_help').get('_uptime'))
     async def _uptime(self, ctx):
         """Tells you how long the bot has been up for."""
         uptime = humanize.naturaltime(
diff --git a/cogs/Polls.py b/cogs/Polls.py
index b02e36e..be74efa 100644
--- a/cogs/Polls.py
+++ b/cogs/Polls.py
@@ -206,13 +206,13 @@ class Polls(commands.Cog):
 
     @groupExtra(name='sondage', aliases=['poll'],
                 category='poll',
-                description=Texts('commands').get('poll._poll'))
+                description=Texts('poll_help').get('_poll'))
     async def _poll(self, ctx: commands.Context):
         if ctx.invoked_subcommand is None:
             await ctx.send_help('sondage')
 
     @_poll.group(name='create', aliases=['new', 'nouveau'],
-                 description=Texts('commands').get('poll._poll_create'))
+                 description=Texts('poll_help').get('_poll_create'))
     async def _poll_create(self, ctx: commands.Context, *, poll: str):
         is_anonymous = '--anonyme' in poll
         poll = poll.replace('--anonyme', '')
diff --git a/cogs/Useful.py b/cogs/Useful.py
index f11433c..e9bd97a 100644
--- a/cogs/Useful.py
+++ b/cogs/Useful.py
@@ -38,8 +38,8 @@ class Useful(commands.Cog):
 
     ###########################################################################
 
-    @commandExtra(name='iplocalise', category='utility',
-                  description=Texts('commands').get('utility._iplocalise'))
+    @commandExtra(name='iplocalise', category='useful',
+                  description=Texts('useful_help').get('_iplocalise'))
     async def _iplocalise(self, ctx: commands.Context, addr, ip_type=''):
         addr = re.sub(r'http(s?)://', '', addr)
         addr = addr[:-1] if addr.endswith('/') else addr
@@ -52,7 +52,7 @@ class Useful(commands.Cog):
                     ip = socket.getaddrinfo(addr, None, AF_INET6)[1][4][0]
                 except socket.gaierror:
                     return await ctx.send(
-                        Texts('utility', ctx).get('ipv6 not available'))
+                        Texts('useful', ctx).get('ipv6 not available'))
             else:
                 ip = socket.gethostbyname(addr)
 
@@ -62,19 +62,19 @@ class Useful(commands.Cog):
 
                 if response.get('status') == 'success':
                     e = discord.Embed(
-                        title=f"{Texts('utility', ctx).get('Information for')}"
+                        title=f"{Texts('useful', ctx).get('Information for')}"
                               f" ``{addr}`` *`({response.get('query')})`*",
                         color=0x5858d7
                     )
 
                     e.add_field(
-                        name=Texts('utility', ctx).get('Belongs to :'),
+                        name=Texts('useful', ctx).get('Belongs to :'),
                         value=response.get('org', 'N/A'),
                         inline=False
                     )
 
                     e.add_field(
-                        name=Texts('utility', ctx).get('Is located at :'),
+                        name=Texts('useful', ctx).get('Is located at :'),
                         value=response.get('city', 'N/A'),
                         inline=True
                     )
@@ -93,18 +93,18 @@ class Useful(commands.Cog):
                     await ctx.send(embed=e)
                 else:
                     await ctx.send(
-                        content=f"{Texts('utility', ctx).get('info not available')}"
+                        content=f"{Texts('useful', ctx).get('info not available')}"
                                 f"``{response.get('query')}``")
 
         except Exception:
             await ctx.send(
-                f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
+                f"{Texts('useful', ctx).get('Cannot connect to host')} {addr}"
             )
 
     ###########################################################################
 
-    @commandExtra(name='getheaders', category='utility',
-                  description=Texts('commands').get('utility._getheaders'))
+    @commandExtra(name='getheaders', category='useful',
+                  description=Texts('useful_help').get('_getheaders'))
     async def _getheaders(self, ctx: commands.Context, addr: str):
         if (addr.startswith('http') or addr.startswith('ftp')) is not True:
             addr = f"http://{addr}"
@@ -114,7 +114,7 @@ class Useful(commands.Cog):
         try:
             async with self.bot.session.get(addr) as s:
                 e = discord.Embed(
-                    title=f"{Texts('utility', ctx).get('Headers of')} {addr}",
+                    title=f"{Texts('useful', ctx).get('Headers of')} {addr}",
                     color=0xd75858
                 )
                 e.add_field(name="Status", value=s.status, inline=True)
@@ -129,18 +129,18 @@ class Useful(commands.Cog):
 
         except aiohttp.client_exceptions.ClientError:
             await ctx.send(
-                f"{Texts('utility', ctx).get('Cannot connect to host')} {addr}"
+                f"{Texts('useful', ctx).get('Cannot connect to host')} {addr}"
             )
 
     ###########################################################################
 
     @commandExtra(name='git', aliases=['sources', 'source', 'github'],
-                  category='utility',
-                  description=Texts('commands').get('utility._git'))
+                  category='useful',
+                  description=Texts('useful_help').get('_git'))
     async def _git(self, ctx):
         e = discord.Embed(
-            title=Texts('utility', ctx).get('git repo'),
-            description=Texts('utility', ctx).get('git text'),
+            title=Texts('useful', ctx).get('git repo'),
+            description=Texts('useful', ctx).get('git text'),
             colour=0xE9D460
         )
         e.set_author(
@@ -151,8 +151,8 @@ class Useful(commands.Cog):
 
     ###########################################################################
 
-    @commandExtra(name='quote', category='utility',
-                  description=Texts('commands').get('utility._quote'))
+    @commandExtra(name='quote', category='useful',
+                  description=Texts('useful_help').get('_quote'))
     async def _quote(self, ctx, message_id: discord.Message):
         e = discord.Embed(
             colour=message_id.author.colour,
@@ -174,8 +174,8 @@ class Useful(commands.Cog):
 
     ###########################################################################
 
-    @commandExtra(name='ping', category='basics',
-                  description=Texts('commands').get('basics._ping'))
+    @commandExtra(name='ping', category='useful',
+                  description=Texts('useful_help').get('_ping'))
     async def _ping(self, ctx: commands.Context):
         start = time.perf_counter()
         await ctx.trigger_typing()
@@ -183,7 +183,7 @@ class Useful(commands.Cog):
 
         latency = round(self.bot.latency * 1000, 2)
         typing = round((end - start) * 1000, 2)
-        discordapp = measure_latency(host='google.com', wait=0)[0]
+        discordapp = measure_latency(host='discordapp.com', wait=0)[0]
 
         e = discord.Embed(title='Ping', color=discord.Color.teal())
         e.add_field(name='Websocket', value=f'{latency}ms')
@@ -195,44 +195,53 @@ class Useful(commands.Cog):
 
     @staticmethod
     def fetch_info():
-        total = 0
+        total_lines = 0
+        total_python_lines = 0
         file_amount = 0
+        python_file_amount = 0
         ENV = "env"
 
         for path, _, files in os.walk("."):
             for name in files:
                 file_dir = str(pathlib.PurePath(path, name))
-                if not name.endswith(".py") or ENV in file_dir:
+                if (
+                        not name.endswith(".py")
+                        and not name.endswith(".po")
+                        and not name.endswith(".json")
+                ) or ENV in file_dir:
                     continue
                 file_amount += 1
+                python_file_amount += 1 if name.endswith(".py") else 0
                 with open(file_dir, "r", encoding="utf-8") as file:
                     for line in file:
                         if not line.strip().startswith("#") \
                                 or not line.strip():
-                            total += 1
+                            total_lines += 1
+                            total_python_lines += 1 if name.endswith(".py") \
+                                else 0
 
-        return total, file_amount
+        return (file_amount, total_lines), (python_file_amount, total_python_lines)
 
-    @commandExtra(name='info', aliases=['about'], category='basics',
-                  description=Texts('commands').get('basics._info'))
+    @commandExtra(name='info', aliases=['about'], category='useful',
+                  description=Texts('useful_help').get('_info'))
     async def _info(self, ctx: commands.Context):
         proc = psutil.Process()
-        lines, files = self.fetch_info()
+        total, python = self.fetch_info()
 
         with proc.oneshot():
             mem = proc.memory_full_info()
             e = discord.Embed(
-                title=Texts('basics', ctx).get('Information about TuxBot'),
+                title=Texts('useful', ctx).get('Information about TuxBot'),
                 color=0x89C4F9)
 
             e.add_field(
-                name=f"__{Texts('basics', ctx).get('Latest changes')}__",
+                name=f"__{Texts('useful', ctx).get('Latest changes')}__",
                 value=self._latest_commits(),
                 inline=False)
 
             e.add_field(
                 name=f"__:busts_in_silhouette: "
-                     f"{Texts('basics', ctx).get('Development')}__",
+                     f"{Texts('useful', ctx).get('Development')}__",
                 value=f"**Romain#5117:** [git](https://git.gnous.eu/Romain)\n"
                       f"**Outout#4039:** [git](https://git.gnous.eu/mael)\n",
                 inline=True
@@ -246,45 +255,46 @@ class Useful(commands.Cog):
             e.add_field(
                 name="__:gear: Usage__",
                 value=f"**{humanize.naturalsize(mem.rss)}** "
-                      f"{Texts('basics', ctx).get('physical memory')}\n"
+                      f"{Texts('useful', ctx).get('physical memory')}\n"
                       f"**{humanize.naturalsize(mem.vms)}** "
-                      f"{Texts('basics', ctx).get('virtual memory')}\n",
+                      f"{Texts('useful', ctx).get('virtual memory')}\n",
                 inline=True
             )
 
             e.add_field(
-                name=f"__{Texts('basics', ctx).get('Servers count')}__",
+                name=f"__{Texts('useful', ctx).get('Servers count')}__",
                 value=str(len(self.bot.guilds)),
                 inline=True
             )
             e.add_field(
-                name=f"__{Texts('basics', ctx).get('Channels count')}__",
+                name=f"__{Texts('useful', ctx).get('Channels count')}__",
                 value=str(len([_ for _ in self.bot.get_all_channels()])),
                 inline=True
             )
             e.add_field(
-                name=f"__{Texts('basics', ctx).get('Members count')}__",
+                name=f"__{Texts('useful', ctx).get('Members count')}__",
                 value=str(len([_ for _ in self.bot.get_all_members()])),
                 inline=True
             )
 
             e.add_field(
-                name=f"__:file_folder: {Texts('basics', ctx).get('Files')}__",
-                value=str(files),
+                name=f"__:file_folder: {Texts('useful', ctx).get('Files')}__",
+                value=f"{total[0]} *({python[0]} <:python:596577462335307777>)*",
                 inline=True
             )
             e.add_field(
-                name=f"__¶ {Texts('basics', ctx).get('Lines')}__",
-                value=str(lines),
+                name=f"__¶ {Texts('useful', ctx).get('Lines')}__",
+                value=f"{total[1]} *({python[1]} <:python:596577462335307777>)*",
                 inline=True
             )
 
             e.add_field(
-                name=f"__:link: {Texts('basics', ctx).get('Links')}__",
+                name=f"__:link: {Texts('useful', ctx).get('Links')}__",
                 value="[tuxbot.gnous.eu](https://tuxbot.gnous.eu/) "
                       "| [gnous.eu](https://gnous.eu/) "
                       "| [git](https://git.gnous.eu/gnouseu/tuxbot-bot) "
-                      f"| [{Texts('basics', ctx).get('Invite')}](https://discordapp.com/oauth2/authorize?client_id=301062143942590465&scope=bot&permissions=268749888)",
+                      "| [status](https://status.gnous.eu/check/154250) "
+                      f"| [{Texts('useful', ctx).get('Invite')}](https://discordapp.com/oauth2/authorize?client_id=301062143942590465&scope=bot&permissions=268749888)",
                 inline=False
             )
 
@@ -296,11 +306,11 @@ class Useful(commands.Cog):
     ###########################################################################
 
     @commandExtra(name='credits', aliases=['contributors', 'authors'],
-                  category='basics',
-                  description=Texts('commands').get('basics._credits'))
+                  category='useful',
+                  description=Texts('useful_help').get('_credits'))
     async def _credits(self, ctx: commands.Context):
         e = discord.Embed(
-            title=Texts('basics', ctx).get('Contributors'),
+            title=Texts('useful', ctx).get('Contributors'),
             color=0x36393f
         )
 
diff --git a/cogs/User.py b/cogs/User.py
index 215052b..0ccfd98 100644
--- a/cogs/User.py
+++ b/cogs/User.py
@@ -20,13 +20,13 @@ class User(commands.Cog):
     ###########################################################################
 
     @groupExtra(name='alias', aliases=['aliases'], category='user',
-                description=Texts('commands').get('user._alias'))
+                description=Texts('user_help').get('user._alias'))
     async def _alias(self, ctx: commands.Context):
         if ctx.invoked_subcommand is None:
             await ctx.send_help('alias')
 
     @_alias.command(name='add', aliases=['set', 'new'],
-                    description=Texts('commands').get('user._alias_add'))
+                    description=Texts('user_help').get('_alias_add'))
     async def _alias_add(self, ctx: commands.Context, *, user_alias: str):
         is_global = False
         if '--global' in user_alias:
@@ -54,12 +54,12 @@ class User(commands.Cog):
         self.bot.database.session.commit()
 
     @_alias.command(name='remove', aliases=['drop', 'del', 'delete'],
-                    description=Texts('commands').get('user._alias_remove'))
+                    description=Texts('user_help').get('_alias_remove'))
     async def _alias_remove(self, ctx: commands.Context, prefix: str):
         ...
 
     @_alias.command(name='list', aliases=['show', 'all'],
-                    description=Texts('commands').get('user._alias_list'))
+                    description=Texts('user_help').get('_alias_list'))
     async def _alias_list(self, ctx: commands.Context):
         ...
 
diff --git a/extras/locales/en/LC_MESSAGES/admin_help.po b/extras/locales/en/LC_MESSAGES/admin_help.po
new file mode 100644
index 0000000..26257ac
--- /dev/null
+++ b/extras/locales/en/LC_MESSAGES/admin_help.po
@@ -0,0 +1,92 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
+msgid '_say'
+msgstr ''
+
+msgid '_say_edit'
+msgstr ''
+
+msgid '_say_to'
+msgstr ''
+
+###########################################################################
+
+msgid '_ban'
+msgstr ''
+
+###########################################################################
+
+msgid '_kick'
+msgstr ''
+
+###########################################################################
+
+msgid '_clear'
+msgstr ''
+
+###########################################################################
+
+msgid '_react'
+msgstr ''
+
+msgid '_react_remove'
+msgstr ''
+
+###########################################################################
+
+msgid '_delete'
+msgstr ''
+
+msgid '_delete_from'
+msgstr ''
+
+###########################################################################
+
+msgid '_warn'
+msgstr ''
+
+msgid '_warn_new'
+msgstr ''
+
+msgid '_warn_remove'
+msgstr ''
+
+msgid '_warn_show'
+msgstr ''
+
+msgid '_warn_edit'
+msgstr ''
+
+###########################################################################
+
+msgid '_language'
+msgstr ''
+
+###########################################################################
+
+msgid '_prefix'
+msgstr ''
+
+msgid '_prefix_add'
+msgstr ''
+
+msgid '_prefix_remove'
+msgstr ''
+
+msgid '_prefix_list'
+msgstr ''
\ No newline at end of file
diff --git a/extras/locales/en/LC_MESSAGES/basics.mo b/extras/locales/en/LC_MESSAGES/basics.mo
deleted file mode 100644
index e56e9c9c4f698196d1c9f23390bf6da85a3ddd45..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 363
zcmYjM!A`?43>^}u9yxQ!f!lCNCy=(VO$%!_D$;i9x=C;gn<+&jt<r$#hwyuR3#o)O
zEI-Nid$ON@&Q8C3E>0ZI9WJ`&UtGF+;z;ObD^tDU&O)?@Et;mRG$SiMf8a|&wjx_c
zY2vNY9Oed<bu5I+A|nGDjDWfvl3>K>b)OC>bwbGSv+TC~=^h2oAWk9V<UVC_)PG77
z;Yrn4$c@s?LD|YMve-yT5*`aO7BP?HjE7++*6XR0>f%Ec2sx^EMkG&`o6g%<%Gsgx
zD^pCpIEuy5ec)4XUTKTk-DqoP*5a4Fst>Bvw`BLKOoMi^$rms@>N+nkXh7&)wJ&wS
f$nd$e-V!w$_wXL>T1M)&K-(?z>y`xmjo14HFE3?c

diff --git a/extras/locales/en/LC_MESSAGES/commands.mo b/extras/locales/en/LC_MESSAGES/commands.mo
deleted file mode 100644
index 4b144831cf5f75c62f6e9446b91ce164bb3c8dee..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 28
Tcmca7#4?ou3S@vZ2*UsXEKdQ#

diff --git a/extras/locales/en/LC_MESSAGES/basics.po b/extras/locales/en/LC_MESSAGES/help.po
similarity index 53%
rename from extras/locales/en/LC_MESSAGES/basics.po
rename to extras/locales/en/LC_MESSAGES/help.po
index 89d6c26..8e535cf 100644
--- a/extras/locales/en/LC_MESSAGES/basics.po
+++ b/extras/locales/en/LC_MESSAGES/help.po
@@ -15,41 +15,8 @@ msgstr ""
 "Generated-By: pygettext.py 1.5\n"
 
 
-msgid "Information about TuxBot"
-msgstr ""
+msgid 'main_page.description'
+msgstr "Made by {}\nWhen using commands, <> means a required argument and [] means an optional argument.\n***(These symbols shouldn't be written)***"
 
-msgid "Latest changes"
-msgstr ""
-
-msgid "Development"
-msgstr ""
-
-msgid "physical memory"
-msgstr ""
-
-msgid "virtual memory"
-msgstr ""
-
-msgid "Servers count"
-msgstr ""
-
-msgid "Channels count"
-msgstr ""
-
-msgid "Members count"
-msgstr ""
-
-msgid "Links"
-msgstr ""
-
-msgid "Files"
-msgstr ""
-
-msgid "Lines"
-msgstr ""
-
-msgid "Invite"
-msgstr ""
-
-msgid "Contributors"
-msgstr ""
\ No newline at end of file
+msgid 'main_page.categories'
+msgstr 'Categories'
\ No newline at end of file
diff --git a/extras/locales/en/LC_MESSAGES/logs.po b/extras/locales/en/LC_MESSAGES/logs.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/en/LC_MESSAGES/logs.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/en/LC_MESSAGES/poll_help.po b/extras/locales/en/LC_MESSAGES/poll_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/en/LC_MESSAGES/poll_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/en/LC_MESSAGES/utility.po b/extras/locales/en/LC_MESSAGES/useful.po
similarity index 70%
rename from extras/locales/en/LC_MESSAGES/utility.po
rename to extras/locales/en/LC_MESSAGES/useful.po
index 0b9cb9b..904dd0b 100644
--- a/extras/locales/en/LC_MESSAGES/utility.po
+++ b/extras/locales/en/LC_MESSAGES/useful.po
@@ -15,6 +15,45 @@ msgstr ""
 "Generated-By: pygettext.py 1.5\n"
 
 
+msgid "Information about TuxBot"
+msgstr ""
+
+msgid "Latest changes"
+msgstr ""
+
+msgid "Development"
+msgstr ""
+
+msgid "physical memory"
+msgstr ""
+
+msgid "virtual memory"
+msgstr ""
+
+msgid "Servers count"
+msgstr ""
+
+msgid "Channels count"
+msgstr ""
+
+msgid "Members count"
+msgstr ""
+
+msgid "Links"
+msgstr ""
+
+msgid "Files"
+msgstr ""
+
+msgid "Lines"
+msgstr ""
+
+msgid "Invite"
+msgstr ""
+
+msgid "Contributors"
+msgstr ""
+
 msgid "ipv6 not available"
 msgstr "Error, this address is not available in IPv6."
 
diff --git a/extras/locales/en/LC_MESSAGES/useful_help.po b/extras/locales/en/LC_MESSAGES/useful_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/en/LC_MESSAGES/useful_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/en/LC_MESSAGES/commands.po b/extras/locales/en/LC_MESSAGES/user.po
similarity index 100%
rename from extras/locales/en/LC_MESSAGES/commands.po
rename to extras/locales/en/LC_MESSAGES/user.po
diff --git a/extras/locales/en/LC_MESSAGES/user_help.po b/extras/locales/en/LC_MESSAGES/user_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/en/LC_MESSAGES/user_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/en/LC_MESSAGES/utility.mo b/extras/locales/en/LC_MESSAGES/utility.mo
deleted file mode 100644
index 1d3d407b10a3deb876cc4fe3eb35607e2447569b..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 669
zcmY*XO>fgc5H+X=<YO;fI809*nsuBCs??;VZsG<DJBjj91cJjRo;X`MyVmYH#8>_U
z{2qP=Cw>d#s8Y+y&+l3LJp0DuzsE;E9a=|(SA<^k@ML`@{etlAf!D;x1Vy-f<~Toy
zUlM+k{zd$Um=UYzbjyVWjiovWi+k&ca(50=S>QV^3cf7RnP_#7E6d`H-Jv!@$p9u{
z|6@3e;4YfZ;_=9xjOVPckz3kj18y;ZGrx1ee7d^Oxd{9>r~aAmlaWnvCz>h`zRyuO
zW$Bm=LijKa()jetcoew_H<rycm!{xW=>TpQNdluVji48$VVqotgTXYK&92BQ^NQ!l
z=E%1JB;jbdXtMQ^<hl@^()pE}#%c7JzT^3BUrCFS&ZtWY+w|Tp3ohh4SZ%mAXfGG@
zTh@K_HCfiEStM5~6EY8=yA;+PqC`y%XY8g9psaJWO);;mq2s-Eoq4stQI-*2o5Qy@
zg8HeQPaDNskSVBD1>d=}U=<id*w!!<7Wor%vy};BXbP~!_b^gWYDKfz!U@E{x4?l8
zXpyFZ&GgoY1=tNjNiCg#3ma=o6SUhjaW9vuG9Fg#gCMrmen}Y#PNcQcEqYZL;8~{8
R7$EuI9|1x_JlUOl&Oesg!;Js{

diff --git a/extras/locales/fr/LC_MESSAGES/admin.mo b/extras/locales/fr/LC_MESSAGES/admin.mo
index cb6ea86b4d2b9b1b8667b9b8011ff08751d4cba5..ea265749b3b258f513073035eda8606bc166ea5f 100644
GIT binary patch
delta 204
zcmXZTJq`g;7=__;%|&um{!OTaMk%4g3T6e`(MeQFu>y%?8nKOO6-tdlLN8IX0)-d1
zdUD=;U*dLd8?TF!E=F?rz$(5lhc@%?1uU~`Siv5SxS3#!y$YlT?lHs^zyD|7uh?Nf
rv5h4wb#Y)d{5?zwb;1(+xWPOgeLrE7efPeT&>XVSBA(6Dn;8cm2%i@c

delta 198
zcmbQiHJNKdN<9w)1H(l|1_mx5eGf>B0_m4Pnhi+*hl;Z?F)#=N`GP=N1W2m_X<MM2
z6_Azz@++7b7$ku7R3I%0q}Ksykp2@;@$*1h1;~E^q?Ld)FALBNAZ@_HU<TF@1{4qn
m3KRfoBOu)Yq}hS=Zm9TSAT15#--goPCrdK!*?f!9ju`;^D;2E(

diff --git a/extras/locales/fr/LC_MESSAGES/admin_help.po b/extras/locales/fr/LC_MESSAGES/admin_help.po
new file mode 100644
index 0000000..26257ac
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/admin_help.po
@@ -0,0 +1,92 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
+msgid '_say'
+msgstr ''
+
+msgid '_say_edit'
+msgstr ''
+
+msgid '_say_to'
+msgstr ''
+
+###########################################################################
+
+msgid '_ban'
+msgstr ''
+
+###########################################################################
+
+msgid '_kick'
+msgstr ''
+
+###########################################################################
+
+msgid '_clear'
+msgstr ''
+
+###########################################################################
+
+msgid '_react'
+msgstr ''
+
+msgid '_react_remove'
+msgstr ''
+
+###########################################################################
+
+msgid '_delete'
+msgstr ''
+
+msgid '_delete_from'
+msgstr ''
+
+###########################################################################
+
+msgid '_warn'
+msgstr ''
+
+msgid '_warn_new'
+msgstr ''
+
+msgid '_warn_remove'
+msgstr ''
+
+msgid '_warn_show'
+msgstr ''
+
+msgid '_warn_edit'
+msgstr ''
+
+###########################################################################
+
+msgid '_language'
+msgstr ''
+
+###########################################################################
+
+msgid '_prefix'
+msgstr ''
+
+msgid '_prefix_add'
+msgstr ''
+
+msgid '_prefix_remove'
+msgstr ''
+
+msgid '_prefix_list'
+msgstr ''
\ No newline at end of file
diff --git a/extras/locales/fr/LC_MESSAGES/basics.mo b/extras/locales/fr/LC_MESSAGES/basics.mo
deleted file mode 100644
index f594e3b48f58cc9e4afff93239b7a51ca9432448..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 933
zcmY+C%Wl&^6o$=J$WSg7;v%t_4XbK`Q-Rc)wyK-BC90iNxm2Rv;3TK6!JaYWan$S(
zYgUzb0G54@z6ZPl4*-aNQlk_rCtuE-<C#C_pYMy;zgl?iBAy|>nB>y)3%^b6H{y<o
zE0%Q|d<xzGpMy`pCGaNL1Wo^LRX?cs4qU+cQAG{jL;e{w{ionM;v3>V@*h_(`hS9^
z{s+7TE?l#$$KWH-25aC$a1}J?w?U(806qW@!9_5u@=sNM3R;chNC-*`Hj<^#RznJ{
zl3}T(Dy$|=D3y6eC~PMw6;?|eNtH!9k%C1-S!&iVPqw5+VUlRFf=E-L*$A7)Xb%!`
z@%^E&Ldu4u{+-h!HJNAm@w7-rQOYvPq?%fjMCo##?kV}6Mw++Ad>=32aF^|Qja_fY
zXZwD)*Xp$Gy-uGu6wRdZCS<s5*{QE`2cH#IUv-_AOU|<6ppkcJl9*kpzPG;D<za_6
zJ@%&KhOMQ8PTRMGsL;HxB2lCfrs1;fK@hOE7y4|?54~2f={1{Ozt`J9tBA`eCf=tg
zb6McEcLqk=S`cieNlmJF!wy@aKUZI`Ikp)!Cd>QN9AY({=ofh!CE~RipDIYN5Bl4D
zW!`7B9FgL_7|C%WVwbH96K(I1Aca3X=37&j<<pq7*{qgNS-tkkw%RfqDq>?|MU+ZW
z%sr;kn0$UVb2+EV=h1P3Az!w-U`46^b9y#r+z%y8Z{@dn-*_Hhm`*rqem0ziipwj7
bxdKK(c7B%01QKW0;A2VimDxq0G$rdVUKjdo

diff --git a/extras/locales/fr/LC_MESSAGES/basics.po b/extras/locales/fr/LC_MESSAGES/basics.po
deleted file mode 100644
index 429badb..0000000
--- a/extras/locales/fr/LC_MESSAGES/basics.po
+++ /dev/null
@@ -1,55 +0,0 @@
-# SOME DESCRIPTIVE TITLE.
-# Copyright (C) YEAR ORGANIZATION
-# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
-#
-msgid ""
-msgstr ""
-"Project-Id-Version: PACKAGE VERSION\n"
-"POT-Creation-Date: 2019-09-08 19:04+0200\n"
-"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
-"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
-"Language-Team: LANGUAGE <LL@li.org>\n"
-"MIME-Version: 1.0\n"
-"Content-Type: text/plain; charset=UTF-8\n"
-"Content-Transfer-Encoding: 8bit\n"
-"Generated-By: pygettext.py 1.5\n"
-
-
-msgid "Information about TuxBot"
-msgstr "Informations sur TuxBot"
-
-msgid "Latest changes"
-msgstr "Derniers changements"
-
-msgid "Development"
-msgstr "Développement"
-
-msgid "physical memory"
-msgstr "mémoire physique"
-
-msgid "virtual memory"
-msgstr "mémoire virtuelle"
-
-msgid "Servers count"
-msgstr "Nombre de serveurs"
-
-msgid "Channels count"
-msgstr "Nombre de salons"
-
-msgid "Members count"
-msgstr "Nombre de membres"
-
-msgid "Links"
-msgstr "Liens"
-
-msgid "Files"
-msgstr "Fichiers"
-
-msgid "Lines"
-msgstr "Lignes"
-
-msgid "Invite"
-msgstr "Invitation"
-
-msgid "Contributors"
-msgstr "Contributeurs"
\ No newline at end of file
diff --git a/extras/locales/fr/LC_MESSAGES/commands.mo b/extras/locales/fr/LC_MESSAGES/commands.mo
deleted file mode 100644
index 4b144831cf5f75c62f6e9446b91ce164bb3c8dee..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 28
Tcmca7#4?ou3S@vZ2*UsXEKdQ#

diff --git a/extras/locales/fr/LC_MESSAGES/help.po b/extras/locales/fr/LC_MESSAGES/help.po
new file mode 100644
index 0000000..13ad1f4
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/help.po
@@ -0,0 +1,22 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
+msgid 'main_page.description'
+msgstr "Créé par {}\nLorsque vous utilisez les commandes, <> correspond à un argument obligatoire et [] à un argument optionnel.\n***(Vous ne devez pas écrire ces symboles)***"
+
+msgid 'main_page.categories'
+msgstr 'Catégories'
\ No newline at end of file
diff --git a/extras/locales/fr/LC_MESSAGES/logs.po b/extras/locales/fr/LC_MESSAGES/logs.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/logs.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/fr/LC_MESSAGES/logs_help.po b/extras/locales/fr/LC_MESSAGES/logs_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/logs_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/fr/LC_MESSAGES/poll_help.po b/extras/locales/fr/LC_MESSAGES/poll_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/poll_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/fr/LC_MESSAGES/utility.po b/extras/locales/fr/LC_MESSAGES/useful.po
similarity index 66%
rename from extras/locales/fr/LC_MESSAGES/utility.po
rename to extras/locales/fr/LC_MESSAGES/useful.po
index 2d1931e..89525c0 100644
--- a/extras/locales/fr/LC_MESSAGES/utility.po
+++ b/extras/locales/fr/LC_MESSAGES/useful.po
@@ -15,6 +15,45 @@ msgstr ""
 "Generated-By: pygettext.py 1.5\n"
 
 
+msgid "Information about TuxBot"
+msgstr "Informations sur TuxBot"
+
+msgid "Latest changes"
+msgstr "Derniers changements"
+
+msgid "Development"
+msgstr "Développement"
+
+msgid "physical memory"
+msgstr "mémoire physique"
+
+msgid "virtual memory"
+msgstr "mémoire virtuelle"
+
+msgid "Servers count"
+msgstr "Nombre de serveurs"
+
+msgid "Channels count"
+msgstr "Nombre de salons"
+
+msgid "Members count"
+msgstr "Nombre de membres"
+
+msgid "Links"
+msgstr "Liens"
+
+msgid "Files"
+msgstr "Fichiers"
+
+msgid "Lines"
+msgstr "Lignes"
+
+msgid "Invite"
+msgstr "Invitation"
+
+msgid "Contributors"
+msgstr "Contributeurs"
+
 msgid "ipv6 not available"
 msgstr "Erreur, cette adresse n'est pas disponible en IPv6."
 
diff --git a/extras/locales/fr/LC_MESSAGES/useful_help.po b/extras/locales/fr/LC_MESSAGES/useful_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/useful_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/fr/LC_MESSAGES/commands.po b/extras/locales/fr/LC_MESSAGES/user.po
similarity index 100%
rename from extras/locales/fr/LC_MESSAGES/commands.po
rename to extras/locales/fr/LC_MESSAGES/user.po
diff --git a/extras/locales/fr/LC_MESSAGES/user_help.po b/extras/locales/fr/LC_MESSAGES/user_help.po
new file mode 100644
index 0000000..cdc6fcd
--- /dev/null
+++ b/extras/locales/fr/LC_MESSAGES/user_help.po
@@ -0,0 +1,17 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR ORGANIZATION
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2019-09-08 19:04+0200\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"Generated-By: pygettext.py 1.5\n"
+
+
diff --git a/extras/locales/fr/LC_MESSAGES/utility.mo b/extras/locales/fr/LC_MESSAGES/utility.mo
deleted file mode 100644
index 9819573c3492b4f7fbaa2febc458016c16562908..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 1035
zcmZ9Kzi-n(6vvMr0}3FZ5=;oa4yXe-P09}yQwnZlT0_!AX<7u^HF-_0a_-FCIcit_
z1OzK$g_(f?rZVvdz=njx$jZjR*J*)*<*z=^_WR}c?#sl{=K@y=IuE7A!-4A^>=V#?
z=p6JBDtx~}r=aiq{0Sa|P8{0fS#Sc+7xq~NZ$UMvh<kEah>PG;@HqGuJOh3JPlBJo
z)8IGo1^5G80G}NZ;tKc~6bqah-FM^-g<?@^Z9H|2*4*{QyMb|DEVJyfb!0Y0qBo5l
zO0SG2SR!$hny&QRBk7T$uRK}K%-Ha}?S(=F6<Os-s#I>IEL1kS{@<&XHCredB)woA
zrI0?PR<w9OT8e2sZm%ZIl~SwO2^KAniw8B-3~8oPy%AJ!&r<b9Sh;$sGE=F*F=+Eh
z6<PNE9>!5SXf%UbM9a;vkz9JzT!~9{>3q<!QoB@oV?(;TR<F}a)QD*=ZbV7_PE@P4
z<JHx9xaxi``y6yw4nwL(D@$udZ*%qfom7>L?a!AQNhAK-eYIREEgJ1vqsC5#W{Yu5
zXQ@>BCUpnWI`+5LI(LKFzkWq8n{0zvcTG>}en_($%9oZ{vn_@kEbN4o?ey6f$;#Od
zRm;~(BFZvpy+SG4eTgk3!^}9RFl*{DIsUy-w#D~!YOwppvxv3deeK!7=ipu)WhS>`
z6@kj<yqB?!ojU5|+Y81Aka#dKl6+1h&bMh~l%*k#M6r5DOUknxXQ3fFP|oeXdYq&9
zZEDG)966JBm7__z2RnzAYeLq`w8f+uX`Ew?M&O-F>X|&{+)h%72Hs~boSw!xEBCd@
zU77Rgu>tygdjsu3BDNM0mq{I%#FW{<HqdDg|6Cl){e$e#f~9UTQ<A-LZAw~yQvCZt
WPqFjk#_(U6(c>YrM!@KLS^NTVb}<wH

diff --git a/generate_locales.sh b/generate_locales.sh
new file mode 100755
index 0000000..ee2ad88
--- /dev/null
+++ b/generate_locales.sh
@@ -0,0 +1,17 @@
+#!/bin/bash
+
+BASEDIR=$(pwd)
+
+cd "$BASEDIR/extras/locales/en/LC_MESSAGES"
+
+for i in *.po ; do
+  [[ -f "$i" ]] || continue
+  /usr/lib/python3.8/Tools/i18n/msgfmt.py -o "${i%.po}.mo" "${i%.po}"
+done
+
+cd "$BASEDIR/extras/locales/fr/LC_MESSAGES"
+
+for i in *.po ; do
+  [[ -f "$i" ]] || continue
+  /usr/lib/python3.8/Tools/i18n/msgfmt.py -o "${i%.po}.mo" "${i%.po}"
+done
\ No newline at end of file
diff --git a/logs/tuxbot.log b/logs/tuxbot.log
index e69de29..77d9fac 100644
--- a/logs/tuxbot.log
+++ b/logs/tuxbot.log
@@ -0,0 +1,60 @@
+[INFO   ] [2020-01-04 18:47:27] discord.client: logging in using static token
+[INFO   ] [2020-01-04 18:47:28] discord.gateway: Shard ID 0 has sent the IDENTIFY payload.
+[INFO   ] [2020-01-04 18:47:28] discord.gateway: Shard ID 0 has connected to Gateway: ["gateway-prd-main-1mb3",{"micros":59339,"calls":["discord-sessions-prd-1-26",{"micros":56634,"calls":["start_session",{"micros":36442,"calls":["api-prd-main-wpx2",{"micros":33053,"calls":["get_user",{"micros":2542},"add_authorized_ip",{"micros":1944},"get_guilds",{"micros":2441},"coros_wait",{"micros":1}]}]},"guilds_connect",{"micros":7,"calls":[]},"presence_connect",{"micros":1,"calls":[]}]}]}] (Session ID: 2e6c7d848985fce96ccf1d3a03a9878b).
+[INFO   ] [2020-01-04 18:47:38] discord.state: Processed a chunk for 462 members in guild ID 280805240977227776.
+[INFO   ] [2020-01-04 18:47:38] discord.state: Processed a chunk for 794 members in guild ID 331981755177238530.
+[INFO   ] [2020-01-04 18:47:38] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:39] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:39] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:40] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:40] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:41] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:41] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:42] discord.state: Processed a chunk for 1000 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:42] discord.state: Processed a chunk for 810 members in guild ID 296698073177128962.
+[INFO   ] [2020-01-04 18:47:45] cogs.Logs: 2020-01-04 17:48:03.502000: Romain#5117 in #general (Gnous): rm-dev01.info
+[INFO   ] [2020-01-04 18:49:07] cogs.Logs: 2020-01-04 17:49:25.331000: loup#8965 in #general (Gnous): rm-dev01.info
+[INFO   ] [2020-01-04 18:50:52] cogs.Logs: 2020-01-04 17:51:11.819000: Romain#5117 in #bot (Gnous): rm-dev01.jsk reloac cogs.Utility
+[INFO   ] [2020-01-04 18:50:58] cogs.Logs: 2020-01-04 17:51:16.650000: loup#8965 in #bot (Gnous): rm-dev01.info
+[INFO   ] [2020-01-04 18:50:58] cogs.Logs: 2020-01-04 17:51:17.057000: Romain#5117 in #bot (Gnous): rm-dev01.jsk reload cogs.Utility
+[INFO   ] [2020-01-04 18:51:09] cogs.Logs: 2020-01-04 17:51:28.317000: Romain#5117 in #bot (Gnous): rm-dev01.jsk reload cogs.Useful
+[INFO   ] [2020-01-04 18:51:18] cogs.Logs: 2020-01-04 17:51:36.366000: Romain#5117 in #bot (Gnous): rm-dev01.info
+[INFO   ] [2020-01-04 18:52:22] cogs.Logs: 2020-01-04 17:52:41.348000: loup#8965 in #bot (Gnous): rm-dev01.jsk
+[INFO   ] [2020-01-04 18:53:20] cogs.Logs: 2020-01-04 17:53:38.893000: Romain#5117 in #bots-spam (Mounak): rm-dev01.info
+[INFO   ] [2020-01-04 18:57:52] cogs.Logs: 2020-01-04 17:58:10.611000: Romain#5117 in #bot (Gnous): rm-dev01.jsk
+[INFO   ] [2020-01-04 18:59:40] cogs.Logs: 2020-01-04 17:59:59.117000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permission", "Owners")
+[INFO   ] [2020-01-04 18:59:49] cogs.Logs: 2020-01-04 18:00:08.291000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permissions", "Owners")
+[INFO   ] [2020-01-04 18:59:59] cogs.Logs: 2020-01-04 18:00:17.851000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permissions", "Owners")
+
+await _ctx.send(conf)
+[INFO   ] [2020-01-04 19:01:46] cogs.Logs: 2020-01-04 18:02:04.343000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permissions", "Owners")
+conf = conf.split(', ')
+conf.append(str(329989396218773504))
+
+conf = ', '.join(conf)
+
+await _ctx.send(conf)
+[INFO   ] [2020-01-04 19:02:06] cogs.Logs: 2020-01-04 18:02:25.221000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permissions", "Owners")
+conf = conf.split(', ')
+conf.append(str(a))
+
+conf = ', '.join(conf)
+
+_bot.config.set("permissions", "Owners", conf)
+[INFO   ] [2020-01-04 19:02:17] cogs.Logs: 2020-01-04 18:02:36.778000: Romain#5117 in #tuxbot-test (Gnous): rm-dev01.jsk py
+conf = _bot.config.get("permissions", "Owners")
+conf = conf.split(', ')
+conf.append(str(123456789))
+
+conf = ', '.join(conf)
+
+_bot.config.set("permissions", "Owners", conf)
+[INFO   ] [2020-01-04 19:05:37] discord.client: Cleaning up tasks.
+[INFO   ] [2020-01-04 19:05:37] discord.client: Cleaning up after 6 tasks.
+[INFO   ] [2020-01-04 19:05:37] discord.client: All tasks finished cancelling.
+[INFO   ] [2020-01-04 19:05:37] discord.client: Closing the event loop.
diff --git a/venv/bin/activate b/venv/bin/activate
index c9a2175..3f4bf1c 100644
--- a/venv/bin/activate
+++ b/venv/bin/activate
@@ -37,7 +37,7 @@ deactivate () {
 # unset irrelevant variables
 deactivate nondestructive
 
-VIRTUAL_ENV="/opt/tuxbot-bot/venv"
+VIRTUAL_ENV="/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv"
 export VIRTUAL_ENV
 
 _OLD_VIRTUAL_PATH="$PATH"
diff --git a/venv/bin/activate.csh b/venv/bin/activate.csh
index 83031a3..98060ea 100644
--- a/venv/bin/activate.csh
+++ b/venv/bin/activate.csh
@@ -8,7 +8,7 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
 # Unset irrelevant variables.
 deactivate nondestructive
 
-setenv VIRTUAL_ENV "/opt/tuxbot-bot/venv"
+setenv VIRTUAL_ENV "/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv"
 
 set _OLD_VIRTUAL_PATH="$PATH"
 setenv PATH "$VIRTUAL_ENV/bin:$PATH"
diff --git a/venv/bin/activate.fish b/venv/bin/activate.fish
index 49518e4..4963b20 100644
--- a/venv/bin/activate.fish
+++ b/venv/bin/activate.fish
@@ -29,7 +29,7 @@ end
 # unset irrelevant variables
 deactivate nondestructive
 
-set -gx VIRTUAL_ENV "/opt/tuxbot-bot/venv"
+set -gx VIRTUAL_ENV "/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv"
 
 set -gx _OLD_VIRTUAL_PATH $PATH
 set -gx PATH "$VIRTUAL_ENV/bin" $PATH
diff --git a/venv/bin/chardetect b/venv/bin/chardetect
index a43fcee..42fff1b 100755
--- a/venv/bin/chardetect
+++ b/venv/bin/chardetect
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys
diff --git a/venv/bin/easy_install b/venv/bin/easy_install
index 6475025..de4c6b6 100755
--- a/venv/bin/easy_install
+++ b/venv/bin/easy_install
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys
diff --git a/venv/bin/import_expression b/venv/bin/import_expression
index 0d4fa1e..0268679 100755
--- a/venv/bin/import_expression
+++ b/venv/bin/import_expression
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys
diff --git a/venv/bin/pip b/venv/bin/pip
index c8cec3c..6b21959 100755
--- a/venv/bin/pip
+++ b/venv/bin/pip
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys
diff --git a/venv/bin/pip3 b/venv/bin/pip3
index c8cec3c..6b21959 100755
--- a/venv/bin/pip3
+++ b/venv/bin/pip3
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys
diff --git a/venv/bin/tcp-latency b/venv/bin/tcp-latency
index f368ef6..1818b8f 100755
--- a/venv/bin/tcp-latency
+++ b/venv/bin/tcp-latency
@@ -1,4 +1,4 @@
-#!/opt/tuxbot-bot/venv/bin/python
+#!/home/romain/gnousEU/rm-dev01/tuxbot-bot/venv/bin/python
 # -*- coding: utf-8 -*-
 import re
 import sys