diff --git a/pyproject.toml b/pyproject.toml
index e1075c9..6fbf200 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,6 +15,8 @@ keywords = ["chat", "snek", "molodetz"]
 requires-python = ">=3.12"
 dependencies = [
     "mkdocs>=1.4.0",
+    "lxml",
+
     "shed",
     "app @ git+https://retoor.molodetz.nl/retoor/app",
     "beautifulsoup4",
diff --git a/src/snek/app.py b/src/snek/app.py
index dd3e0f3..984fcf3 100644
--- a/src/snek/app.py
+++ b/src/snek/app.py
@@ -1,13 +1,14 @@
-import pathlib
 import asyncio
-
 import logging
+import pathlib
 import time
 
-from snek.view.threads import ThreadsView 
+from snek.view.threads import ThreadsView
 
 logging.basicConfig(level=logging.DEBUG)
 
+from concurrent.futures import ThreadPoolExecutor
+
 from aiohttp import web
 from aiohttp_session import (
     get_session as session_get,
@@ -24,23 +25,24 @@ from snek.system import http
 from snek.system.cache import Cache
 from snek.system.markdown import MarkdownExtension
 from snek.system.middleware import cors_middleware
-from snek.system.template import LinkifyExtension, PythonExtension,EmojiExtension
+from snek.system.profiler import profiler_handler
+from snek.system.template import EmojiExtension, LinkifyExtension, PythonExtension
 from snek.view.about import AboutHTMLView, AboutMDView
+from snek.view.avatar import AvatarView
 from snek.view.docs import DocsHTMLView, DocsMDView
+from snek.view.drive import DriveView
 from snek.view.index import IndexView
 from snek.view.login import LoginView
 from snek.view.logout import LogoutView
 from snek.view.register import RegisterView
 from snek.view.rpc import RPCView
+from snek.view.search_user import SearchUserView
 from snek.view.status import StatusView
-from snek.view.web import WebView
+from snek.view.terminal import TerminalSocketView, TerminalView
 from snek.view.upload import UploadView
-from snek.view.search_user import SearchUserView 
-from snek.view.avatar import AvatarView
-from snek.system.profiler import profiler_handler
-from snek.view.terminal import TerminalView, TerminalSocketView
-from snek.view.drive import DriveView
-from  concurrent.futures import ThreadPoolExecutor
+from snek.view.web import WebView
+from snek.webdav import WebdavApplication
+
 SESSION_KEY = b"c79a0c5fda4b424189c427d28c9f7c34"
 
 
@@ -50,6 +52,15 @@ async def session_middleware(request, handler):
     response = await handler(request)
     return response
 
+
+@web.middleware
+async def trailing_slash_middleware(request, handler):
+    if request.path and not request.path.endswith("/"):
+        # Redirect to the same path with a trailing slash
+        raise web.HTTPFound(request.path + "/")
+    return await handler(request)
+
+
 class Application(BaseApplication):
 
     def __init__(self, *args, **kwargs):
@@ -68,9 +79,9 @@ class Application(BaseApplication):
         self.jinja2_env.add_extension(LinkifyExtension)
         self.jinja2_env.add_extension(PythonExtension)
         self.jinja2_env.add_extension(EmojiExtension)
-        
+
         self.setup_router()
-     
+
         self.cache = Cache(self)
         self.services = get_services(app=self)
         self.mappers = get_mappers(app=self)
@@ -81,7 +92,7 @@ class Application(BaseApplication):
 
     async def task_runner(self):
         while True:
-            task = await self.tasks.get() 
+            task = await self.tasks.get()
             self.db.begin()
             try:
                 task_start = time.time()
@@ -93,20 +104,20 @@ class Application(BaseApplication):
                 print(ex)
             self.db.commit()
 
-    async def prepare_database(self,app):
+    async def prepare_database(self, app):
         self.db.query("PRAGMA journal_mode=WAL")
         self.db.query("PRAGMA syncnorm=off")
 
         try:
             if not self.db["user"].has_index("username"):
                 self.db["user"].create_index("username", unique=True)
-            if not self.db["channel_member"].has_index(["channel_uid","user_uid"]):
-                self.db["channel_member"].create_index(["channel_uid","user_uid"])
-            if not self.db["channel_message"].has_index(["channel_uid","user_uid"]):
-                self.db["channel_message"].create_index(["channel_uid","user_uid"])
+            if not self.db["channel_member"].has_index(["channel_uid", "user_uid"]):
+                self.db["channel_member"].create_index(["channel_uid", "user_uid"])
+            if not self.db["channel_message"].has_index(["channel_uid", "user_uid"]):
+                self.db["channel_message"].create_index(["channel_uid", "user_uid"])
         except:
-            pass 
- 
+            pass
+
         await app.services.drive.prepare_all()
         self.loop.create_task(self.task_runner())
 
@@ -145,6 +156,8 @@ class Application(BaseApplication):
         self.router.add_view("/terminal.html", TerminalView)
         self.router.add_view("/drive.json", DriveView)
         self.router.add_view("/drive/{drive}.json", DriveView)
+        self.webdav = WebdavApplication(self)
+        self.add_subapp("/webdav", self.webdav)
 
         self.add_subapp(
             "/docs",
@@ -174,17 +187,21 @@ class Application(BaseApplication):
         channels = []
         if not context:
             context = {}
-        if request.session.get("uid"): 
-            async for subscribed_channel in self.services.channel_member.find(user_uid=request.session.get("uid"), deleted_at=None, is_banned=False):
+        if request.session.get("uid"):
+            async for subscribed_channel in self.services.channel_member.find(
+                user_uid=request.session.get("uid"), deleted_at=None, is_banned=False
+            ):
                 item = {}
-                other_user = await self.services.channel_member.get_other_dm_user(subscribed_channel["channel_uid"], request.session.get("uid"))
+                other_user = await self.services.channel_member.get_other_dm_user(
+                    subscribed_channel["channel_uid"], request.session.get("uid")
+                )
                 parent_object = await subscribed_channel.get_channel()
-                last_message =await parent_object.get_last_message()
-                color = None 
+                last_message = await parent_object.get_last_message()
+                color = None
                 if last_message:
                     last_message_user = await last_message.get_user()
                     color = last_message_user["color"]
-                item['color'] = color
+                item["color"] = color
                 item["last_message_on"] = parent_object["last_message_on"]
                 item["is_private"] = parent_object["tag"] == "dm"
                 if other_user:
@@ -193,19 +210,22 @@ class Application(BaseApplication):
                 else:
                     item["name"] = subscribed_channel["label"]
                     item["uid"] = subscribed_channel["channel_uid"]
-                item['new_count'] = subscribed_channel['new_count'] 
-                
+                item["new_count"] = subscribed_channel["new_count"]
+
                 print(item)
                 channels.append(item)
-            
-            channels.sort(key=lambda x: x['last_message_on'] or '', reverse=True)
-            if not 'channels' in context:
-                context['channels'] = channels
-            if not 'user' in context:
-                context['user'] = await self.services.user.get(uid=request.session.get("uid"))
+
+            channels.sort(key=lambda x: x["last_message_on"] or "", reverse=True)
+            if "channels" not in context:
+                context["channels"] = channels
+            if "user" not in context:
+                context["user"] = await self.services.user.get(
+                    uid=request.session.get("uid")
+                )
 
         return await super().render_template(template, request, context)
 
+
 executor = ThreadPoolExecutor(max_workers=200)
 
 loop = asyncio.get_event_loop()
@@ -213,8 +233,10 @@ loop.set_default_executor(executor)
 
 app = Application(db_path="sqlite:///snek.db")
 
+
 async def main():
     await web._run_app(app, port=8081, host="0.0.0.0")
 
+
 if __name__ == "__main__":
     asyncio.run(main())
diff --git a/src/snek/dump.py b/src/snek/dump.py
index 1b7eb6b..b254756 100644
--- a/src/snek/dump.py
+++ b/src/snek/dump.py
@@ -1,31 +1,39 @@
 import asyncio
-import json 
 
 from snek.app import app
 
+
 async def fix_message(message):
-    message = dict(
-        uid=message['uid'],
-        user_uid=message['user_uid'],
-        text=message['message'],
-        sent=message['created_at']
-    )
-    user = await app.services.user.get(uid=message['user_uid'])
-    message['user'] = user and user['username'] or None
-    return (message['user'] or '') + ': ' + (message['text'] or '')
+    message = {
+        "uid": message["uid"],
+        "user_uid": message["user_uid"],
+        "text": message["message"],
+        "sent": message["created_at"],
+    }
+    user = await app.services.user.get(uid=message["user_uid"])
+    message["user"] = user and user["username"] or None
+    return (message["user"] or "") + ": " + (message["text"] or "")
+
 
 async def dump_public_channels():
     result = []
-    for channel in app.db['channel'].find(is_private=False,is_listed=True,tag='public'):
+    for channel in app.db["channel"].find(
+        is_private=False, is_listed=True, tag="public"
+    ):
         print(f"Dumping channel: {channel['label']}.")
-        result += [await fix_message(record) for record in app.db['channel_message'].find(channel_uid=channel['uid'],order_by='created_at')]
+        result += [
+            await fix_message(record)
+            for record in app.db["channel_message"].find(
+                channel_uid=channel["uid"], order_by="created_at"
+            )
+        ]
         print("Dump succesfull!")
     print("Converting to json.")
     print("Converting succesful, now writing to dump.json")
-    with open("dump.txt","w") as f:
-        f.write('\n\n'.join(result))
+    with open("dump.txt", "w") as f:
+        f.write("\n\n".join(result))
     print("Dump written to dump.json")
-    
 
-if __name__ == '__main__':
+
+if __name__ == "__main__":
     asyncio.run(dump_public_channels())
diff --git a/src/snek/form/search_user.py b/src/snek/form/search_user.py
index 6f431f0..7e946b9 100644
--- a/src/snek/form/search_user.py
+++ b/src/snek/form/search_user.py
@@ -16,4 +16,3 @@ class SearchUserForm(Form):
     action = FormButtonElement(
         name="action", value="submit", text="Search", type="button"
     )
-
diff --git a/src/snek/mapper/__init__.py b/src/snek/mapper/__init__.py
index e4c67b0..96053ea 100644
--- a/src/snek/mapper/__init__.py
+++ b/src/snek/mapper/__init__.py
@@ -3,10 +3,10 @@ import functools
 from snek.mapper.channel import ChannelMapper
 from snek.mapper.channel_member import ChannelMemberMapper
 from snek.mapper.channel_message import ChannelMessageMapper
+from snek.mapper.drive import DriveMapper
+from snek.mapper.drive_item import DriveItemMapper
 from snek.mapper.notification import NotificationMapper
 from snek.mapper.user import UserMapper
-from snek.mapper.drive import DriveMapper 
-from snek.mapper.drive_item import DriveItemMapper
 from snek.system.object import Object
 
 
diff --git a/src/snek/mapper/drive.py b/src/snek/mapper/drive.py
index 970788a..c92c687 100644
--- a/src/snek/mapper/drive.py
+++ b/src/snek/mapper/drive.py
@@ -3,5 +3,5 @@ from snek.system.mapper import BaseMapper
 
 
 class DriveMapper(BaseMapper):
-    table_name = 'drive'
-    model_class = DriveModel 
+    table_name = "drive"
+    model_class = DriveModel
diff --git a/src/snek/mapper/drive_item.py b/src/snek/mapper/drive_item.py
index c35afe1..3d17a61 100644
--- a/src/snek/mapper/drive_item.py
+++ b/src/snek/mapper/drive_item.py
@@ -1,7 +1,8 @@
+from snek.model.drive_item import DriveItemModel
 from snek.system.mapper import BaseMapper
-from snek.model.drive_item import DriveItemModel 
+
 
 class DriveItemMapper(BaseMapper):
-    
+
     model_class = DriveItemModel
-    table_name = 'drive_item'
+    table_name = "drive_item"
diff --git a/src/snek/model/channel.py b/src/snek/model/channel.py
index 649299e..183ddb0 100644
--- a/src/snek/model/channel.py
+++ b/src/snek/model/channel.py
@@ -12,11 +12,16 @@ class ChannelModel(BaseModel):
     index = ModelField(name="index", required=True, kind=int, value=1000)
     last_message_on = ModelField(name="last_message_on", required=False, kind=str)
 
-    async def get_last_message(self)->ChannelMessageModel:
-        async for model in self.app.services.channel_message.query("SELECT uid FROM channel_message WHERE channel_uid=:channel_uid ORDER BY created_at DESC LIMIT 1",dict(channel_uid=self['uid'])):
-            
-            return await self.app.services.channel_message.get(uid=model['uid'])
+    async def get_last_message(self) -> ChannelMessageModel:
+        async for model in self.app.services.channel_message.query(
+            "SELECT uid FROM channel_message WHERE channel_uid=:channel_uid ORDER BY created_at DESC LIMIT 1",
+            {"channel_uid": self["uid"]},
+        ):
+
+            return await self.app.services.channel_message.get(uid=model["uid"])
         return None
 
     async def get_members(self):
-        return await self.app.services.channel_member.find(channel_uid=self['uid'],deleted_at=None,is_banned=False)
+        return await self.app.services.channel_member.find(
+            channel_uid=self["uid"], deleted_at=None, is_banned=False
+        )
diff --git a/src/snek/model/channel_member.py b/src/snek/model/channel_member.py
index 9689fa5..54b0418 100644
--- a/src/snek/model/channel_member.py
+++ b/src/snek/model/channel_member.py
@@ -16,25 +16,26 @@ class ChannelMemberModel(BaseModel):
     new_count = ModelField(name="new_count", required=False, kind=int, value=0)
 
     async def get_user(self):
-        return await self.app.services.user.get(uid=self['user_uid'])
-    
+        return await self.app.services.user.get(uid=self["user_uid"])
+
     async def get_channel(self):
-        return await self.app.services.channel.get(uid=self['channel_uid'])
+        return await self.app.services.channel.get(uid=self["channel_uid"])
 
     async def get_name(self):
         channel = await self.get_channel()
         if channel["tag"] == "dm":
             user = await self.get_other_dm_user()
-            return user['nick']
-        return channel['name'] or self['label']
+            return user["nick"]
+        return channel["name"] or self["label"]
 
     async def get_other_dm_user(self):
         channel = await self.get_channel()
         if channel["tag"] != "dm":
             return None
-        
-        async for model in self.app.services.channel_member.find(channel_uid=channel['uid']):
-            if model["uid"] != self['uid']:
+
+        async for model in self.app.services.channel_member.find(
+            channel_uid=channel["uid"]
+        ):
+            if model["uid"] != self["uid"]:
                 return await self.app.services.user.get(uid=model["user_uid"])
         return await self.get_user()
-        
diff --git a/src/snek/model/channel_message.py b/src/snek/model/channel_message.py
index 4b84fdc..524a8a4 100644
--- a/src/snek/model/channel_message.py
+++ b/src/snek/model/channel_message.py
@@ -8,8 +8,8 @@ class ChannelMessageModel(BaseModel):
     message = ModelField(name="message", required=True, kind=str)
     html = ModelField(name="html", required=False, kind=str)
 
-    async def get_user(self)->UserModel:
+    async def get_user(self) -> UserModel:
         return await self.app.services.user.get(uid=self["user_uid"])
-    
+
     async def get_channel(self):
-        return await self.app.services.channel.get(uid=self["channel_uid"])
\ No newline at end of file
+        return await self.app.services.channel.get(uid=self["channel_uid"])
diff --git a/src/snek/model/drive.py b/src/snek/model/drive.py
index 3936d97..df17d0f 100644
--- a/src/snek/model/drive.py
+++ b/src/snek/model/drive.py
@@ -1,13 +1,14 @@
-from snek.system.model import BaseModel,ModelField
+from snek.system.model import BaseModel, ModelField
 
 
 class DriveModel(BaseModel):
 
     user_uid = ModelField(name="user_uid", required=True)
-    name = ModelField(name='name', required=False, type=str) 
+    name = ModelField(name="name", required=False, type=str)
 
     @property
     async def items(self):
-        async for drive_item in self.app.services.drive_item.find(drive_uid=self['uid']):
+        async for drive_item in self.app.services.drive_item.find(
+            drive_uid=self["uid"]
+        ):
             yield drive_item
-
diff --git a/src/snek/model/drive_item.py b/src/snek/model/drive_item.py
index 728cd89..6e28f84 100644
--- a/src/snek/model/drive_item.py
+++ b/src/snek/model/drive_item.py
@@ -1,18 +1,20 @@
-from snek.system.model import BaseModel,ModelField 
 import mimetypes
 
+from snek.system.model import BaseModel, ModelField
+
+
 class DriveItemModel(BaseModel):
-    drive_uid = ModelField(name="drive_uid", required=True,kind=str)
-    name = ModelField(name="name", required=True,kind=str)
-    path = ModelField(name="path", required=True,kind=str)
-    file_type = ModelField(name="file_type", required=True,kind=str) 
-    file_size = ModelField(name="file_size", required=True,kind=int)
-    
+    drive_uid = ModelField(name="drive_uid", required=True, kind=str)
+    name = ModelField(name="name", required=True, kind=str)
+    path = ModelField(name="path", required=True, kind=str)
+    file_type = ModelField(name="file_type", required=True, kind=str)
+    file_size = ModelField(name="file_size", required=True, kind=int)
+
     @property
     def extension(self):
-        return self['name'].split('.')[-1]
-    
-    @property 
+        return self["name"].split(".")[-1]
+
+    @property
     def mime_type(self):
-        mimetype,_ = mimetypes.guess_type(self['name'])
-        return mimetype 
+        mimetype, _ = mimetypes.guess_type(self["name"])
+        return mimetype
diff --git a/src/snek/model/user.py b/src/snek/model/user.py
index 0621ecf..a35d890 100644
--- a/src/snek/model/user.py
+++ b/src/snek/model/user.py
@@ -18,10 +18,7 @@ class UserModel(BaseModel):
         regex=r"^[a-zA-Z0-9_-+/]+$",
     )
     color = ModelField(
-        name ="color",
-        required=True,
-        regex=r"^#[0-9a-fA-F]{6}$",
-        kind=str
+        name="color", required=True, regex=r"^#[0-9a-fA-F]{6}$", kind=str
     )
     email = ModelField(
         name="email",
@@ -33,5 +30,7 @@ class UserModel(BaseModel):
     last_ping = ModelField(name="last_ping", required=False, kind=str)
 
     async def get_channel_members(self):
-        async for channel_member in self.app.services.channel_member.find(user_uid=self['uid'],is_banned=False,deleted_at=None):
+        async for channel_member in self.app.services.channel_member.find(
+            user_uid=self["uid"], is_banned=False, deleted_at=None
+        ):
             yield channel_member
diff --git a/src/snek/service/__init__.py b/src/snek/service/__init__.py
index e521c7b..4059f77 100644
--- a/src/snek/service/__init__.py
+++ b/src/snek/service/__init__.py
@@ -4,12 +4,12 @@ from snek.service.channel import ChannelService
 from snek.service.channel_member import ChannelMemberService
 from snek.service.channel_message import ChannelMessageService
 from snek.service.chat import ChatService
+from snek.service.drive import DriveService
+from snek.service.drive_item import DriveItemService
 from snek.service.notification import NotificationService
 from snek.service.socket import SocketService
 from snek.service.user import UserService
 from snek.service.util import UtilService
-from snek.service.drive import DriveService
-from snek.service.drive_item import DriveItemService
 from snek.system.object import Object
 
 
@@ -26,7 +26,7 @@ def get_services(app):
             "notification": NotificationService(app=app),
             "util": UtilService(app=app),
             "drive": DriveService(app=app),
-            "drive_item": DriveItemService(app=app)
+            "drive_item": DriveItemService(app=app),
         }
     )
 
diff --git a/src/snek/service/channel.py b/src/snek/service/channel.py
index 95ceef7..b90e66f 100644
--- a/src/snek/service/channel.py
+++ b/src/snek/service/channel.py
@@ -1,30 +1,28 @@
-from snek.system.service import BaseService
-from datetime import datetime 
+from datetime import datetime
+
+from snek.system.model import now
+from snek.system.service import BaseService
 
-from snek.system.model import now 
 
 class ChannelService(BaseService):
     mapper_name = "channel"
 
-    async def get(
-        self,
-        uid=None,
-        **kwargs):
+    async def get(self, uid=None, **kwargs):
         if uid:
-            kwargs['uid'] = uid 
-            result = await super().get(**kwargs)
-            if result:
-                return result 
-            del kwargs['uid']
-            kwargs['name'] = uid 
+            kwargs["uid"] = uid
             result = await super().get(**kwargs)
             if result:
                 return result
-            kwargs['name'] = '#' + uid 
+            del kwargs["uid"]
+            kwargs["name"] = uid
             result = await super().get(**kwargs)
             if result:
                 return result
-            return None 
+            kwargs["name"] = "#" + uid
+            result = await super().get(**kwargs)
+            if result:
+                return result
+            return None
         return await super().get(**kwargs)
 
     async def create(
@@ -53,38 +51,34 @@ class ChannelService(BaseService):
         raise Exception(f"Failed to create channel: {model.errors}.")
 
     async def get_dm(self, user1, user2):
-        channel_member = await self.services.channel_member.get_dm(
-            user1, user2 
-        )
+        channel_member = await self.services.channel_member.get_dm(user1, user2)
         if channel_member:
             return await self.get(uid=channel_member["channel_uid"])
-        channel = await self.create(
-            "DM", user1, tag="dm"            
-        )
-        await self.services.channel_member.create_dm(
-            channel["uid"], user1, user2            
-        )
-        return channel 
+        channel = await self.create("DM", user1, tag="dm")
+        await self.services.channel_member.create_dm(channel["uid"], user1, user2)
+        return channel
 
     async def get_users(self, channel_uid):
-        users = []
         async for channel_member in self.services.channel_member.find(
             channel_uid=channel_uid,
             is_banned=False,
             is_muted=False,
             deleted_at=None,
         ):
-            user =  await self.services.user.get(uid=channel_member["user_uid"])
+            user = await self.services.user.get(uid=channel_member["user_uid"])
             if user:
                 yield user
+
     async def get_online_users(self, channel_uid):
-        users = []
         async for user in self.get_users(channel_uid):
             if not user["last_ping"]:
                 continue
 
-            if (datetime.fromisoformat(now()) - datetime.fromisoformat(user["last_ping"])).total_seconds() < 20:
-                yield user 
+            if (
+                datetime.fromisoformat(now())
+                - datetime.fromisoformat(user["last_ping"])
+            ).total_seconds() < 20:
+                yield user
 
     async def get_for_user(self, user_uid):
         async for channel_member in self.services.channel_member.find(
@@ -93,7 +87,7 @@ class ChannelService(BaseService):
             deleted_at=None,
         ):
             channel = await self.get(uid=channel_member["channel_uid"])
-            yield channel 
+            yield channel
 
     async def ensure_public_channel(self, created_by_uid):
         model = await self.get(is_listed=True, tag="public")
diff --git a/src/snek/service/channel_member.py b/src/snek/service/channel_member.py
index 5c6c7ee..16d1887 100644
--- a/src/snek/service/channel_member.py
+++ b/src/snek/service/channel_member.py
@@ -6,10 +6,7 @@ class ChannelMemberService(BaseService):
     mapper_name = "channel_member"
 
     async def mark_as_read(self, channel_uid, user_uid):
-        channel_member =  await self.get(
-            channel_uid=channel_uid,
-            user_uid=user_uid
-        )
+        channel_member = await self.get(channel_uid=channel_uid, user_uid=user_uid)
         channel_member["new_count"] = 0
         return await self.save(channel_member)
 
@@ -24,7 +21,7 @@ class ChannelMemberService(BaseService):
     ):
         model = await self.get(channel_uid=channel_uid, user_uid=user_uid)
         if model:
-            if model['is_banned']:
+            if model["is_banned"]:
                 return False
             return model
         model = await self.new()
@@ -39,30 +36,32 @@ class ChannelMemberService(BaseService):
         if await self.save(model):
             return model
         raise Exception(f"Failed to create channel member: {model.errors}.")
-    
-    async def get_dm(self,from_user, to_user):
-        async for model in self.query("SELECT channel_member.* FROM channel_member INNER JOIN channel ON (channel.uid = channel_member.channel_uid and channel.tag = 'dm') INNER JOIN channel_member AS channel_member2 ON(channel_member2.channel_uid = channel.uid AND channel_member2.user_uid = :to_user)   WHERE channel_member.user_uid=:from_user " ,dict(from_user=from_user, to_user=to_user)):
+
+    async def get_dm(self, from_user, to_user):
+        async for model in self.query(
+            "SELECT channel_member.* FROM channel_member INNER JOIN channel ON (channel.uid = channel_member.channel_uid and channel.tag = 'dm') INNER JOIN channel_member AS channel_member2 ON(channel_member2.channel_uid = channel.uid AND channel_member2.user_uid = :to_user)   WHERE channel_member.user_uid=:from_user ",
+            {"from_user": from_user, "to_user": to_user},
+        ):
             return model
         if not from_user == to_user:
-            return None 
-        async for model in self.query("SELECT channel_member.* FROM channel_member INNER JOIN channel ON (channel.uid = channel_member.channel_uid and channel.tag = 'dm') LEFT JOIN channel_member AS channel_member2 ON(channel_member2.channel_uid = NULL AND channel_member2.user_uid = NULL)   WHERE channel_member.user_uid=:from_user " ,dict(from_user=from_user, to_user=to_user)):
-           
-            return model 
-    
+            return None
+        async for model in self.query(
+            "SELECT channel_member.* FROM channel_member INNER JOIN channel ON (channel.uid = channel_member.channel_uid and channel.tag = 'dm') LEFT JOIN channel_member AS channel_member2 ON(channel_member2.channel_uid = NULL AND channel_member2.user_uid = NULL)   WHERE channel_member.user_uid=:from_user ",
+            {"from_user": from_user, "to_user": to_user},
+        ):
+
+            return model
+
     async def get_other_dm_user(self, channel_uid, user_uid):
         channel_member = await self.get(channel_uid=channel_uid, user_uid=user_uid)
-        channel = await self.services.channel.get(uid=channel_member['channel_uid'])
+        channel = await self.services.channel.get(uid=channel_member["channel_uid"])
         if channel["tag"] != "dm":
             return None
         async for model in self.services.channel_member.find(channel_uid=channel_uid):
-            if model["uid"] != channel_member['uid']:
+            if model["uid"] != channel_member["uid"]:
                 return await self.services.user.get(uid=model["user_uid"])
 
-    async def create_dm(self,channel_uid, from_user_uid, to_user_uid):
+    async def create_dm(self, channel_uid, from_user_uid, to_user_uid):
         result = await self.create(channel_uid, from_user_uid)
         await self.create(channel_uid, to_user_uid)
-        return result 
-
-
-
-
+        return result
diff --git a/src/snek/service/channel_message.py b/src/snek/service/channel_message.py
index 9683631..f8a000f 100644
--- a/src/snek/service/channel_message.py
+++ b/src/snek/service/channel_message.py
@@ -1,71 +1,93 @@
 from snek.system.service import BaseService
-import jinja2 
+
 
 class ChannelMessageService(BaseService):
     mapper_name = "channel_message"
 
     async def create(self, channel_uid, user_uid, message):
         model = await self.new()
-        
+
         model["channel_uid"] = channel_uid
         model["user_uid"] = user_uid
         model["message"] = message
-                
-        context = {
-            
-        }
-        
-        
-        record = model.record 
+
+        context = {}
+
+        record = model.record
         context.update(record)
         user = await self.app.services.user.get(uid=user_uid)
-        context.update(dict(
-            user_uid=user['uid'],
-            username=user['username'],
-            user_nick=user['nick'],
-            color=user['color']
-        ))
+        context.update(
+            {
+                "user_uid": user["uid"],
+                "username": user["username"],
+                "user_nick": user["nick"],
+                "color": user["color"],
+            }
+        )
         try:
             template = self.app.jinja2_env.get_template("message.html")
             model["html"] = template.render(**context)
         except Exception as ex:
-            print(ex,flush=True)
-        
+            print(ex, flush=True)
+
         if await self.save(model):
             return model
         raise Exception(f"Failed to create channel message: {model.errors}.")
-    
+
     async def to_extended_dict(self, message):
         user = await self.services.user.get(uid=message["user_uid"])
         if not user:
             return {}
         return {
             "uid": message["uid"],
-            "color": user['color'],
+            "color": user["color"],
             "user_uid": message["user_uid"],
             "channel_uid": message["channel_uid"],
-            "user_nick": user['nick'],
+            "user_nick": user["nick"],
             "message": message["message"],
             "created_at": message["created_at"],
-            "html": message['html'],
-            "username": user['username'] 
+            "html": message["html"],
+            "username": user["username"],
         }
 
-    async def offset(self, channel_uid, page=0, timestamp = None, page_size=30):
+    async def offset(self, channel_uid, page=0, timestamp=None, page_size=30):
         results = []
-        offset = page * page_size 
+        offset = page * page_size
         try:
             if timestamp:
-                async for model in self.query("SELECT * FROM channel_message WHERE channel_uid=:channel_uid AND created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",dict(channel_uid=channel_uid, page_size=page_size, offset=offset, timestamp=timestamp)):
+                async for model in self.query(
+                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid AND created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",
+                    {
+                        "channel_uid": channel_uid,
+                        "page_size": page_size,
+                        "offset": offset,
+                        "timestamp": timestamp,
+                    },
+                ):
                     results.append(model)
             elif page > 0:
-                async for model in self.query("SELECT * FROM channel_message WHERE channel_uid=:channel_uid WHERE created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size",dict(channel_uid=channel_uid, page_size=page_size, offset=offset,timestamp=timestamp )):
+                async for model in self.query(
+                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid WHERE created_at < :timestamp ORDER BY created_at DESC LIMIT :page_size",
+                    {
+                        "channel_uid": channel_uid,
+                        "page_size": page_size,
+                        "offset": offset,
+                        "timestamp": timestamp,
+                    },
+                ):
                     results.append(model)
-            else: 
-                async for model in self.query("SELECT * FROM channel_message WHERE channel_uid=:channel_uid ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",dict(channel_uid=channel_uid, page_size=page_size, offset=offset)):
+            else:
+                async for model in self.query(
+                    "SELECT * FROM channel_message WHERE channel_uid=:channel_uid ORDER BY created_at DESC LIMIT :page_size OFFSET :offset",
+                    {
+                        "channel_uid": channel_uid,
+                        "page_size": page_size,
+                        "offset": offset,
+                    },
+                ):
                     results.append(model)
 
-        except: 
+        except:
             pass
-        results.sort(key=lambda x: x['created_at'])
-        return results 
+        results.sort(key=lambda x: x["created_at"])
+        return results
diff --git a/src/snek/service/chat.py b/src/snek/service/chat.py
index 8b1f8ad..388d5c0 100644
--- a/src/snek/service/chat.py
+++ b/src/snek/service/chat.py
@@ -1,40 +1,39 @@
-
-
-
 from snek.system.model import now
 from snek.system.service import BaseService
 
 
 class ChatService(BaseService):
 
-    async def send(self,user_uid, channel_uid, message):
+    async def send(self, user_uid, channel_uid, message):
         channel = await self.services.channel.get(uid=channel_uid)
         if not channel:
             raise Exception("Channel not found.")
         channel_message = await self.services.channel_message.create(
-            channel_uid, 
-            user_uid, 
-            message
+            channel_uid, user_uid, message
         )
         channel_message_uid = channel_message["uid"]
-        
-        
+
         user = await self.services.user.get(uid=user_uid)
-        channel['last_message_on'] = now()
+        channel["last_message_on"] = now()
         await self.services.channel.save(channel)
-         
-        await self.services.socket.broadcast(channel_uid, dict(
-            message=channel_message["message"],
-            html=channel_message["html"],
-            user_uid=user_uid,
-            color=user['color'],
-            channel_uid=channel_uid,
-            created_at=channel_message["created_at"], 
-            updated_at=None,
-            username=user['username'],
-            uid=channel_message['uid'],
-            user_nick=user['nick']
-        ))
-        await self.app.create_task(self.services.notification.create_channel_message(channel_message_uid))
-       
+
+        await self.services.socket.broadcast(
+            channel_uid,
+            {
+                "message": channel_message["message"],
+                "html": channel_message["html"],
+                "user_uid": user_uid,
+                "color": user["color"],
+                "channel_uid": channel_uid,
+                "created_at": channel_message["created_at"],
+                "updated_at": None,
+                "username": user["username"],
+                "uid": channel_message["uid"],
+                "user_nick": user["nick"],
+            },
+        )
+        await self.app.create_task(
+            self.services.notification.create_channel_message(channel_message_uid)
+        )
+
         return True
diff --git a/src/snek/service/drive.py b/src/snek/service/drive.py
index b90a959..38035c7 100644
--- a/src/snek/service/drive.py
+++ b/src/snek/service/drive.py
@@ -2,14 +2,90 @@ from snek.system.service import BaseService
 
 
 class DriveService(BaseService):
-    
+
     mapper_name = "drive"
 
-    EXTENSIONS_PICTURES = ["jpg","jpeg","png","gif","svg","webp","tiff"]
-    EXTENSIONS_VIDEOS = ["mp4","m4v","mov","wmv","webm","mkv","mpg","mpeg","avi","ogv","ogg","flv","3gp","3g2"]
-    EXTENSIONS_ARCHIVES = ["zip","rar","7z","tar","tar.gz","tar.xz","tar.bz2","tar.lzma","tar.lz"]
-    EXTENSIONS_AUDIO = ["mp3","wav","ogg","flac","m4a","wma","aac","opus","aiff","au","mid","midi"]
-    EXTENSIONS_DOCS = ["pdf","doc","docx","xls","xlsx","ppt","pptx","txt","md","json","csv","xml","html","css","js","py","sql","rs","toml","yml","yaml","ini","conf","config","log","csv","tsv","java","cs","csproj","scss","less","sass","json","lock","lock.json","jsonl"]
+    EXTENSIONS_PICTURES = ["jpg", "jpeg", "png", "gif", "svg", "webp", "tiff"]
+    EXTENSIONS_VIDEOS = [
+        "mp4",
+        "m4v",
+        "mov",
+        "wmv",
+        "webm",
+        "mkv",
+        "mpg",
+        "mpeg",
+        "avi",
+        "ogv",
+        "ogg",
+        "flv",
+        "3gp",
+        "3g2",
+    ]
+    EXTENSIONS_ARCHIVES = [
+        "zip",
+        "rar",
+        "7z",
+        "tar",
+        "tar.gz",
+        "tar.xz",
+        "tar.bz2",
+        "tar.lzma",
+        "tar.lz",
+    ]
+    EXTENSIONS_AUDIO = [
+        "mp3",
+        "wav",
+        "ogg",
+        "flac",
+        "m4a",
+        "wma",
+        "aac",
+        "opus",
+        "aiff",
+        "au",
+        "mid",
+        "midi",
+    ]
+    EXTENSIONS_DOCS = [
+        "pdf",
+        "doc",
+        "docx",
+        "xls",
+        "xlsx",
+        "ppt",
+        "pptx",
+        "txt",
+        "md",
+        "json",
+        "csv",
+        "xml",
+        "html",
+        "css",
+        "js",
+        "py",
+        "sql",
+        "rs",
+        "toml",
+        "yml",
+        "yaml",
+        "ini",
+        "conf",
+        "config",
+        "log",
+        "csv",
+        "tsv",
+        "java",
+        "cs",
+        "csproj",
+        "scss",
+        "less",
+        "sass",
+        "json",
+        "lock",
+        "lock.json",
+        "jsonl",
+    ]
 
     async def get_drive_name_by_extension(self, extension):
         if extension.startswith("."):
@@ -26,54 +102,52 @@ class DriveService(BaseService):
             return "Documents"
         return "My Drive"
 
-    async def get_drive_by_extension(self,user_uid, extension):
+    async def get_drive_by_extension(self, user_uid, extension):
         name = await self.get_drive_name_by_extension(extension)
-        return await self.get_or_create(user_uid=user_uid,name=name)
+        return await self.get_or_create(user_uid=user_uid, name=name)
 
-    async def get_by_user(self, user_uid,name=None):
-        kwargs = dict(
-            user_uid = user_uid
-        )
+    async def get_by_user(self, user_uid, name=None):
+        kwargs = {"user_uid": user_uid}
         async for model in self.find(**kwargs):
             if not name:
-                yield model 
-            elif model['name'] == name:
                 yield model
-            elif not model['name'] and name == 'My Drive':
-                model['name'] = 'My Drive'
+            elif model["name"] == name:
+                yield model
+            elif not model["name"] and name == "My Drive":
+                model["name"] = "My Drive"
                 await self.save(model)
-                yield model 
+                yield model
 
-    async def get_or_create(self, user_uid,name=None,extensions=None):
-        kwargs = dict(user_uid=user_uid)
+    async def get_or_create(self, user_uid, name=None, extensions=None):
+        kwargs = {"user_uid": user_uid}
         if name:
-            kwargs['name'] = name
+            kwargs["name"] = name
         async for model in self.get_by_user(**kwargs):
-            return model  
+            return model
 
         model = await self.new()
-        model['user_uid'] = user_uid
-        model['name'] = name 
+        model["user_uid"] = user_uid
+        model["name"] = name
         await self.save(model)
-        return model 
+        return model
 
     async def prepare_default_drives(self):
         async for drive_item in self.services.drive_item.find():
             extension = drive_item.extension
-            drive = await self.get_drive_by_extension(drive_item['user_uid'],extension)
-            if not drive_item['drive_uid'] == drive['uid']:
-                drive_item['drive_uid'] = drive['uid']
+            drive = await self.get_drive_by_extension(drive_item["user_uid"], extension)
+            if not drive_item["drive_uid"] == drive["uid"]:
+                drive_item["drive_uid"] = drive["uid"]
                 await self.services.drive_item.save(drive_item)
-            
+
     async def prepare_default_drives_for_user(self, user_uid):
-        await self.get_or_create(user_uid=user_uid,name="My Drive")
-        await self.get_or_create(user_uid=user_uid,name="Shared Drive")
-        await self.get_or_create(user_uid=user_uid,name="Pictures")
-        await self.get_or_create(user_uid=user_uid,name="Videos")
-        await self.get_or_create(user_uid=user_uid,name="Archives")
-        await self.get_or_create(user_uid=user_uid,name="Documents")
+        await self.get_or_create(user_uid=user_uid, name="My Drive")
+        await self.get_or_create(user_uid=user_uid, name="Shared Drive")
+        await self.get_or_create(user_uid=user_uid, name="Pictures")
+        await self.get_or_create(user_uid=user_uid, name="Videos")
+        await self.get_or_create(user_uid=user_uid, name="Archives")
+        await self.get_or_create(user_uid=user_uid, name="Documents")
 
     async def prepare_all(self):
         await self.prepare_default_drives()
         async for user in self.services.user.find():
-            await self.prepare_default_drives_for_user(user['uid']) 
+            await self.prepare_default_drives_for_user(user["uid"])
diff --git a/src/snek/service/drive_item.py b/src/snek/service/drive_item.py
index 05a7da8..ce747c1 100644
--- a/src/snek/service/drive_item.py
+++ b/src/snek/service/drive_item.py
@@ -1,19 +1,19 @@
-from snek.system.service import BaseService 
+from snek.system.service import BaseService
 
 
 class DriveItemService(BaseService):
 
     mapper_name = "drive_item"
 
-    async def create(self, drive_uid, name, path, type_,size):
-        model = await self.new() 
-        model['drive_uid'] = drive_uid 
-        model['name'] = name 
-        model['path'] = str(path) 
-        model['extension'] = str(name).split(".")[-1]
-        model['file_type'] = type_ 
-        model['file_size'] = size
+    async def create(self, drive_uid, name, path, type_, size):
+        model = await self.new()
+        model["drive_uid"] = drive_uid
+        model["name"] = name
+        model["path"] = str(path)
+        model["extension"] = str(name).split(".")[-1]
+        model["file_type"] = type_
+        model["file_size"] = size
         if await self.save(model):
-            return model 
+            return model
         errors = await model.errors
         raise Exception(f"Failed to create drive item: {errors}.")
diff --git a/src/snek/service/notification.py b/src/snek/service/notification.py
index 1392044..a22e8ae 100644
--- a/src/snek/service/notification.py
+++ b/src/snek/service/notification.py
@@ -1,5 +1,6 @@
-from snek.system.service import BaseService
 from snek.system.model import now
+from snek.system.service import BaseService
+
 
 class NotificationService(BaseService):
     mapper_name = "notification"
@@ -7,13 +8,16 @@ class NotificationService(BaseService):
     async def mark_as_read(self, user_uid, channel_message_uid):
         model = await self.get(user_uid, object_uid=channel_message_uid)
         if not model:
-            return False 
-        model['read_at'] = now()
+            return False
+        model["read_at"] = now()
         await self.save(model)
-        return True 
-    
-    async def get_unread_stats(self,user_uid):
-        records = await self.query("SELECT object_type, COUNT(*) as count FROM notification WHERE user_uid=:user_uid AND read_at IS NULL GROUP BY object_type",dict(user_uid=user_uid))
+        return True
+
+    async def get_unread_stats(self, user_uid):
+        await self.query(
+            "SELECT object_type, COUNT(*) as count FROM notification WHERE user_uid=:user_uid AND read_at IS NULL GROUP BY object_type",
+            {"user_uid": user_uid},
+        )
 
     async def create(self, object_uid, object_type, user_uid, message):
         model = await self.new()
@@ -37,10 +41,10 @@ class NotificationService(BaseService):
             is_muted=False,
             deleted_at=None,
         ):
-            if not channel_member['new_count']:
-                channel_member['new_count'] = 0
-            channel_member['new_count'] += 1
-            
+            if not channel_member["new_count"]:
+                channel_member["new_count"] = 0
+            channel_member["new_count"] += 1
+
             usr = await self.services.user.get(uid=channel_member["user_uid"])
             if not usr:
                 continue
@@ -55,7 +59,7 @@ class NotificationService(BaseService):
             )
             try:
                 await self.save(model)
-            except Exception as ex:
+            except Exception:
                 raise Exception(f"Failed to create notification: {model.errors}.")
 
         self.app.db.commit()
diff --git a/src/snek/service/socket.py b/src/snek/service/socket.py
index d941321..072a86f 100644
--- a/src/snek/service/socket.py
+++ b/src/snek/service/socket.py
@@ -1,6 +1,4 @@
 from snek.model.user import UserModel
-
-
 from snek.system.service import BaseService
 
 
@@ -9,28 +7,27 @@ class SocketService(BaseService):
     class Socket:
         def __init__(self, ws, user: UserModel):
             self.ws = ws
-            self.is_connected = True 
-            self.user = user 
+            self.is_connected = True
+            self.user = user
 
         async def send_json(self, data):
             if not self.is_connected:
-                return False 
+                return False
             try:
                 await self.ws.send_json(data)
             except Exception as ex:
-                print(ex,flush=True)
+                print(ex, flush=True)
                 self.is_connected = False
-            return True 
+            return True
 
         async def close(self):
             if not self.is_connected:
-                return True 
-            
+                return True
+
             await self.ws.close()
             self.is_connected = False
-            
-            return True  
 
+            return True
 
     def __init__(self, app):
         super().__init__(app)
@@ -42,32 +39,31 @@ class SocketService(BaseService):
         s = self.Socket(ws, await self.app.services.user.get(uid=user_uid))
         self.sockets.add(s)
         if not self.users.get(user_uid):
-            self.users[user_uid] = set() 
+            self.users[user_uid] = set()
         self.users[user_uid].add(s)
 
-    async def subscribe(self, ws,channel_uid, user_uid):
+    async def subscribe(self, ws, channel_uid, user_uid):
         return
-        if not channel_uid in self.subscriptions:
+        if channel_uid not in self.subscriptions:
             self.subscriptions[channel_uid] = set()
-        s = self.Socket(ws,await self.app.services.user.get(uid=user_uid))
+        s = self.Socket(ws, await self.app.services.user.get(uid=user_uid))
         self.subscriptions[channel_uid].add(s)
 
     async def send_to_user(self, user_uid, message):
-        count = 0 
-        for s in self.users.get(user_uid,[]):
+        count = 0
+        for s in self.users.get(user_uid, []):
             if await s.send_json(message):
-               count += 1 
-        return count  
+                count += 1
+        return count
 
     async def broadcast(self, channel_uid, message):
-        count = 0
-        async for channel_member in self.app.services.channel_member.find(channel_uid=channel_uid):
-            await self.send_to_user(channel_member["user_uid"],message)
-        return True 
-    
+        async for channel_member in self.app.services.channel_member.find(
+            channel_uid=channel_uid
+        ):
+            await self.send_to_user(channel_member["user_uid"], message)
+        return True
+
     async def delete(self, ws):
         for s in [sock for sock in self.sockets if sock.ws == ws]:
             await s.close()
             self.sockets.remove(s)
-            
-    
diff --git a/src/snek/service/user.py b/src/snek/service/user.py
index 02707b0..6055403 100644
--- a/src/snek/service/user.py
+++ b/src/snek/service/user.py
@@ -1,16 +1,18 @@
+import pathlib
+
 from snek.system import security
 from snek.system.service import BaseService
 
 
 class UserService(BaseService):
     mapper_name = "user"
-    
+
     async def search(self, query, **kwargs):
         query = query.strip().lower()
         if not query:
             raise []
         results = []
-        async for result in self.find(username=dict(ilike='%' + query + '%'), **kwargs):
+        async for result in self.find(username={"ilike": "%" + query + "%"}, **kwargs):
             results.append(result)
         return results
 
@@ -23,17 +25,32 @@ class UserService(BaseService):
         return True
 
     async def save(self, user):
-        if not user['color']:
-            user['color'] = await self.services.util.random_light_hex_color()
+        if not user["color"]:
+            user["color"] = await self.services.util.random_light_hex_color()
         return await super().save(user)
 
+    async def authenticate(self, username, password):
+        print(username, password, flush=True)
+        success = await self.validate_login(username, password)
+        print(success, flush=True)
+        if not success:
+            return None
+
+        model = await self.get(username=username, deleted_at=None)
+        return model
+
+    async def get_home_folder(self, user_uid):
+        folder = pathlib.Path(f"./drive/{user_uid}")
+        if not folder.exists():
+            folder.mkdir(parents=True, exist_ok=True)
+        return folder
 
     async def register(self, email, username, password):
         if await self.exists(username=username):
             raise Exception("User already exists.")
         model = await self.new()
         model["nick"] = username
-        model['color'] = await self.services.util.random_light_hex_color()
+        model["color"] = await self.services.util.random_light_hex_color()
         model.email.value = email
         model.username.value = username
         model.password.value = await security.hash(password)
diff --git a/src/snek/service/util.py b/src/snek/service/util.py
index 5550a8c..b620d9c 100644
--- a/src/snek/service/util.py
+++ b/src/snek/service/util.py
@@ -1,15 +1,14 @@
 import random
 
-
 from snek.system.service import BaseService
 
 
 class UtilService(BaseService):
-    
+
     async def random_light_hex_color(self):
-   
+
         r = random.randint(128, 255)
         g = random.randint(128, 255)
         b = random.randint(128, 255)
-        
-        return "#{:02x}{:02x}{:02x}".format(r, g, b)
\ No newline at end of file
+
+        return f"#{r:02x}{g:02x}{b:02x}"
diff --git a/src/snek/system/cache.py b/src/snek/system/cache.py
index cd9484d..e97fdc3 100644
--- a/src/snek/system/cache.py
+++ b/src/snek/system/cache.py
@@ -20,13 +20,13 @@ class Cache:
         try:
             self.lru.pop(self.lru.index(args))
         except:
-            #print("Cache miss!", args, flush=True)
+            # print("Cache miss!", args, flush=True)
             return None
         self.lru.insert(0, args)
         while len(self.lru) > self.max_items:
             self.cache.pop(self.lru[-1])
             self.lru.pop()
-        #print("Cache hit!", args, flush=True)
+        # print("Cache hit!", args, flush=True)
         return self.cache[args]
 
     def json_default(self, value):
@@ -61,7 +61,7 @@ class Cache:
 
         if is_new:
             self.version += 1
-            #print(f"Cache store! {len(self.lru)} items. New version:", self.version, flush=True)
+            # print(f"Cache store! {len(self.lru)} items. New version:", self.version, flush=True)
 
     async def delete(self, args):
         if args in self.cache:
diff --git a/src/snek/system/markdown.py b/src/snek/system/markdown.py
index ca603d8..82a222e 100644
--- a/src/snek/system/markdown.py
+++ b/src/snek/system/markdown.py
@@ -1,7 +1,7 @@
 # Original source: https://brandonjay.dev/posts/2021/render-markdown-html-in-python-with-jinja2
 
 from types import SimpleNamespace
-from html import escape
+
 from app.cache import time_cache_async
 from mistune import HTMLRenderer, Markdown
 from pygments import highlight
@@ -24,21 +24,21 @@ class MarkdownRenderer(HTMLRenderer):
     def _escape(self, str):
         return str  ##escape(str)
 
-    def get_lexer(self, lang, default='bash'):
+    def get_lexer(self, lang, default="bash"):
         try:
             return get_lexer_by_name(lang, stripall=True)
         except:
             return get_lexer_by_name(default, stripall=True)
-    
+
     def block_code(self, code, lang=None, info=None):
         if not lang:
             lang = info
         if not lang:
-            lang = 'bash'
+            lang = "bash"
         lexer = self.get_lexer(lang)
         formatter = html.HtmlFormatter(lineseparator="<br>")
         result = highlight(code, lexer, formatter)
-        return result 
+        return result
 
     def render(self):
         markdown_string = self.app.template_path.joinpath(self.template).read_text()
diff --git a/src/snek/system/middleware.py b/src/snek/system/middleware.py
index 2946262..1a6c7e6 100644
--- a/src/snek/system/middleware.py
+++ b/src/snek/system/middleware.py
@@ -20,7 +20,9 @@ async def no_cors_middleware(request, handler):
 async def cors_allow_middleware(request, handler):
     response = await handler(request)
     response.headers["Access-Control-Allow-Origin"] = "*"
-    response.headers["Access-Control-Allow-Methods"] = "GET, POST, OPTIONS, PUT, DELETE"
+    response.headers["Access-Control-Allow-Methods"] = (
+        "GET, POST, OPTIONS, PUT, DELETE, MOVE, COPY, HEAD, LOCK, UNLOCK, PATCH, PROPFIND"
+    )
     response.headers["Access-Control-Allow-Headers"] = "*"
     response.headers["Access-Control-Allow-Credentials"] = "true"
     return response
@@ -28,17 +30,12 @@ async def cors_allow_middleware(request, handler):
 
 @web.middleware
 async def cors_middleware(request, handler):
-    if request.method == "OPTIONS":
-        response = web.Response()
-        response.headers["Access-Control-Allow-Origin"] = "*"
-        response.headers["Access-Control-Allow-Methods"] = (
-            "GET, POST, PUT, DELETE, OPTIONS"
-        )
-        response.headers["Access-Control-Allow-Headers"] = "*"
-        response.headers["Access-Control-Allow-Credentials"] = "true"
-        return response
+    if request.headers.get("Allow"):
+        return await handler(request)
 
     response = await handler(request)
+    if request.headers.get("Allow"):
+        return response
     response.headers["Access-Control-Allow-Origin"] = "*"
     response.headers["Access-Control-Allow-Methods"] = "GET, POST, PUT, DELETE, OPTIONS"
     response.headers["Access-Control-Allow-Headers"] = "*"
diff --git a/src/snek/system/profiler.py b/src/snek/system/profiler.py
index 193bbb7..e0e5542 100644
--- a/src/snek/system/profiler.py
+++ b/src/snek/system/profiler.py
@@ -1,24 +1,27 @@
 import cProfile
 import pstats
-import sys 
+import sys
+
 from aiohttp import web
+
 profiler = None
-import io 
+import io
 
 
 @web.middleware
 async def profile_middleware(request, handler):
-    global profiler 
+    global profiler
     if not profiler:
         profiler = cProfile.Profile()
     profiler.enable()
     response = await handler(request)
     profiler.disable()
     stats = pstats.Stats(profiler, stream=sys.stdout)
-    stats.sort_stats('cumulative')
-    stats.print_stats() 
+    stats.sort_stats("cumulative")
+    stats.print_stats()
     return response
 
+
 async def profiler_handler(request):
     output = io.StringIO()
     stats = pstats.Stats(profiler, stream=output)
@@ -27,17 +30,17 @@ async def profiler_handler(request):
     stats.print_stats()
     return web.Response(text=output.getvalue())
 
+
 class Profiler:
 
     def __init__(self):
-        global profiler 
+        global profiler
         if profiler is None:
             profiler = cProfile.Profile()
         self.profiler = profiler
 
     async def __aenter__(self):
-        self.profiler.enable()    
-    
+        self.profiler.enable()
+
     async def __aexit__(self, *args, **kwargs):
         self.profiler.disable()
-
diff --git a/src/snek/system/service.py b/src/snek/system/service.py
index d65f947..c6d2afc 100644
--- a/src/snek/system/service.py
+++ b/src/snek/system/service.py
@@ -58,7 +58,7 @@ class BaseService:
         raise Exception(f"Couldn't save model. Errors: f{errors}")
 
     async def find(self, **kwargs):
-        if not "_limit" in kwargs or int(kwargs.get("_limit")) > 30:
+        if "_limit" not in kwargs or int(kwargs.get("_limit")) > 30:
             kwargs["_limit"] = 60
         async for model in self.mapper.find(**kwargs):
             yield model
diff --git a/src/snek/system/template.py b/src/snek/system/template.py
index 0e71b80..cff807b 100644
--- a/src/snek/system/template.py
+++ b/src/snek/system/template.py
@@ -1,15 +1,21 @@
+import re
 from types import SimpleNamespace
-from bs4 import BeautifulSoup
-import re 
-import emoji
 
+import emoji
+from bs4 import BeautifulSoup
 from jinja2 import TemplateSyntaxError, nodes
 from jinja2.ext import Extension
 from jinja2.nodes import Const
 
-emoji.EMOJI_DATA['<img src="/emoji/snek1.gif" />'] = {"en": ":snek1:","status":2,"E":0.6, "alias":[":snek1:"]} 
+emoji.EMOJI_DATA['<img src="/emoji/snek1.gif" />'] = {
+    "en": ":snek1:",
+    "status": 2,
+    "E": 0.6,
+    "alias": [":snek1:"],
+}
 
-emoji.EMOJI_DATA["""⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
+emoji.EMOJI_DATA[
+    """⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣀⣠⣤⡴⠶⢶⣞⣛⣛⡳⣳⠶⣶⡶⢶⢶⣦⣤⣄⣀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⢀⣠⣤⠶⠚⣫⣴⣬⠐⣶⣿⣿⣏⣽⣿⣿⣇⢿⣯⣿⣿⣻⣿⣿⣾⣮⣹⣿⢶⣄⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣀⣴⢾⣻⣽⣾⡇⢡⣿⣿⣇⡟⣿⣿⣿⣼⣿⣿⣿⣿⢸⣿⣟⣿⣷⢻⣿⣿⣿⣷⡽⣧⣹⡻⣦⡀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
@@ -64,62 +70,91 @@ emoji.EMOJI_DATA["""⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣰⣟⣽⣿⣯⣿⣣⣿⣿⣿⣿⣿⡄⢿⣿⣿⣿⣿⣿⣿⡿⠟⣡⣾⣿⣿⣿⣿⣿⣿⡏⣰⣿⣿⡿⢹⡇⣾⠀⣿⣿⣾⣿⡇⠀⠈⢷⢰⣿⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣷⣦⣦⣀⡀⠈⠛⠻⢿⣎⢿⣿⣿⣿⣿⣿⣿⣷⣄⠀⣿⡇⠘⣧⠀⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⣴⢟⣾⣿⣻⡿⣵⣿⣿⣿⣿⣟⣾⣯⠌⠛⠛⠛⠛⠉⠁⢠⣾⣿⣿⣿⣿⣿⣿⡿⠏⣰⣿⣿⡿⠁⢸⡇⢿⠀⣿⣿⣿⣿⡇⠀⠠⠈⠂⢃⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣾⣿⣻⡿⣿⣿⣿⣿⣿⣿⣿⡇⡄⠾⣲⣾⣿⣌⢿⣿⣿⣿⣿⣿⣿⣿⣧⡙⠇⠀⢻⡄⠀⠀⠀⠀⠀⠀⠀
 ⠀⠀⠀⠀⠀⠀⠀⠀⠀⠀⠛⠚⠛⠛⠛⠚⠛⠛⠛⠛⠛⠚⠛⠛⠓⠚⠒⠛⠒⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠚⠛⠛⠛⠛⠓⠛⠛⠛⠓⠛⠛⠛⠛⠓⠚⠛⠛⠓⠚⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠛⠚⠛⠛⠛⠛⠛⠛⠓⠛⠚⠛⠛⠛⠛⠓⠛⠛⠛⠛⠛⠛⠛⠛⠛⠒⠚⠚⠁⠀⠀⠀⠀⠀⠀⠀
-"""] = {"en": ":a1:","status":2,"E":0.6, "alias":[":a1:"]}
+"""
+] = {"en": ":a1:", "status": 2, "E": 0.6, "alias": [":a1:"]}
+
 
 def set_link_target_blank(text):
-    soup = BeautifulSoup(text, 'html.parser')
+    soup = BeautifulSoup(text, "html.parser")
 
-    for element in soup.find_all("a"):  
-        element.attrs['target'] = '_blank'
-        element.attrs['rel'] = 'noopener noreferrer'
-        element.attrs['referrerpolicy'] = 'no-referrer'
-        element.attrs['href'] = element.attrs['href'].strip(".").strip(",")
+    for element in soup.find_all("a"):
+        element.attrs["target"] = "_blank"
+        element.attrs["rel"] = "noopener noreferrer"
+        element.attrs["referrerpolicy"] = "no-referrer"
+        element.attrs["href"] = element.attrs["href"].strip(".").strip(",")
 
     return str(soup)
 
+
 def embed_youtube(text):
-    soup = BeautifulSoup(text, 'html.parser') 
-    for element in soup.find_all("a"):  
-        if element.attrs['href'].startswith("https://www.you") and "?v=" in element.attrs["href"]:
+    soup = BeautifulSoup(text, "html.parser")
+    for element in soup.find_all("a"):
+        if (
+            element.attrs["href"].startswith("https://www.you")
+            and "?v=" in element.attrs["href"]
+        ):
             video_name = element.attrs["href"].split("?v=")[1].split("&")[0]
             embed_template = f'<iframe width="560" height="315" src="https://www.youtube.com/embed/{video_name}" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>'
-            element.replace_with(BeautifulSoup(embed_template, 'html.parser'))
+            element.replace_with(BeautifulSoup(embed_template, "html.parser"))
     return str(soup)
 
+
 def embed_image(text):
-    soup = BeautifulSoup(text, 'html.parser') 
-    for element in soup.find_all("a"):  
-        for extension in [".png", ".jpg", ".jpeg", ".gif", ".webp", ".svg", ".bmp", ".tiff", ".ico", ".heif"]:
-            if extension in element.attrs['href'].lower():
+    soup = BeautifulSoup(text, "html.parser")
+    for element in soup.find_all("a"):
+        for extension in [
+            ".png",
+            ".jpg",
+            ".jpeg",
+            ".gif",
+            ".webp",
+            ".svg",
+            ".bmp",
+            ".tiff",
+            ".ico",
+            ".heif",
+        ]:
+            if extension in element.attrs["href"].lower():
                 embed_template = f'<img src="{element.attrs["href"]}" title="{element.attrs["href"]}" alt="{element.attrs["href"]}" />'
-                element.replace_with(BeautifulSoup(embed_template, 'html.parser'))
+                element.replace_with(BeautifulSoup(embed_template, "html.parser"))
     return str(soup)
 
+
 def embed_media(text):
-    soup = BeautifulSoup(text, 'html.parser') 
-    for element in soup.find_all("a"):  
-        for extension in [".mp4", ".mp3", ".wav", ".ogg", ".webm", ".flac", ".aac",".mpg",".avi",".wmv"]:
-            if extension in element.attrs['href'].lower():
+    soup = BeautifulSoup(text, "html.parser")
+    for element in soup.find_all("a"):
+        for extension in [
+            ".mp4",
+            ".mp3",
+            ".wav",
+            ".ogg",
+            ".webm",
+            ".flac",
+            ".aac",
+            ".mpg",
+            ".avi",
+            ".wmv",
+        ]:
+            if extension in element.attrs["href"].lower():
                 embed_template = f'<video controls> <source src="{element.attrs["href"]}">Your browser does not support the video tag.</video>'
-                element.replace_with(BeautifulSoup(embed_template, 'html.parser'))
+                element.replace_with(BeautifulSoup(embed_template, "html.parser"))
     return str(soup)
 
 
-
 def linkify_https(text):
-    if not "https://" in text:
-        return text 
+    if "https://" not in text:
+        return text
     url_pattern = r'(?<!["\'])\bhttps://[^\s<>()]+(?<!\.)'
 
-    soup = BeautifulSoup(text, 'html.parser')
+    soup = BeautifulSoup(text, "html.parser")
 
-    for element in soup.find_all(text=True):  
+    for element in soup.find_all(text=True):
         parent = element.parent
-        if parent.name in ['a', 'script', 'style']:  
+        if parent.name in ["a", "script", "style"]:
             continue
-        
+
         new_text = re.sub(url_pattern, r'<a href="\g<0>">\g<0></a>', element)
-        element.replace_with(BeautifulSoup(new_text, 'html.parser'))
+        element.replace_with(BeautifulSoup(new_text, "html.parser"))
 
     return set_link_target_blank(str(soup))
 
@@ -140,8 +175,7 @@ class EmojiExtension(Extension):
         ).set_lineno(line_number)
 
     def _to_html(self, md_file, caller):
-        return emoji.emojize(caller(),language='alias')
-
+        return emoji.emojize(caller(), language="alias")
 
 
 class LinkifyExtension(Extension):
@@ -170,6 +204,7 @@ class LinkifyExtension(Extension):
         result = embed_youtube(result)
         return result
 
+
 class PythonExtension(Extension):
     tags = {"py3"}
 
@@ -186,26 +221,26 @@ class PythonExtension(Extension):
         ).set_lineno(line_number)
 
     def _to_html(self, md_file, caller):
-        
+
         def fn(source):
-            import subprocess 
-            import subprocess 
-            import pathlib 
-            from pathlib import Path 
-            import os 
-            import sys 
-            import requests
+            import subprocess
+
             def system(command):
                 if isinstance(command):
                     command = command.split(" ")
-                from io import StringIO 
+                from io import StringIO
+
                 stdout = StringIO()
-                subprocess.run(command,stderr=stdout,stdout=stdout,text=True)
+                subprocess.run(command, stderr=stdout, stdout=stdout, text=True)
                 return stdout.getvalue()
+
             to_write = []
+
             def render(text):
-                global to_write 
+                global to_write
                 to_write.append(text)
+
             exec(source)
             return "".join(to_write)
+
         return str(fn(caller()))
diff --git a/src/snek/system/terminal.py b/src/snek/system/terminal.py
index 80dda17..4d3781e 100644
--- a/src/snek/system/terminal.py
+++ b/src/snek/system/terminal.py
@@ -1,30 +1,27 @@
 import asyncio
-import aiohttp
-import aiohttp.web
 import os
 import pty
-import shlex
 import subprocess
-import pathlib
 
 commands = {
-    'alpine': 'docker run -it alpine /bin/sh',
-    'r': 'docker run -v /usr/local/bin:/usr/local/bin -it ubuntu:latest run.sh',
+    "alpine": "docker run -it alpine /bin/sh",
+    "r": "docker run -v /usr/local/bin:/usr/local/bin -it ubuntu:latest run.sh",
 }
 
+
 class TerminalSession:
-    def __init__(self,command):
+    def __init__(self, command):
         self.master, self.slave = pty.openpty()
-        self.sockets =[]
-        self.history = b''
-        self.history_size = 1024*20
+        self.sockets = []
+        self.history = b""
+        self.history_size = 1024 * 20
         self.process = subprocess.Popen(
             command.split(" "),
             stdin=self.slave,
             stdout=self.slave,
             stderr=self.slave,
             bufsize=0,
-            universal_newlines=True
+            universal_newlines=True,
         )
 
     async def add_websocket(self, ws):
@@ -35,11 +32,11 @@ class TerminalSession:
         if len(self.sockets) > 1 and self.history:
             start = 0
             try:
-                start = self.history.index(b'\n')
+                start = self.history.index(b"\n")
             except ValueError:
-                pass 
+                pass
             await ws.send_bytes(self.history[start:])
-            return 
+            return
         loop = asyncio.get_event_loop()
         while True:
             try:
@@ -48,9 +45,10 @@ class TerminalSession:
                     break
                 self.history += data
                 if len(self.history) > self.history_size:
-                    self.history = self.history[:0-self.history_size]
+                    self.history = self.history[: 0 - self.history_size]
                 try:
-                    for ws in self.sockets: await ws.send_bytes(data)  # Send raw bytes for ANSI support
+                    for ws in self.sockets:
+                        await ws.send_bytes(data)  # Send raw bytes for ANSI support
                 except:
                     self.sockets.remove(ws)
             except Exception:
diff --git a/src/snek/system/view.py b/src/snek/system/view.py
index 2765642..4a6e7a1 100644
--- a/src/snek/system/view.py
+++ b/src/snek/system/view.py
@@ -12,9 +12,9 @@ class BaseView(web.View):
             return web.HTTPFound("/")
         return await super()._iter()
 
-    @property 
+    @property
     def base_url(self):
-        return str(self.request.url.with_path('').with_query(''))
+        return str(self.request.url.with_path("").with_query(""))
 
     @property
     def app(self):
diff --git a/src/snek/view/about.py b/src/snek/view/about.py
index b03f922..aba57ae 100644
--- a/src/snek/view/about.py
+++ b/src/snek/view/about.py
@@ -26,12 +26,14 @@
 
 from snek.system.view import BaseView
 
+
 class AboutHTMLView(BaseView):
-   
+
     async def get(self):
         return await self.render_template("about.html")
 
+
 class AboutMDView(BaseView):
 
     async def get(self):
-        return await self.render_template("about.md")
\ No newline at end of file
+        return await self.render_template("about.md")
diff --git a/src/snek/view/avatar.py b/src/snek/view/avatar.py
index cbd973c..a85b876 100644
--- a/src/snek/view/avatar.py
+++ b/src/snek/view/avatar.py
@@ -23,11 +23,14 @@
 # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 # SOFTWARE.
-from multiavatar import multiavatar
 import uuid
+
 from aiohttp import web
+from multiavatar import multiavatar
+
 from snek.system.view import BaseView
 
+
 class AvatarView(BaseView):
     login_required = False
 
@@ -36,6 +39,6 @@ class AvatarView(BaseView):
         if uid == "unique":
             uid = str(uuid.uuid4())
         avatar = multiavatar.multiavatar(uid, True, None)
-        response = web.Response(text=avatar, content_type='image/svg+xml')
-        response.headers['Cache-Control'] = f'public, max-age={1337*42}'
+        response = web.Response(text=avatar, content_type="image/svg+xml")
+        response.headers["Cache-Control"] = f"public, max-age={1337*42}"
         return response
diff --git a/src/snek/view/docs.py b/src/snek/view/docs.py
index 592d1a2..bb63413 100644
--- a/src/snek/view/docs.py
+++ b/src/snek/view/docs.py
@@ -1,35 +1,37 @@
-# Written by retoor@molodetz.nl  
-  
-# This code defines two classes, DocsHTMLView and DocsMDView, which are intended to asynchronously render HTML and Markdown templates respectively. Both classes inherit from the BaseView class.  
-  
-# Dependencies: BaseView is imported from the "snek.system.view" package.  
-  
-# MIT License  
-# Permission is hereby granted, free of charge, to any person obtaining a copy  
-# of this software and associated documentation files (the "Software"), to deal  
-# in the Software without restriction, including without limitation the rights  
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell  
-# copies of the Software, and to permit persons to whom the Software is  
-# furnished to do so, subject to the following conditions:  
-# The above copyright notice and this permission notice shall be included in all  
-# copies or substantial portions of the Software.  
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR  
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,  
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE  
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER  
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,  
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE  
-# SOFTWARE.  
-  
-  
+# Written by retoor@molodetz.nl
+
+# This code defines two classes, DocsHTMLView and DocsMDView, which are intended to asynchronously render HTML and Markdown templates respectively. Both classes inherit from the BaseView class.
+
+# Dependencies: BaseView is imported from the "snek.system.view" package.
+
+# MIT License
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+
 from snek.system.view import BaseView
 
+
 class DocsHTMLView(BaseView):
 
     async def get(self):
         return await self.render_template("docs.html")
 
+
 class DocsMDView(BaseView):
 
     async def get(self):
-        return await self.render_template("docs.md")
\ No newline at end of file
+        return await self.render_template("docs.md")
diff --git a/src/snek/view/drive.py b/src/snek/view/drive.py
index 1026cf7..853cdb2 100644
--- a/src/snek/view/drive.py
+++ b/src/snek/view/drive.py
@@ -1,6 +1,8 @@
-from snek.system.view import BaseView
 from aiohttp import web
 
+from snek.system.view import BaseView
+
+
 class DriveView(BaseView):
 
     login_required = True
@@ -14,21 +16,22 @@ class DriveView(BaseView):
             drive_items = []
             async for item in drive.items:
                 record = item.record
-                record['url'] = '/drive.bin/' + record['uid'] + '.' + item.extension
+                record["url"] = "/drive.bin/" + record["uid"] + "." + item.extension
                 drive_items.append(record)
             return web.json_response(drive_items)
 
         user = await self.services.user.get(uid=self.session.get("uid"))
 
-        
         drives = []
-        async for drive in self.services.drive.get_by_user(user['uid']):
+        async for drive in self.services.drive.get_by_user(user["uid"]):
             record = drive.record
-            record['items'] = []
+            record["items"] = []
             async for item in drive.items:
                 drive_item_record = item.record
-                drive_item_record['url'] = '/drive.bin/' + drive_item_record['uid'] + '.' + item.extension
-                record['items'].append(item.record)
+                drive_item_record["url"] = (
+                    "/drive.bin/" + drive_item_record["uid"] + "." + item.extension
+                )
+                record["items"].append(item.record)
             drives.append(record)
-        
+
         return web.json_response(drives)
diff --git a/src/snek/view/index.py b/src/snek/view/index.py
index 3e62518..6ad6e70 100644
--- a/src/snek/view/index.py
+++ b/src/snek/view/index.py
@@ -12,6 +12,7 @@
 
 from snek.system.view import BaseView
 
+
 class IndexView(BaseView):
     async def get(self):
-        return await self.render_template("index.html")
\ No newline at end of file
+        return await self.render_template("index.html")
diff --git a/src/snek/view/login.py b/src/snek/view/login.py
index 5028a7a..be79328 100644
--- a/src/snek/view/login.py
+++ b/src/snek/view/login.py
@@ -7,9 +7,11 @@
 # MIT License
 
 from aiohttp import web
+
 from snek.form.login import LoginForm
 from snek.system.view import BaseFormView
 
+
 class LoginView(BaseFormView):
     form = LoginForm
 
@@ -18,17 +20,23 @@ class LoginView(BaseFormView):
             return web.HTTPFound("/web.html")
         if self.request.path.endswith(".json"):
             return await super().get()
-        return await self.render_template("login.html", {"form": await self.form(app=self.app).to_json()})
+        return await self.render_template(
+            "login.html", {"form": await self.form(app=self.app).to_json()}
+        )
 
     async def submit(self, form):
         if await form.is_valid:
-            user = await self.services.user.get(username=form['username'], deleted_at=None)
+            user = await self.services.user.get(
+                username=form["username"], deleted_at=None
+            )
             await self.services.user.save(user)
-            self.session.update({
-                "logged_in": True,
-                "username": user['username'],
-                "uid": user["uid"],
-                "color": user["color"]
-            })
+            self.session.update(
+                {
+                    "logged_in": True,
+                    "username": user["username"],
+                    "uid": user["uid"],
+                    "color": user["color"],
+                }
+            )
             return {"redirect_url": "/web.html"}
-        return {"is_valid": False}
\ No newline at end of file
+        return {"is_valid": False}
diff --git a/src/snek/view/login_form.py b/src/snek/view/login_form.py
index 230d334..acf7c75 100644
--- a/src/snek/view/login_form.py
+++ b/src/snek/view/login_form.py
@@ -20,4 +20,4 @@ class LoginFormView(BaseFormView):
             self.session["username"] = form.username.value
             self.session["uid"] = form.uid.value
             return {"redirect_url": "/web.html"}
-        return {"is_valid": False}
\ No newline at end of file
+        return {"is_valid": False}
diff --git a/src/snek/view/logout.py b/src/snek/view/logout.py
index 57b92a3..42016d8 100644
--- a/src/snek/view/logout.py
+++ b/src/snek/view/logout.py
@@ -15,10 +15,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -29,6 +29,7 @@
 
 
 from aiohttp import web
+
 from snek.system.view import BaseView
 
 
@@ -52,4 +53,4 @@ class LogoutView(BaseView):
             del self.session["username"]
         except KeyError:
             pass
-        return await self.json_response({"redirect_url": self.redirect_url})
\ No newline at end of file
+        return await self.json_response({"redirect_url": self.redirect_url})
diff --git a/src/snek/view/register.py b/src/snek/view/register.py
index 6e49506..7fbce9d 100644
--- a/src/snek/view/register.py
+++ b/src/snek/view/register.py
@@ -2,14 +2,16 @@
 
 # This module defines a web view for user registration. It handles GET requests and form submissions for the registration process.
 
-# The code makes use of 'RegisterForm' from 'snek.form.register' for handling registration forms and 'BaseFormView' from 'snek.system.view' for basic view functionalities. 
+# The code makes use of 'RegisterForm' from 'snek.form.register' for handling registration forms and 'BaseFormView' from 'snek.system.view' for basic view functionalities.
 
 # MIT License
 
 from aiohttp import web
+
 from snek.form.register import RegisterForm
 from snek.system.view import BaseFormView
 
+
 class RegisterView(BaseFormView):
     form = RegisterForm
 
@@ -18,16 +20,20 @@ class RegisterView(BaseFormView):
             return web.HTTPFound("/web.html")
         if self.request.path.endswith(".json"):
             return await super().get()
-        return await self.render_template("register.html", {"form": await self.form(app=self.app).to_json()})
+        return await self.render_template(
+            "register.html", {"form": await self.form(app=self.app).to_json()}
+        )
 
     async def submit(self, form):
         result = await self.app.services.user.register(
             form.email.value, form.username.value, form.password.value
         )
-        self.request.session.update({
-            "uid": result["uid"],
-            "username": result["username"],
-            "logged_in": True,
-            "color": result["color"]
-        })
-        return {"redirect_url": "/web.html"}
\ No newline at end of file
+        self.request.session.update(
+            {
+                "uid": result["uid"],
+                "username": result["username"],
+                "logged_in": True,
+                "color": result["color"],
+            }
+        )
+        return {"redirect_url": "/web.html"}
diff --git a/src/snek/view/register_form.py b/src/snek/view/register_form.py
index 5ce42a7..7b98647 100644
--- a/src/snek/view/register_form.py
+++ b/src/snek/view/register_form.py
@@ -2,7 +2,7 @@
 
 # This code defines a `RegisterFormView` class that handles the user registration process by using a form object, a view parent class, and asynchronously submitting the form data to register a user. It then stores the user's session details and provides a redirect URL to a specific page.
 
-# Imports used but not part of the language: 
+# Imports used but not part of the language:
 # snek.form.register.RegisterForm, snek.system.view.BaseFormView
 
 # MIT License
@@ -13,10 +13,10 @@
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,6 +28,7 @@
 from snek.form.register import RegisterForm
 from snek.system.view import BaseFormView
 
+
 class RegisterFormView(BaseFormView):
     form = RegisterForm
 
@@ -35,10 +36,12 @@ class RegisterFormView(BaseFormView):
         result = await self.app.services.user.register(
             form.email.value, form.username.value, form.password.value
         )
-        self.request.session.update({
-            "uid": result["uid"],
-            "username": result["username"],
-            "logged_in": True,
-            "color": result["color"]
-        })
-        return {"redirect_url": "/web.html"}
\ No newline at end of file
+        self.request.session.update(
+            {
+                "uid": result["uid"],
+                "username": result["username"],
+                "logged_in": True,
+                "color": result["color"],
+            }
+        )
+        return {"redirect_url": "/web.html"}
diff --git a/src/snek/view/rpc.py b/src/snek/view/rpc.py
index 27a8dcf..19c98d4 100644
--- a/src/snek/view/rpc.py
+++ b/src/snek/view/rpc.py
@@ -7,41 +7,44 @@
 # MIT License: Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions.
 
 
-from aiohttp import web  
-from snek.system.view import BaseView
-import traceback
 import json
-from snek.system.model import now 
+import traceback
+
+from aiohttp import web
+
+from snek.system.model import now
 from snek.system.profiler import Profiler
+from snek.system.view import BaseView
+
 
 class RPCView(BaseView):
 
     class RPCApi:
         def __init__(self, view, ws):
-            self.view = view 
+            self.view = view
             self.app = self.view.app
             self.services = self.app.services
-            self.ws = ws 
+            self.ws = ws
 
         @property
         def user_uid(self):
             return self.view.session.get("uid")
 
-        @property 
+        @property
         def request(self):
-            return self.view.request 
-        
+            return self.view.request
+
         def _require_login(self):
             if not self.is_logged_in:
                 raise Exception("Not logged in")
 
-        @property 
+        @property
         def is_logged_in(self):
             return self.view.session.get("logged_in", False)
 
         async def mark_as_read(self, channel_uid):
             self._require_login()
-            await self.services.channel_member.mark_as_read(channel_uid, self.user_uid) 
+            await self.services.channel_member.mark_as_read(channel_uid, self.user_uid)
             return True
 
         async def login(self, username, password):
@@ -54,16 +57,26 @@ class RPCView(BaseView):
             self.view.session["username"] = user["username"]
             self.view.session["user_nick"] = user["nick"]
             record = user.record
-            del record['password']
-            del record['deleted_at']
-            await self.services.socket.add(self.ws,self.view.request.session.get('uid'))
-            async for subscription in self.services.channel_member.find(user_uid=self.view.request.session.get("uid"), deleted_at=None, is_banned=False):
-                await self.services.socket.subscribe(self.ws, subscription["channel_uid"], self.view.request.session.get("uid"))
-            return record 
+            del record["password"]
+            del record["deleted_at"]
+            await self.services.socket.add(
+                self.ws, self.view.request.session.get("uid")
+            )
+            async for subscription in self.services.channel_member.find(
+                user_uid=self.view.request.session.get("uid"),
+                deleted_at=None,
+                is_banned=False,
+            ):
+                await self.services.socket.subscribe(
+                    self.ws,
+                    subscription["channel_uid"],
+                    self.view.request.session.get("uid"),
+                )
+            return record
 
-        async def search_user(self, query): 
+        async def search_user(self, query):
             self._require_login()
-            return [user['username'] for user in await self.services.user.search(query)]
+            return [user["username"] for user in await self.services.user.search(query)]
 
         async def get_user(self, user_uid):
             self._require_login()
@@ -71,46 +84,56 @@ class RPCView(BaseView):
                 user_uid = self.user_uid
             user = await self.services.user.get(uid=user_uid)
             record = user.record
-            del record['password']
-            del record['deleted_at']
+            del record["password"]
+            del record["deleted_at"]
             if user_uid != user["uid"]:
-                del record['email']
-            return record 
+                del record["email"]
+            return record
 
-        async def get_messages(self, channel_uid, offset=0,timestamp = None):
+        async def get_messages(self, channel_uid, offset=0, timestamp=None):
             self._require_login()
             messages = []
-            for message in await self.services.channel_message.offset(channel_uid, offset or 0,timestamp or None):
-                extended_dict = await self.services.channel_message.to_extended_dict(message)
+            for message in await self.services.channel_message.offset(
+                channel_uid, offset or 0, timestamp or None
+            ):
+                extended_dict = await self.services.channel_message.to_extended_dict(
+                    message
+                )
                 messages.append(extended_dict)
             return messages
 
         async def get_channels(self):
             self._require_login()
             channels = []
-            async for subscription in self.services.channel_member.find(user_uid=self.user_uid, is_banned=False):
-                channel = await self.services.channel.get(uid=subscription['channel_uid'])
+            async for subscription in self.services.channel_member.find(
+                user_uid=self.user_uid, is_banned=False
+            ):
+                channel = await self.services.channel.get(
+                    uid=subscription["channel_uid"]
+                )
                 last_message = await channel.get_last_message()
-                color = None 
+                color = None
                 if last_message:
                     last_message_user = await last_message.get_user()
-                    color = last_message_user['color']
-                channels.append({
-                    "name": subscription["label"],
-                    "uid": subscription["channel_uid"],
-                    "tag": channel["tag"],
-                    "new_count": subscription["new_count"],
-                    "is_moderator": subscription["is_moderator"],
-                    "is_read_only": subscription["is_read_only"],
-                    'new_count': subscription['new_count'],
-                    'color': color 
-                })
+                    color = last_message_user["color"]
+                channels.append(
+                    {
+                        "name": subscription["label"],
+                        "uid": subscription["channel_uid"],
+                        "tag": channel["tag"],
+                        "new_count": subscription["new_count"],
+                        "is_moderator": subscription["is_moderator"],
+                        "is_read_only": subscription["is_read_only"],
+                        "new_count": subscription["new_count"],
+                        "color": color,
+                    }
+                )
             return channels
 
         async def send_message(self, channel_uid, message):
             self._require_login()
             await self.services.chat.send(self.user_uid, channel_uid, message)
-            return True 
+            return True
 
         async def echo(self, *args):
             self._require_login()
@@ -118,29 +141,47 @@ class RPCView(BaseView):
 
         async def query(self, *args):
             self._require_login()
-            query = args[0] 
+            query = args[0]
             lowercase = query.lower()
-            if any(keyword in lowercase for keyword in ["drop", "alter", "update", "delete", "replace", "insert", "truncate"]) and 'select' not in lowercase:
+            if (
+                any(
+                    keyword in lowercase
+                    for keyword in [
+                        "drop",
+                        "alter",
+                        "update",
+                        "delete",
+                        "replace",
+                        "insert",
+                        "truncate",
+                    ]
+                )
+                and "select" not in lowercase
+            ):
                 raise Exception("Not allowed")
-            records = [dict(record) async for record in self.services.channel.query(args[0])]
+            records = [
+                dict(record) async for record in self.services.channel.query(args[0])
+            ]
             for record in records:
                 try:
-                    del record['email']
+                    del record["email"]
                 except KeyError:
-                    pass 
+                    pass
                 try:
                     del record["password"]
                 except KeyError:
-                    pass 
+                    pass
                 try:
-                    del record['message']
+                    del record["message"]
                 except:
                     pass
                 try:
-                    del record['html']
-                except: 
+                    del record["html"]
+                except:
                     pass
-            return [dict(record) async for record in self.services.channel.query(args[0])]
+            return [
+                dict(record) async for record in self.services.channel.query(args[0])
+            ]
 
         async def __call__(self, data):
             try:
@@ -150,30 +191,43 @@ class RPCView(BaseView):
                     raise Exception("Not allowed")
                 args = data.get("args") or []
                 if hasattr(super(), method_name) or not hasattr(self, method_name):
-                    return await self._send_json({"callId": call_id, "data": "Not allowed"})
+                    return await self._send_json(
+                        {"callId": call_id, "data": "Not allowed"}
+                    )
                 method = getattr(self, method_name.replace(".", "_"), None)
                 if not method:
                     raise Exception("Method not found")
-                success = True 
+                success = True
                 try:
                     result = await method(*args)
                 except Exception as ex:
                     result = {"exception": str(ex), "traceback": traceback.format_exc()}
                     success = False
                 if result != "noresponse":
-                    await self._send_json({"callId": call_id, "success": success, "data": result})
+                    await self._send_json(
+                        {"callId": call_id, "success": success, "data": result}
+                    )
             except Exception as ex:
                 print(str(ex), flush=True)
-                await self._send_json({"callId": call_id, "success": False, "data": str(ex)})
+                await self._send_json(
+                    {"callId": call_id, "success": False, "data": str(ex)}
+                )
 
         async def _send_json(self, obj):
             await self.ws.send_str(json.dumps(obj, default=str))
-    
 
         async def get_online_users(self, channel_uid):
             self._require_login()
-            
-            return [dict(uid=record['uid'],username=record['username'], nick=record['nick'],last_ping=record['last_ping']) async for record in self.services.channel.get_online_users(channel_uid)]
+
+            return [
+                {
+                    "uid": record["uid"],
+                    "username": record["username"],
+                    "nick": record["nick"],
+                    "last_ping": record["last_ping"],
+                }
+                async for record in self.services.channel.get_online_users(channel_uid)
+            ]
 
         async def echo(self, obj):
             await self.ws.send_json(obj)
@@ -182,12 +236,20 @@ class RPCView(BaseView):
         async def get_users(self, channel_uid):
             self._require_login()
 
-            return [dict(uid=record['uid'],username=record['username'], nick=record['nick'],last_ping=record['last_ping']) async for record in self.services.channel.get_users(channel_uid)]
+            return [
+                {
+                    "uid": record["uid"],
+                    "username": record["username"],
+                    "nick": record["nick"],
+                    "last_ping": record["last_ping"],
+                }
+                async for record in self.services.channel.get_users(channel_uid)
+            ]
 
         async def ping(self, callId, *args):
             if self.user_uid:
                 user = await self.services.user.get(uid=self.user_uid)
-                user['last_ping'] = now()
+                user["last_ping"] = now()
                 await self.services.user.save(user)
             return {"pong": args}
 
@@ -196,8 +258,14 @@ class RPCView(BaseView):
         await ws.prepare(self.request)
         if self.request.session.get("logged_in"):
             await self.services.socket.add(ws, self.request.session.get("uid"))
-            async for subscription in self.services.channel_member.find(user_uid=self.request.session.get("uid"), deleted_at=None, is_banned=False):
-                await self.services.socket.subscribe(ws, subscription["channel_uid"], self.request.session.get("uid"))
+            async for subscription in self.services.channel_member.find(
+                user_uid=self.request.session.get("uid"),
+                deleted_at=None,
+                is_banned=False,
+            ):
+                await self.services.socket.subscribe(
+                    ws, subscription["channel_uid"], self.request.session.get("uid")
+                )
         rpc = RPCView.RPCApi(self, ws)
         async for msg in ws:
             if msg.type == web.WSMsgType.TEXT:
@@ -209,7 +277,7 @@ class RPCView(BaseView):
                     await self.services.socket.delete(ws)
                     break
             elif msg.type == web.WSMsgType.ERROR:
-                pass 
+                pass
             elif msg.type == web.WSMsgType.CLOSE:
-                pass 
+                pass
         return ws
diff --git a/src/snek/view/search_user.py b/src/snek/view/search_user.py
index 347d3b2..d97a4b6 100644
--- a/src/snek/view/search_user.py
+++ b/src/snek/view/search_user.py
@@ -8,17 +8,17 @@
 # - snek.system.view: Provides the BaseFormView class to facilitate form-related operations in a web context.
 
 # MIT License
-# 
+#
 # Permission is hereby granted, free of charge, to any person obtaining a copy
 # of this software and associated documentation files (the "Software"), to deal
 # in the Software without restriction, including without limitation the rights
 # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 # copies of the Software, and to permit persons to whom the Software is
 # furnished to do so, subject to the following conditions:
-# 
+#
 # The above copyright notice and this permission notice shall be included in all
 # copies or substantial portions of the Software.
-# 
+#
 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
@@ -28,7 +28,6 @@
 # SOFTWARE.
 
 
-from aiohttp import web
 from snek.form.search_user import SearchUserForm
 from snek.system.view import BaseFormView
 
@@ -40,14 +39,17 @@ class SearchUserView(BaseFormView):
         users = []
         query = self.request.query.get("query")
         if query:
-            users = [user.record for user in  await self.app.services.user.search(query)]
+            users = [user.record for user in await self.app.services.user.search(query)]
 
         if self.request.path.endswith(".json"):
             return await super().get()
         current_user = await self.app.services.user.get(uid=self.session.get("uid"))
-        return await self.render_template("search_user.html", {"users": users, "query": query or '','current_user': current_user})
+        return await self.render_template(
+            "search_user.html",
+            {"users": users, "query": query or "", "current_user": current_user},
+        )
 
     async def submit(self, form):
         if await form.is_valid:
-            return {"redirect_url": "/search-user.html?query=" + form['username']}
+            return {"redirect_url": "/search-user.html?query=" + form["username"]}
         return {"is_valid": False}
diff --git a/src/snek/view/status.py b/src/snek/view/status.py
index 117942a..4675572 100644
--- a/src/snek/view/status.py
+++ b/src/snek/view/status.py
@@ -25,17 +25,18 @@
 
 from snek.system.view import BaseView
 
+
 class StatusView(BaseView):
     async def get(self):
         memberships = []
         user = {}
-        
+
         user_id = self.session.get("uid")
         if user_id:
             user = await self.app.services.user.get(uid=user_id)
             if not user:
                 return await self.json_response({"error": "User not found"}, status=404)
-            
+
             async for model in self.app.services.channel_member.find(
                 user_uid=user_id, deleted_at=None, is_banned=False
             ):
@@ -69,4 +70,4 @@ class StatusView(BaseView):
                     self.app.cache.cache, None
                 ),
             }
-        )
\ No newline at end of file
+        )
diff --git a/src/snek/view/terminal.py b/src/snek/view/terminal.py
index 6596f2c..d3af9b0 100644
--- a/src/snek/view/terminal.py
+++ b/src/snek/view/terminal.py
@@ -1,15 +1,17 @@
-from snek.system.view import BaseView 
-import aiohttp 
-import asyncio
-from snek.system.terminal import TerminalSession
 import pathlib
 
+import aiohttp
+
+from snek.system.terminal import TerminalSession
+from snek.system.view import BaseView
+
+
 class TerminalSocketView(BaseView):
-    
+
     login_required = True
 
     user_sessions = {}
-    
+
     async def prepare_drive(self):
         user = await self.services.user.get(uid=self.session.get("uid"))
         root = pathlib.Path("drive").joinpath(user["uid"])
@@ -19,40 +21,34 @@ class TerminalSocketView(BaseView):
             destination_path = root.joinpath(path.name)
             if not path.is_dir():
                 destination_path.write_bytes(path.read_bytes())
-        return root 
-        
-    async def get(self):
-       
+        return root
 
+    async def get(self):
 
         ws = aiohttp.web.WebSocketResponse()
         await ws.prepare(self.request)
         user = await self.services.user.get(uid=self.session.get("uid"))
         root = await self.prepare_drive()
-        
-
-        
 
         command = f"docker run -v ./{root}/:/root -it --memory 512M --cpus=0.5 -w /root snek_ubuntu /bin/bash"
 
         session = self.user_sessions.get(user["uid"])
         if not session:
             self.user_sessions[user["uid"]] = TerminalSession(command=command)
-        session = self.user_sessions[user["uid"]]   
+        session = self.user_sessions[user["uid"]]
         await session.add_websocket(ws)
-        #asyncio.create_task(session.read_output(ws))  
+        # asyncio.create_task(session.read_output(ws))
 
         async for msg in ws:
             if msg.type == aiohttp.WSMsgType.BINARY:
                 await session.write_input(msg.data.decode())
 
-        
         return ws
 
+
 class TerminalView(BaseView):
 
     login_required = True
 
     async def get(self):
-        request = self.request
-        return await self.request.app.render_template('terminal.html',self.request)
+        return await self.request.app.render_template("terminal.html", self.request)
diff --git a/src/snek/view/threads.py b/src/snek/view/threads.py
index 4f3fe8c..bc923c6 100644
--- a/src/snek/view/threads.py
+++ b/src/snek/view/threads.py
@@ -1,5 +1,6 @@
 from snek.system.view import BaseView
 
+
 class ThreadsView(BaseView):
 
     async def get(self):
@@ -12,22 +13,25 @@ class ThreadsView(BaseView):
             if not last_message:
                 continue
 
-            thread["uid"] = channel['uid']
+            thread["uid"] = channel["uid"]
             thread["name"] = await channel_member.get_name()
             thread["new_count"] = channel_member["new_count"]
             thread["last_message_on"] = channel["last_message_on"]
-            thread['created_at'] = thread['last_message_on']
+            thread["created_at"] = thread["last_message_on"]
 
-            
-            thread['name_color'] = "#f05a28"
+            thread["name_color"] = "#f05a28"
             thread["last_message_text"] = last_message["message"]
-            thread['last_message_user_uid'] = last_message["user_uid"]
-            user_last_message = await self.app.services.user.get(uid=last_message["user_uid"])
-            if channel['tag'] == "dm":
-                thread['name_color'] = user_last_message['color']
-            thread['last_message_user_color'] = user_last_message['color']  
+            thread["last_message_user_uid"] = last_message["user_uid"]
+            user_last_message = await self.app.services.user.get(
+                uid=last_message["user_uid"]
+            )
+            if channel["tag"] == "dm":
+                thread["name_color"] = user_last_message["color"]
+            thread["last_message_user_color"] = user_last_message["color"]
             threads.append(thread)
-            
-        threads.sort(key=lambda x: x['last_message_on'] or '', reverse=True)
 
-        return await self.render_template("threads.html", dict(threads=threads,user=user))
+        threads.sort(key=lambda x: x["last_message_on"] or "", reverse=True)
+
+        return await self.render_template(
+            "threads.html", {"threads": threads, "user": user}
+        )
diff --git a/src/snek/view/upload.py b/src/snek/view/upload.py
index 8884d72..b32d94e 100644
--- a/src/snek/view/upload.py
+++ b/src/snek/view/upload.py
@@ -1,31 +1,36 @@
 # Written by retoor@molodetz.nl
 
-# This code defines a web application for uploading and retrieving files. 
-# It includes functionality to upload files through a POST request and retrieve them via a GET request. 
+# This code defines a web application for uploading and retrieving files.
+# It includes functionality to upload files through a POST request and retrieve them via a GET request.
 
-# The code uses the following non-standard imports: 
+# The code uses the following non-standard imports:
 # - snek.system.view.BaseView: For extending view functionalities.
 # - aiofiles: For asynchronous file operations.
 # - aiohttp: For managing web server requests and responses.
 
 # MIT License: This software is licensed under the MIT License, a permissive free software license.
 
-from snek.system.view import BaseView
-import aiofiles
 import pathlib
-from aiohttp import web
 import uuid
 
+import aiofiles
+from aiohttp import web
+
+from snek.system.view import BaseView
+
 UPLOAD_DIR = pathlib.Path("./drive")
 
+
 class UploadView(BaseView):
 
     async def get(self):
         uid = self.request.match_info.get("uid")
         drive_item = await self.services.drive_item.get(uid)
         response = web.FileResponse(drive_item["path"])
-        response.headers['Cache-Control'] = f'public, max-age={1337*420}'
-        response.headers['Content-Disposition'] = f'attachment; filename="{drive_item["name"]}"'
+        response.headers["Cache-Control"] = f"public, max-age={1337*420}"
+        response.headers["Content-Disposition"] = (
+            f'attachment; filename="{drive_item["name"]}"'
+        )
         return response
 
     async def post(self):
@@ -36,7 +41,9 @@ class UploadView(BaseView):
 
         channel_uid = None
 
-        drive = await self.services.drive.get_or_create(user_uid=self.request.session.get("uid"))
+        drive = await self.services.drive.get_or_create(
+            user_uid=self.request.session.get("uid")
+        )
 
         extension_types = {
             ".jpg": "image",
@@ -47,7 +54,7 @@ class UploadView(BaseView):
             ".mp3": "audio",
             ".pdf": "document",
             ".doc": "document",
-            ".docx": "document"
+            ".docx": "document",
         }
 
         while field := await reader.next():
@@ -58,32 +65,45 @@ class UploadView(BaseView):
             filename = field.filename
             if not filename:
                 continue
-            
+
             name = str(uuid.uuid4()) + pathlib.Path(filename).suffix
 
             file_path = pathlib.Path(UPLOAD_DIR).joinpath(name)
             files.append(file_path)
 
-            async with aiofiles.open(str(file_path.absolute()), 'wb') as f:
+            async with aiofiles.open(str(file_path.absolute()), "wb") as f:
                 while chunk := await field.read_chunk():
                     await f.write(chunk)
 
             drive_item = await self.services.drive_item.create(
-                drive["uid"], filename, str(file_path.absolute()), file_path.stat().st_size, file_path.suffix
+                drive["uid"],
+                filename,
+                str(file_path.absolute()),
+                file_path.stat().st_size,
+                file_path.suffix,
             )
-           
-            type_ = "unknown"
+
             extension = "." + filename.split(".")[-1]
             if extension in extension_types:
-                type_ = extension_types[extension] 
-            
+                extension_types[extension]
+
             await self.services.drive_item.save(drive_item)
-            response = "Uploaded [" + filename + "](/drive.bin/" + drive_item["uid"] + ")"
-            #response = "<iframe width=\"100%\" frameborder=\"0\" allowfullscreen title=\"Embedded\" src=\"" + self.base_url + "/drive.bin/" + drive_item["uid"] + "\"></iframe>\n"
-            response = "[" + filename + "](/drive.bin/" + drive_item["uid"] + extension + ")"
+            response = (
+                "Uploaded [" + filename + "](/drive.bin/" + drive_item["uid"] + ")"
+            )
+            # response = "<iframe width=\"100%\" frameborder=\"0\" allowfullscreen title=\"Embedded\" src=\"" + self.base_url + "/drive.bin/" + drive_item["uid"] + "\"></iframe>\n"
+            response = (
+                "[" + filename + "](/drive.bin/" + drive_item["uid"] + extension + ")"
+            )
 
             await self.services.chat.send(
                 self.request.session.get("uid"), channel_uid, response
             )
 
-        return web.json_response({"message": "Files uploaded successfully", "files": [str(file) for file in files], "channel_uid": channel_uid})
+        return web.json_response(
+            {
+                "message": "Files uploaded successfully",
+                "files": [str(file) for file in files],
+                "channel_uid": channel_uid,
+            }
+        )
diff --git a/src/snek/view/web.py b/src/snek/view/web.py
index b9271c3..111f76c 100644
--- a/src/snek/view/web.py
+++ b/src/snek/view/web.py
@@ -25,37 +25,55 @@
 # SOFTWARE.
 
 from aiohttp import web
+
 from snek.system.view import BaseView
 
+
 class WebView(BaseView):
     login_required = True
 
     async def get(self):
         if self.login_required and not self.session.get("logged_in"):
             return web.HTTPFound("/")
-        channel = await self.services.channel.get(uid=self.request.match_info.get("channel"))
+        channel = await self.services.channel.get(
+            uid=self.request.match_info.get("channel")
+        )
         if not channel:
-            user = await self.services.user.get(uid=self.request.match_info.get("channel"))
+            user = await self.services.user.get(
+                uid=self.request.match_info.get("channel")
+            )
             if user:
-                channel = await self.services.channel.get_dm(self.session.get("uid"), user["uid"])
+                channel = await self.services.channel.get_dm(
+                    self.session.get("uid"), user["uid"]
+                )
                 if channel:
                     return web.HTTPFound("/channel/{}.html".format(channel["uid"]))
         if not channel:
             return web.HTTPNotFound()
-        
-        channel_member = await self.app.services.channel_member.get(user_uid=self.session.get("uid"), channel_uid=channel["uid"])
+
+        channel_member = await self.app.services.channel_member.get(
+            user_uid=self.session.get("uid"), channel_uid=channel["uid"]
+        )
         if not channel_member:
             return web.HTTPNotFound()
-        
-        channel_member['new_count'] = 0
+
+        channel_member["new_count"] = 0
         await self.app.services.channel_member.save(channel_member)
 
         user = await self.services.user.get(uid=self.session.get("uid"))
-        messages = [await self.app.services.channel_message.to_extended_dict(message) for message in await self.app.services.channel_message.offset(
-            channel["uid"]
-        )]
+        messages = [
+            await self.app.services.channel_message.to_extended_dict(message)
+            for message in await self.app.services.channel_message.offset(
+                channel["uid"]
+            )
+        ]
         for message in messages:
-            await self.app.services.notification.mark_as_read(self.session.get("uid"),message["uid"])
+            await self.app.services.notification.mark_as_read(
+                self.session.get("uid"), message["uid"]
+            )
 
         name = await channel_member.get_name()
-        return await self.render_template("web.html", {"name": name, "channel": channel,"user": user,"messages": messages})
+        return await self.render_template(
+            "web.html",
+            {"name": name, "channel": channel, "user": user, "messages": messages},
+        )
diff --git a/src/snekssh/app.py b/src/snekssh/app.py
index 27e1b4b..aab17e4 100644
--- a/src/snekssh/app.py
+++ b/src/snekssh/app.py
@@ -1,7 +1,9 @@
 import asyncio
-import asyncssh
-import os
 import logging
+import os
+
+import asyncssh
+
 asyncssh.set_debug_level(2)
 logging.basicConfig(level=logging.DEBUG)
 # Configuration for SFTP server
@@ -11,6 +13,7 @@ PASSWORD = "woeii"
 HOST = "localhost"
 PORT = 2225
 
+
 class MySFTPServer(asyncssh.SFTPServer):
     def __init__(self, chan):
         super().__init__(chan)
@@ -31,8 +34,10 @@ class MySFTPServer(asyncssh.SFTPServer):
         full_path = os.path.join(self.root, path.lstrip("/"))
         return await super().listdir(full_path)
 
+
 class MySSHServer(asyncssh.SSHServer):
     """Custom SSH server to handle authentication"""
+
     def connection_made(self, conn):
         print(f"New connection from {conn.get_extra_info('peername')}")
 
@@ -46,11 +51,12 @@ class MySSHServer(asyncssh.SSHServer):
         return True  # Support password authentication
 
     def validate_password(self, username, password):
-        print(username,password)
-        
+        print(username, password)
+
         return True
         return username == USERNAME and password == PASSWORD
 
+
 async def start_sftp_server():
     os.makedirs(SFTP_ROOT, exist_ok=True)  # Ensure the root directory exists
 
@@ -59,11 +65,12 @@ async def start_sftp_server():
         host=HOST,
         port=PORT,
         server_host_keys=["ssh_host_key"],
-        process_factory=MySFTPServer
+        process_factory=MySFTPServer,
     )
     print(f"SFTP server running on {HOST}:{PORT}")
     await asyncio.Future()  # Keep running forever
 
+
 if __name__ == "__main__":
     try:
         asyncio.run(start_sftp_server())
diff --git a/src/snekssh/app2.py b/src/snekssh/app2.py
index 1bfec21..2fa26a7 100644
--- a/src/snekssh/app2.py
+++ b/src/snekssh/app2.py
@@ -1,7 +1,8 @@
 import asyncio
-import asyncssh
 import os
 
+import asyncssh
+
 # SSH Server Configuration
 HOST = "0.0.0.0"
 PORT = 2225
@@ -9,6 +10,7 @@ USERNAME = "user"
 PASSWORD = "password"
 SHELL = "/bin/sh"  # Change to another shell if needed
 
+
 class CustomSSHServer(asyncssh.SSHServer):
     def connection_made(self, conn):
         print(f"New connection from {conn.get_extra_info('peername')}")
@@ -22,6 +24,7 @@ class CustomSSHServer(asyncssh.SSHServer):
     def validate_password(self, username, password):
         return username == USERNAME and password == PASSWORD
 
+
 async def custom_bash_process(process):
     """Spawns a custom bash shell process"""
     env = os.environ.copy()
@@ -29,7 +32,12 @@ async def custom_bash_process(process):
 
     # Start the Bash shell
     bash_proc = await asyncio.create_subprocess_exec(
-        SHELL, "-i", stdin=asyncio.subprocess.PIPE, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, env=env
+        SHELL,
+        "-i",
+        stdin=asyncio.subprocess.PIPE,
+        stdout=asyncio.subprocess.PIPE,
+        stderr=asyncio.subprocess.PIPE,
+        env=env,
     )
 
     async def read_output():
@@ -48,6 +56,7 @@ async def custom_bash_process(process):
 
     await asyncio.gather(read_output(), read_input())
 
+
 async def start_ssh_server():
     """Starts the AsyncSSH server with Bash"""
     await asyncssh.create_server(
@@ -55,14 +64,14 @@ async def start_ssh_server():
         host=HOST,
         port=PORT,
         server_host_keys=["ssh_host_key"],
-        process_factory=custom_bash_process
+        process_factory=custom_bash_process,
     )
     print(f"SSH server running on {HOST}:{PORT}")
     await asyncio.Future()  # Keep running
 
+
 if __name__ == "__main__":
     try:
         asyncio.run(start_ssh_server())
     except (OSError, asyncssh.Error) as e:
         print(f"Error starting SSH server: {e}")
-
diff --git a/src/snekssh/app3.py b/src/snekssh/app3.py
index d50cc54..4a09452 100644
--- a/src/snekssh/app3.py
+++ b/src/snekssh/app3.py
@@ -27,45 +27,48 @@
 # The file ``ssh_user_ca`` must exist with a cert-authority entry of
 # the certificate authority which can sign valid client certificates.
 
-import asyncio, asyncssh, sys
+import asyncio
+import sys
+
+import asyncssh
+
 
 async def handle_client(process: asyncssh.SSHServerProcess) -> None:
 
-
-
-
-
     width, height, pixwidth, pixheight = process.term_size
 
-    process.stdout.write(f'Terminal type: {process.term_type}, '
-                         f'size: {width}x{height}')
+    process.stdout.write(
+        f"Terminal type: {process.term_type}, " f"size: {width}x{height}"
+    )
     if pixwidth and pixheight:
-        process.stdout.write(f' ({pixwidth}x{pixheight} pixels)')
-    process.stdout.write('\nTry resizing your window!\n')
+        process.stdout.write(f" ({pixwidth}x{pixheight} pixels)")
+    process.stdout.write("\nTry resizing your window!\n")
 
     while not process.stdin.at_eof():
         try:
             await process.stdin.read()
         except asyncssh.TerminalSizeChanged as exc:
-            process.stdout.write(f'New window size: {exc.width}x{exc.height}')
+            process.stdout.write(f"New window size: {exc.width}x{exc.height}")
             if exc.pixwidth and exc.pixheight:
-                process.stdout.write(f' ({exc.pixwidth}'
-                                     f'x{exc.pixheight} pixels)')
-            process.stdout.write('\n')
-
-
+                process.stdout.write(f" ({exc.pixwidth}" f"x{exc.pixheight} pixels)")
+            process.stdout.write("\n")
 
 
 async def start_server() -> None:
-    await asyncssh.listen('', 2230, server_host_keys=['ssh_host_key'],
-                          #authorized_client_keys='ssh_user_ca',
-                          process_factory=handle_client)
+    await asyncssh.listen(
+        "",
+        2230,
+        server_host_keys=["ssh_host_key"],
+        # authorized_client_keys='ssh_user_ca',
+        process_factory=handle_client,
+    )
+
 
 loop = asyncio.new_event_loop()
 
 try:
     loop.run_until_complete(start_server())
 except (OSError, asyncssh.Error) as exc:
-    sys.exit('Error starting server: ' + str(exc))
+    sys.exit("Error starting server: " + str(exc))
 
 loop.run_forever()
diff --git a/src/snekssh/app4.py b/src/snekssh/app4.py
index e54480f..187722c 100644
--- a/src/snekssh/app4.py
+++ b/src/snekssh/app4.py
@@ -24,32 +24,39 @@
 # private key in it to use as a server host key. An SSH host certificate
 # can optionally be provided in the file ``ssh_host_key-cert.pub``.
 
-import asyncio, asyncssh, bcrypt, sys
+import asyncio
+import sys
 from typing import Optional
 
-passwords = {'guest': b'',                # guest account with no password
-             'user': bcrypt.hashpw(b'user', bcrypt.gensalt()),
-            }
+import asyncssh
+import bcrypt
+
+passwords = {
+    "guest": b"",  # guest account with no password
+    "user": bcrypt.hashpw(b"user", bcrypt.gensalt()),
+}
+
 
 def handle_client(process: asyncssh.SSHServerProcess) -> None:
-    username = process.get_extra_info('username')
-    process.stdout.write(f'Welcome to my SSH server, {username}!\n')
-    #process.exit(0)
+    username = process.get_extra_info("username")
+    process.stdout.write(f"Welcome to my SSH server, {username}!\n")
+    # process.exit(0)
+
 
 class MySSHServer(asyncssh.SSHServer):
     def connection_made(self, conn: asyncssh.SSHServerConnection) -> None:
-        peername = conn.get_extra_info('peername')[0]
-        print(f'SSH connection received from {peername}.')
+        peername = conn.get_extra_info("peername")[0]
+        print(f"SSH connection received from {peername}.")
 
     def connection_lost(self, exc: Optional[Exception]) -> None:
         if exc:
-            print('SSH connection error: ' + str(exc), file=sys.stderr)
+            print("SSH connection error: " + str(exc), file=sys.stderr)
         else:
-            print('SSH connection closed.')
+            print("SSH connection closed.")
 
     def begin_auth(self, username: str) -> bool:
         # If the user's password is the empty string, no auth is required
-        return passwords.get(username) != b''
+        return passwords.get(username) != b""
 
     def password_auth_supported(self) -> bool:
         return True
@@ -60,18 +67,24 @@ class MySSHServer(asyncssh.SSHServer):
         pw = passwords[username]
         if not password and not pw:
             return True
-        return bcrypt.checkpw(password.encode('utf-8'), pw)
+        return bcrypt.checkpw(password.encode("utf-8"), pw)
+
 
 async def start_server() -> None:
-    await asyncssh.create_server(MySSHServer, '', 2231,
-                                 server_host_keys=['ssh_host_key'],
-                                 process_factory=handle_client)
+    await asyncssh.create_server(
+        MySSHServer,
+        "",
+        2231,
+        server_host_keys=["ssh_host_key"],
+        process_factory=handle_client,
+    )
+
 
 loop = asyncio.new_event_loop()
 
 try:
     loop.run_until_complete(start_server())
 except (OSError, asyncssh.Error) as exc:
-    sys.exit('Error starting server: ' + str(exc))
+    sys.exit("Error starting server: " + str(exc))
 
 loop.run_forever()
diff --git a/src/snekssh/app5.py b/src/snekssh/app5.py
index bbaf3d3..cfd5d21 100644
--- a/src/snekssh/app5.py
+++ b/src/snekssh/app5.py
@@ -27,11 +27,15 @@
 # The file ``ssh_user_ca`` must exist with a cert-authority entry of
 # the certificate authority which can sign valid client certificates.
 
-import asyncio, asyncssh, sys
+import asyncio
+import sys
 from typing import List, cast
 
+import asyncssh
+
+
 class ChatClient:
-    _clients: List['ChatClient'] = []
+    _clients: List["ChatClient"] = []
 
     def __init__(self, process: asyncssh.SSHServerProcess):
         self._process = process
@@ -40,8 +44,6 @@ class ChatClient:
     async def handle_client(cls, process: asyncssh.SSHServerProcess):
         await cls(process).run()
 
-    
-
     async def readline(self) -> str:
         return cast(str, self._process.stdin.readline())
 
@@ -53,54 +55,58 @@ class ChatClient:
             if client != self:
                 client.write(msg)
 
-
     def begin_auth(self, username: str) -> bool:
-            # If the user's password is the empty string, no auth is required
-            #return False
-            return True # passwords.get(username) != b''
+        # If the user's password is the empty string, no auth is required
+        # return False
+        return True  # passwords.get(username) != b''
 
     def password_auth_supported(self) -> bool:
         return True
 
     def validate_password(self, username: str, password: str) -> bool:
-        #if username not in passwords:
+        # if username not in passwords:
         #    return False
-        #pw = passwords[username]
-        #if not password and not pw:
+        # pw = passwords[username]
+        # if not password and not pw:
         #    return True
         return True
-        #return bcrypt.checkpw(password.encode('utf-8'), pw)
-
+        # return bcrypt.checkpw(password.encode('utf-8'), pw)
 
     async def run(self) -> None:
-        self.write('Welcome to chat!\n\n')
+        self.write("Welcome to chat!\n\n")
 
-        self.write('Enter your name: ')
-        name = (await self.readline()).rstrip('\n')
+        self.write("Enter your name: ")
+        name = (await self.readline()).rstrip("\n")
 
-        self.write(f'\n{len(self._clients)} other users are connected.\n\n')
+        self.write(f"\n{len(self._clients)} other users are connected.\n\n")
 
         self._clients.append(self)
-        self.broadcast(f'*** {name} has entered chat ***\n')
+        self.broadcast(f"*** {name} has entered chat ***\n")
 
         try:
             async for line in self._process.stdin:
-                self.broadcast(f'{name}: {line}')
+                self.broadcast(f"{name}: {line}")
         except asyncssh.BreakReceived:
             pass
 
-        self.broadcast(f'*** {name} has left chat ***\n')
+        self.broadcast(f"*** {name} has left chat ***\n")
         self._clients.remove(self)
 
+
 async def start_server() -> None:
-    await asyncssh.listen('', 2235, server_host_keys=['ssh_host_key'],
-                          process_factory=ChatClient.handle_client)
+    await asyncssh.listen(
+        "",
+        2235,
+        server_host_keys=["ssh_host_key"],
+        process_factory=ChatClient.handle_client,
+    )
+
 
 loop = asyncio.new_event_loop()
 
 try:
     loop.run_until_complete(start_server())
 except (OSError, asyncssh.Error) as exc:
-    sys.exit('Error starting server: ' + str(exc))
+    sys.exit("Error starting server: " + str(exc))
 
 loop.run_forever()