Repository: MasoniteFramework/masonite (language: python)

Issue:
Refactor Route.py to include a default option for route names
Closes #745 


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/pythonapp.yml b/.github/workflows/pythonapp.yml
index 023daaaed..8e6b36dda 100644
--- a/.github/workflows/pythonapp.yml
+++ b/.github/workflows/pythonapp.yml
@@ -7,7 +7,7 @@ jobs:
     runs-on: ubuntu-latest
     strategy:
       matrix:
-        python-version: ["3.9", "3.10", "3.11"]
+        python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
     name: Python ${{ matrix.python-version }}
     steps:
       - uses: actions/checkout@v3
diff --git a/.gitignore b/.gitignore
index ba1ff3840..6591d4bde 100644
--- a/.gitignore
+++ b/.gitignore
@@ -12,5 +12,3 @@ src/masonite.egg-info/*
 .vscode
 build/
 venv4
-.python-version
-*.whl
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 727f19647..8981da29b 100644
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 init:
 	cp .env-example .env
-	pip install --no-cache-dir --upgrade -r requirements.txt
+	pip install -r requirements.txt
 	pip install '.[test]'
 	# Create MySQL Database
 	# Create Postgres Database
diff --git a/README.md b/README.md
index ffdef588e..72c75c991 100644
--- a/README.md
+++ b/README.md
@@ -4,7 +4,7 @@
 </p>
 <p align="center">
   <img alt="GitHub Workflow Status" src="https://img.shields.io/github/actions/workflow/status/MasoniteFramework/masonite/pythonapp.yml?branch=develop">
-  <img src="https://img.shields.io/badge/python-3.7+-blue.svg" alt="Python Version">
+
   <img alt="GitHub release (latest by date including pre-releases)" src="https://img.shields.io/github/v/release/MasoniteFramework/masonite?include_prereleases">
   <img src="https://img.shields.io/github/license/MasoniteFramework/masonite.svg" alt="License">
   <a href="https://github.com/psf/black"><img alt="Code style: black" src="https://img.shields.io/badge/code%20style-black-000000.svg"></a>
@@ -32,7 +32,7 @@ Have questions or want to talk? Be sure to join the [Masonite Discord Community]
 
 ## Getting Started Quickly
 
-Create and activate a virtual environment and if you have a working Python 3.7+ installation then getting started is as quick as typing
+Create and activate a virtual environment and if you have a working Python <= 3.11 installation then getting started is as quick as typing
 
 ```bash
 pip install masonite
diff --git a/poetry.lock b/poetry.lock
deleted file mode 100644
index 1dcfa8c36..000000000
--- a/poetry.lock
+++ /dev/null
@@ -1,910 +0,0 @@
-# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand.
-
-[[package]]
-name = "bcrypt"
-version = "3.2.2"
-description = "Modern password hashing for your software and your servers"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "bcrypt-3.2.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:7180d98a96f00b1050e93f5b0f556e658605dd9f524d0b0e68ae7944673f525e"},
-    {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:61bae49580dce88095d669226d5076d0b9d927754cedbdf76c6c9f5099ad6f26"},
-    {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88273d806ab3a50d06bc6a2fc7c87d737dd669b76ad955f449c43095389bc8fb"},
-    {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_24_x86_64.whl", hash = "sha256:6d2cb9d969bfca5bc08e45864137276e4c3d3d7de2b162171def3d188bf9d34a"},
-    {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2b02d6bfc6336d1094276f3f588aa1225a598e27f8e3388f4db9948cb707b521"},
-    {file = "bcrypt-3.2.2-cp36-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a2c46100e315c3a5b90fdc53e429c006c5f962529bc27e1dfd656292c20ccc40"},
-    {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:7d9ba2e41e330d2af4af6b1b6ec9e6128e91343d0b4afb9282e54e5508f31baa"},
-    {file = "bcrypt-3.2.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:cd43303d6b8a165c29ec6756afd169faba9396a9472cdff753fe9f19b96ce2fa"},
-    {file = "bcrypt-3.2.2-cp36-abi3-win32.whl", hash = "sha256:4e029cef560967fb0cf4a802bcf4d562d3d6b4b1bf81de5ec1abbe0f1adb027e"},
-    {file = "bcrypt-3.2.2-cp36-abi3-win_amd64.whl", hash = "sha256:7ff2069240c6bbe49109fe84ca80508773a904f5a8cb960e02a977f7f519b129"},
-    {file = "bcrypt-3.2.2.tar.gz", hash = "sha256:433c410c2177057705da2a9f2cd01dd157493b2a7ac14c8593a16b3dab6b6bfb"},
-]
-
-[package.dependencies]
-cffi = ">=1.1"
-
-[package.extras]
-tests = ["pytest (>=3.2.1,!=3.3.0)"]
-typecheck = ["mypy"]
-
-[[package]]
-name = "certifi"
-version = "2024.7.4"
-description = "Python package for providing Mozilla's CA Bundle."
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
-    {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
-]
-
-[[package]]
-name = "cffi"
-version = "1.16.0"
-description = "Foreign Function Interface for Python calling C code."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"},
-    {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"},
-    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"},
-    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"},
-    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"},
-    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"},
-    {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"},
-    {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"},
-    {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"},
-    {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"},
-    {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"},
-    {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"},
-    {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"},
-    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"},
-    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"},
-    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"},
-    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"},
-    {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"},
-    {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"},
-    {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"},
-    {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"},
-    {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"},
-    {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"},
-    {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"},
-    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"},
-    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"},
-    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"},
-    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"},
-    {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"},
-    {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"},
-    {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"},
-    {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"},
-    {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"},
-    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"},
-    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"},
-    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"},
-    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"},
-    {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"},
-    {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"},
-    {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"},
-    {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"},
-    {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"},
-    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"},
-    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"},
-    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"},
-    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"},
-    {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"},
-    {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"},
-    {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"},
-    {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"},
-    {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"},
-    {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"},
-]
-
-[package.dependencies]
-pycparser = "*"
-
-[[package]]
-name = "charset-normalizer"
-version = "3.3.2"
-description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
-optional = false
-python-versions = ">=3.7.0"
-files = [
-    {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"},
-    {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"},
-    {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"},
-    {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"},
-    {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"},
-    {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"},
-    {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"},
-    {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"},
-]
-
-[[package]]
-name = "cleo"
-version = "0.8.1"
-description = "Cleo allows you to create beautiful and testable command-line interfaces."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "cleo-0.8.1-py2.py3-none-any.whl", hash = "sha256:141cda6dc94a92343be626bb87a0b6c86ae291dfc732a57bf04310d4b4201753"},
-    {file = "cleo-0.8.1.tar.gz", hash = "sha256:3d0e22d30117851b45970b6c14aca4ab0b18b1b53c8af57bed13208147e4069f"},
-]
-
-[package.dependencies]
-clikit = ">=0.6.0,<0.7.0"
-
-[[package]]
-name = "clikit"
-version = "0.6.2"
-description = "CliKit is a group of utilities to build beautiful and testable command line interfaces."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "clikit-0.6.2-py2.py3-none-any.whl", hash = "sha256:71268e074e68082306e23d7369a7b99f824a0ef926e55ba2665e911f7208489e"},
-    {file = "clikit-0.6.2.tar.gz", hash = "sha256:442ee5db9a14120635c5990bcdbfe7c03ada5898291f0c802f77be71569ded59"},
-]
-
-[package.dependencies]
-crashtest = {version = ">=0.3.0,<0.4.0", markers = "python_version >= \"3.6\" and python_version < \"4.0\""}
-pastel = ">=0.2.0,<0.3.0"
-pylev = ">=1.3,<2.0"
-
-[[package]]
-name = "colorama"
-version = "0.4.6"
-description = "Cross-platform colored terminal text."
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
-files = [
-    {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
-    {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
-]
-
-[[package]]
-name = "crashtest"
-version = "0.3.1"
-description = "Manage Python errors with ease"
-optional = false
-python-versions = ">=3.6,<4.0"
-files = [
-    {file = "crashtest-0.3.1-py3-none-any.whl", hash = "sha256:300f4b0825f57688b47b6d70c6a31de33512eb2fa1ac614f780939aa0cf91680"},
-    {file = "crashtest-0.3.1.tar.gz", hash = "sha256:42ca7b6ce88b6c7433e2ce47ea884e91ec93104a4b754998be498a8e6c3d37dd"},
-]
-
-[[package]]
-name = "cryptography"
-version = "36.0.2"
-description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers."
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_universal2.whl", hash = "sha256:4e2dddd38a5ba733be6a025a1475a9f45e4e41139d1321f412c6b360b19070b6"},
-    {file = "cryptography-36.0.2-cp36-abi3-macosx_10_10_x86_64.whl", hash = "sha256:4881d09298cd0b669bb15b9cfe6166f16fc1277b4ed0d04a22f3d6430cb30f1d"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ea634401ca02367c1567f012317502ef3437522e2fc44a3ea1844de028fa4b84"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.manylinux_2_24_aarch64.whl", hash = "sha256:7be666cc4599b415f320839e36367b273db8501127b38316f3b9f22f17a0b815"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8241cac0aae90b82d6b5c443b853723bcc66963970c67e56e71a2609dc4b5eaf"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b2d54e787a884ffc6e187262823b6feb06c338084bbe80d45166a1cb1c6c5bf"},
-    {file = "cryptography-36.0.2-cp36-abi3-manylinux_2_24_x86_64.whl", hash = "sha256:c2c5250ff0d36fd58550252f54915776940e4e866f38f3a7866d92b32a654b86"},
-    {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:ec6597aa85ce03f3e507566b8bcdf9da2227ec86c4266bd5e6ab4d9e0cc8dab2"},
-    {file = "cryptography-36.0.2-cp36-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:ca9f686517ec2c4a4ce930207f75c00bf03d94e5063cbc00a1dc42531511b7eb"},
-    {file = "cryptography-36.0.2-cp36-abi3-win32.whl", hash = "sha256:f64b232348ee82f13aac22856515ce0195837f6968aeaa94a3d0353ea2ec06a6"},
-    {file = "cryptography-36.0.2-cp36-abi3-win_amd64.whl", hash = "sha256:53e0285b49fd0ab6e604f4c5d9c5ddd98de77018542e88366923f152dbeb3c29"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32db5cc49c73f39aac27574522cecd0a4bb7384e71198bc65a0d23f901e89bb7"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b3d199647468d410994dbeb8cec5816fb74feb9368aedf300af709ef507e3e"},
-    {file = "cryptography-36.0.2-pp37-pypy37_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:da73d095f8590ad437cd5e9faf6628a218aa7c387e1fdf67b888b47ba56a17f0"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-macosx_10_10_x86_64.whl", hash = "sha256:0a3bf09bb0b7a2c93ce7b98cb107e9170a90c51a0162a20af1c61c765b90e60b"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8897b7b7ec077c819187a123174b645eb680c13df68354ed99f9b40a50898f77"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82740818f2f240a5da8dfb8943b360e4f24022b093207160c77cadade47d7c85"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-manylinux_2_24_x86_64.whl", hash = "sha256:1f64a62b3b75e4005df19d3b5235abd43fa6358d5516cfc43d87aeba8d08dd51"},
-    {file = "cryptography-36.0.2-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:e167b6b710c7f7bc54e67ef593f8731e1f45aa35f8a8a7b72d6e42ec76afd4b3"},
-    {file = "cryptography-36.0.2.tar.gz", hash = "sha256:70f8f4f7bb2ac9f340655cbac89d68c527af5bb4387522a8413e841e3e6628c9"},
-]
-
-[package.dependencies]
-cffi = ">=1.12"
-
-[package.extras]
-docs = ["sphinx (>=1.6.5,!=1.8.0,!=3.1.0,!=3.1.1)", "sphinx-rtd-theme"]
-docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"]
-pep8test = ["black", "flake8", "flake8-import-order", "pep8-naming"]
-sdist = ["setuptools-rust (>=0.11.4)"]
-ssh = ["bcrypt (>=3.1.5)"]
-test = ["hypothesis (>=1.11.4,!=3.79.2)", "iso8601", "pretend", "pytest (>=6.2.0)", "pytest-cov", "pytest-subtests", "pytest-xdist", "pytz"]
-
-[[package]]
-name = "dotty-dict"
-version = "1.3.1"
-description = "Dictionary wrapper for quick access to deeply nested keys."
-optional = false
-python-versions = ">=3.5,<4.0"
-files = [
-    {file = "dotty_dict-1.3.1-py3-none-any.whl", hash = "sha256:5022d234d9922f13aa711b4950372a06a6d64cb6d6db9ba43d0ba133ebfce31f"},
-    {file = "dotty_dict-1.3.1.tar.gz", hash = "sha256:4b016e03b8ae265539757a53eba24b9bfda506fb94fbce0bee843c6f05541a15"},
-]
-
-[[package]]
-name = "exceptiongroup"
-version = "1.2.1"
-description = "Backport of PEP 654 (exception groups)"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
-    {file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
-]
-
-[package.extras]
-test = ["pytest (>=6)"]
-
-[[package]]
-name = "exceptionite"
-version = "2.2.5"
-description = "Exception Handling Made Easy"
-optional = false
-python-versions = "*"
-files = [
-    {file = "exceptionite-2.2.5-py3-none-any.whl", hash = "sha256:f6a4ee8a527f972a1cdc4930176fa5b786a362208e96a663a272067abef09d66"},
-    {file = "exceptionite-2.2.5.tar.gz", hash = "sha256:3f76eede3eebc3c50e2ed8897609ef7c09bee176fc71ebe3fbe99f6822060dd0"},
-]
-
-[package.dependencies]
-colorama = "*"
-dotty-dict = "*"
-jinja2 = "*"
-mock = "*"
-requests = "*"
-typing-extensions = "*"
-
-[package.extras]
-test = ["black", "coverage", "flake8", "pytest", "pytest-cov", "twine (>=1.5.0)", "wheel"]
-
-[[package]]
-name = "faker"
-version = "13.16.0"
-description = "Faker is a Python package that generates fake data for you."
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "Faker-13.16.0-py3-none-any.whl", hash = "sha256:920f94d5aa865fd922bc29f2cf75c75b4d86b30eec23e7174d7513241b759b05"},
-    {file = "Faker-13.16.0.tar.gz", hash = "sha256:25c5be99bc5fd8676eea8c1490e0de87f6d9734651c7af2cefc99b322b2936f4"},
-]
-
-[package.dependencies]
-python-dateutil = ">=2.4"
-
-[[package]]
-name = "hashids"
-version = "1.3.1"
-description = "Implements the hashids algorithm in python. For more information, visit http://hashids.org/"
-optional = false
-python-versions = ">=2.7"
-files = [
-    {file = "hashids-1.3.1-py2.py3-none-any.whl", hash = "sha256:8bddd1acba501bfc9306e7e5a99a1667f4f2cacdc20cbd70bcc5ddfa5147c94c"},
-    {file = "hashids-1.3.1.tar.gz", hash = "sha256:6c3dc775e65efc2ce2c157a65acb776d634cb814598f406469abef00ae3f635c"},
-]
-
-[package.extras]
-test = ["pytest (>=2.1.0)"]
-
-[[package]]
-name = "hfilesize"
-version = "0.1.0"
-description = "Human Readable File Sizes"
-optional = false
-python-versions = "*"
-files = [
-    {file = "hfilesize-0.1.0.zip", hash = "sha256:560578c395a3b9b0fd25f93c6fb75008e0797cff48b462656c2bc7373179fa30"},
-]
-
-[[package]]
-name = "hupper"
-version = "1.10.3"
-description = "Integrated process monitor for developing and reloading daemons."
-optional = false
-python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*"
-files = [
-    {file = "hupper-1.10.3-py2.py3-none-any.whl", hash = "sha256:f683850d62598c02faf3c7cdaaa727d8cbe3c5a2497a5737a8358386903b2601"},
-    {file = "hupper-1.10.3.tar.gz", hash = "sha256:cd6f51b72c7587bc9bce8a65ecd025a1e95f1b03284519bfe91284d010316cd9"},
-]
-
-[package.extras]
-docs = ["Sphinx", "pylons-sphinx-themes", "watchdog"]
-testing = ["mock", "pytest", "pytest-cov", "watchdog"]
-
-[[package]]
-name = "idna"
-version = "3.7"
-description = "Internationalized Domain Names in Applications (IDNA)"
-optional = false
-python-versions = ">=3.5"
-files = [
-    {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
-    {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
-]
-
-[[package]]
-name = "inflection"
-version = "0.3.1"
-description = "A port of Ruby on Rails inflector to Python"
-optional = false
-python-versions = "*"
-files = [
-    {file = "inflection-0.3.1.tar.gz", hash = "sha256:18ea7fb7a7d152853386523def08736aa8c32636b047ade55f7578c4edeb16ca"},
-]
-
-[[package]]
-name = "iniconfig"
-version = "2.0.0"
-description = "brain-dead simple config-ini parsing"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
-    {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
-]
-
-[[package]]
-name = "jinja2"
-version = "3.0.3"
-description = "A very fast and expressive template engine."
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "Jinja2-3.0.3-py3-none-any.whl", hash = "sha256:077ce6014f7b40d03b47d1f1ca4b0fc8328a692bd284016f806ed0eaca390ad8"},
-    {file = "Jinja2-3.0.3.tar.gz", hash = "sha256:611bb273cd68f3b993fabdc4064fc858c5b47a973cb5aa7999ec1ba405c87cd7"},
-]
-
-[package.dependencies]
-MarkupSafe = ">=2.0"
-
-[package.extras]
-i18n = ["Babel (>=2.7)"]
-
-[[package]]
-name = "markupsafe"
-version = "2.1.5"
-description = "Safely add untrusted strings to HTML/XML markup."
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"},
-    {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"},
-    {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"},
-    {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"},
-    {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"},
-    {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"},
-    {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"},
-    {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"},
-]
-
-[[package]]
-name = "masonite-orm"
-version = "2.22.1"
-description = "The Official Masonite ORM"
-optional = false
-python-versions = "*"
-files = [
-    {file = "masonite_orm-2.22.1.tar.gz", hash = "sha256:b49bed04af67bdff4b791970a351f45d1890e19f7852c1974be18b48637bccb2"},
-]
-
-[package.dependencies]
-cleo = ">=0.8.0,<0.9"
-faker = ">=4.1.0,<14.0"
-inflection = ">=0.3,<0.6"
-pendulum = ">=2.1,<2.2"
-
-[package.extras]
-test = ["coverage", "pytest"]
-
-[[package]]
-name = "mock"
-version = "5.1.0"
-description = "Rolling backport of unittest.mock for all Pythons"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"},
-    {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"},
-]
-
-[package.extras]
-build = ["blurb", "twine", "wheel"]
-docs = ["sphinx"]
-test = ["pytest", "pytest-cov"]
-
-[[package]]
-name = "packaging"
-version = "24.1"
-description = "Core utilities for Python packages"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"},
-    {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"},
-]
-
-[[package]]
-name = "pastel"
-version = "0.2.1"
-description = "Bring colors to your terminal."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "pastel-0.2.1-py2.py3-none-any.whl", hash = "sha256:4349225fcdf6c2bb34d483e523475de5bb04a5c10ef711263452cb37d7dd4364"},
-    {file = "pastel-0.2.1.tar.gz", hash = "sha256:e6581ac04e973cac858828c6202c1e1e81fee1dc7de7683f3e1ffe0bfd8a573d"},
-]
-
-[[package]]
-name = "pendulum"
-version = "2.1.2"
-description = "Python datetimes made easy"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-files = [
-    {file = "pendulum-2.1.2-cp27-cp27m-macosx_10_15_x86_64.whl", hash = "sha256:b6c352f4bd32dff1ea7066bd31ad0f71f8d8100b9ff709fb343f3b86cee43efe"},
-    {file = "pendulum-2.1.2-cp27-cp27m-win_amd64.whl", hash = "sha256:318f72f62e8e23cd6660dbafe1e346950281a9aed144b5c596b2ddabc1d19739"},
-    {file = "pendulum-2.1.2-cp35-cp35m-macosx_10_15_x86_64.whl", hash = "sha256:0731f0c661a3cb779d398803655494893c9f581f6488048b3fb629c2342b5394"},
-    {file = "pendulum-2.1.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:3481fad1dc3f6f6738bd575a951d3c15d4b4ce7c82dce37cf8ac1483fde6e8b0"},
-    {file = "pendulum-2.1.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:9702069c694306297ed362ce7e3c1ef8404ac8ede39f9b28b7c1a7ad8c3959e3"},
-    {file = "pendulum-2.1.2-cp35-cp35m-win_amd64.whl", hash = "sha256:fb53ffa0085002ddd43b6ca61a7b34f2d4d7c3ed66f931fe599e1a531b42af9b"},
-    {file = "pendulum-2.1.2-cp36-cp36m-macosx_10_15_x86_64.whl", hash = "sha256:c501749fdd3d6f9e726086bf0cd4437281ed47e7bca132ddb522f86a1645d360"},
-    {file = "pendulum-2.1.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:c807a578a532eeb226150d5006f156632df2cc8c5693d778324b43ff8c515dd0"},
-    {file = "pendulum-2.1.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:2d1619a721df661e506eff8db8614016f0720ac171fe80dda1333ee44e684087"},
-    {file = "pendulum-2.1.2-cp36-cp36m-win_amd64.whl", hash = "sha256:f888f2d2909a414680a29ae74d0592758f2b9fcdee3549887779cd4055e975db"},
-    {file = "pendulum-2.1.2-cp37-cp37m-macosx_10_15_x86_64.whl", hash = "sha256:e95d329384717c7bf627bf27e204bc3b15c8238fa8d9d9781d93712776c14002"},
-    {file = "pendulum-2.1.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4c9c689747f39d0d02a9f94fcee737b34a5773803a64a5fdb046ee9cac7442c5"},
-    {file = "pendulum-2.1.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:1245cd0075a3c6d889f581f6325dd8404aca5884dea7223a5566c38aab94642b"},
-    {file = "pendulum-2.1.2-cp37-cp37m-win_amd64.whl", hash = "sha256:db0a40d8bcd27b4fb46676e8eb3c732c67a5a5e6bfab8927028224fbced0b40b"},
-    {file = "pendulum-2.1.2-cp38-cp38-macosx_10_15_x86_64.whl", hash = "sha256:f5e236e7730cab1644e1b87aca3d2ff3e375a608542e90fe25685dae46310116"},
-    {file = "pendulum-2.1.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:de42ea3e2943171a9e95141f2eecf972480636e8e484ccffaf1e833929e9e052"},
-    {file = "pendulum-2.1.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7c5ec650cb4bec4c63a89a0242cc8c3cebcec92fcfe937c417ba18277d8560be"},
-    {file = "pendulum-2.1.2-cp38-cp38-win_amd64.whl", hash = "sha256:33fb61601083f3eb1d15edeb45274f73c63b3c44a8524703dc143f4212bf3269"},
-    {file = "pendulum-2.1.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:29c40a6f2942376185728c9a0347d7c0f07905638c83007e1d262781f1e6953a"},
-    {file = "pendulum-2.1.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:94b1fc947bfe38579b28e1cccb36f7e28a15e841f30384b5ad6c5e31055c85d7"},
-    {file = "pendulum-2.1.2.tar.gz", hash = "sha256:b06a0ca1bfe41c990bbf0c029f0b6501a7f2ec4e38bfec730712015e8860f207"},
-]
-
-[package.dependencies]
-python-dateutil = ">=2.6,<3.0"
-pytzdata = ">=2020.1"
-
-[[package]]
-name = "pluggy"
-version = "1.5.0"
-description = "plugin and hook calling mechanisms for python"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
-    {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
-]
-
-[package.extras]
-dev = ["pre-commit", "tox"]
-testing = ["pytest", "pytest-benchmark"]
-
-[[package]]
-name = "pycparser"
-version = "2.22"
-description = "C parser in Python"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"},
-    {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"},
-]
-
-[[package]]
-name = "pyjwt"
-version = "2.4.0"
-description = "JSON Web Token implementation in Python"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "PyJWT-2.4.0-py3-none-any.whl", hash = "sha256:72d1d253f32dbd4f5c88eaf1fdc62f3a19f676ccbadb9dbc5d07e951b2b26daf"},
-    {file = "PyJWT-2.4.0.tar.gz", hash = "sha256:d42908208c699b3b973cbeb01a969ba6a96c821eefb1c5bfe4c390c01d67abba"},
-]
-
-[package.extras]
-crypto = ["cryptography (>=3.3.1)"]
-dev = ["coverage[toml] (==5.0.4)", "cryptography (>=3.3.1)", "mypy", "pre-commit", "pytest (>=6.0.0,<7.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"]
-docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"]
-tests = ["coverage[toml] (==5.0.4)", "pytest (>=6.0.0,<7.0.0)"]
-
-[[package]]
-name = "pylev"
-version = "1.4.0"
-description = "A pure Python Levenshtein implementation that's not freaking GPL'd."
-optional = false
-python-versions = "*"
-files = [
-    {file = "pylev-1.4.0-py2.py3-none-any.whl", hash = "sha256:7b2e2aa7b00e05bb3f7650eb506fc89f474f70493271a35c242d9a92188ad3dd"},
-    {file = "pylev-1.4.0.tar.gz", hash = "sha256:9e77e941042ad3a4cc305dcdf2b2dec1aec2fbe3dd9015d2698ad02b173006d1"},
-]
-
-[[package]]
-name = "pytest"
-version = "7.4.4"
-description = "pytest: simple powerful testing with Python"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"},
-    {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"},
-]
-
-[package.dependencies]
-colorama = {version = "*", markers = "sys_platform == \"win32\""}
-exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
-iniconfig = "*"
-packaging = "*"
-pluggy = ">=0.12,<2.0"
-tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""}
-
-[package.extras]
-testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
-
-[[package]]
-name = "python-dateutil"
-version = "2.9.0.post0"
-description = "Extensions to the standard Python datetime module"
-optional = false
-python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7"
-files = [
-    {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"},
-    {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"},
-]
-
-[package.dependencies]
-six = ">=1.5"
-
-[[package]]
-name = "python-dotenv"
-version = "0.15.0"
-description = "Add .env support to your django/flask apps in development and deployments"
-optional = false
-python-versions = "*"
-files = [
-    {file = "python-dotenv-0.15.0.tar.gz", hash = "sha256:587825ed60b1711daea4832cf37524dfd404325b7db5e25ebe88c495c9f807a0"},
-    {file = "python_dotenv-0.15.0-py2.py3-none-any.whl", hash = "sha256:0c8d1b80d1a1e91717ea7d526178e3882732420b03f08afea0406db6402e220e"},
-]
-
-[package.extras]
-cli = ["click (>=5.0)"]
-
-[[package]]
-name = "pytzdata"
-version = "2020.1"
-description = "The Olson timezone database for Python."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*"
-files = [
-    {file = "pytzdata-2020.1-py2.py3-none-any.whl", hash = "sha256:e1e14750bcf95016381e4d472bad004eef710f2d6417240904070b3d6654485f"},
-    {file = "pytzdata-2020.1.tar.gz", hash = "sha256:3efa13b335a00a8de1d345ae41ec78dd11c9f8807f522d39850f2dd828681540"},
-]
-
-[[package]]
-name = "requests"
-version = "2.32.3"
-description = "Python HTTP for Humans."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
-    {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
-]
-
-[package.dependencies]
-certifi = ">=2017.4.17"
-charset-normalizer = ">=2,<4"
-idna = ">=2.5,<4"
-urllib3 = ">=1.21.1,<3"
-
-[package.extras]
-socks = ["PySocks (>=1.5.6,!=1.5.7)"]
-use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
-
-[[package]]
-name = "requests-file"
-version = "2.1.0"
-description = "File transport adapter for Requests"
-optional = false
-python-versions = "*"
-files = [
-    {file = "requests_file-2.1.0-py2.py3-none-any.whl", hash = "sha256:cf270de5a4c5874e84599fc5778303d496c10ae5e870bfa378818f35d21bda5c"},
-    {file = "requests_file-2.1.0.tar.gz", hash = "sha256:0f549a3f3b0699415ac04d167e9cb39bccfb730cb832b4d20be3d9867356e658"},
-]
-
-[package.dependencies]
-requests = ">=1.0.0"
-
-[[package]]
-name = "setuptools"
-version = "70.2.0"
-description = "Easily download, build, install, upgrade, and uninstall Python packages"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "setuptools-70.2.0-py3-none-any.whl", hash = "sha256:b8b8060bb426838fbe942479c90296ce976249451118ef566a5a0b7d8b78fb05"},
-    {file = "setuptools-70.2.0.tar.gz", hash = "sha256:bd63e505105011b25c3c11f753f7e3b8465ea739efddaccef8f0efac2137bac1"},
-]
-
-[package.extras]
-doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "pyproject-hooks (!=1.1)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"]
-test = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "importlib-metadata", "ini2toml[lite] (>=0.14)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "jaraco.test", "mypy (==1.10.0)", "packaging (>=23.2)", "pip (>=19.1)", "pyproject-hooks (!=1.1)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-home (>=0.5)", "pytest-mypy", "pytest-perf", "pytest-ruff (>=0.3.2)", "pytest-subprocess", "pytest-timeout", "pytest-xdist (>=3)", "tomli", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"]
-
-[[package]]
-name = "six"
-version = "1.16.0"
-description = "Python 2 and 3 compatibility utilities"
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*"
-files = [
-    {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"},
-    {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"},
-]
-
-[[package]]
-name = "tldextract"
-version = "2.2.3"
-description = "Accurately separate the TLD from the registered domain and subdomains of a URL, using the Public Suffix List. By default, this includes the public ICANN TLDs and their exceptions. You can optionally support the Public Suffix List's private domains as well."
-optional = false
-python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*"
-files = [
-    {file = "tldextract-2.2.3-py2.py3-none-any.whl", hash = "sha256:c2a8a392edf3ea6fa8be80930f04c3ac29e91fa604cb2139bdf6a37fc1e1ac6d"},
-    {file = "tldextract-2.2.3.tar.gz", hash = "sha256:ab0e38977a129c72729476d5f8c85a8e1f8e49e9202e1db8dca76e95da7be9a8"},
-]
-
-[package.dependencies]
-idna = "*"
-requests = ">=2.1.0"
-requests-file = ">=1.4"
-
-[[package]]
-name = "tomli"
-version = "2.0.1"
-description = "A lil' TOML parser"
-optional = false
-python-versions = ">=3.7"
-files = [
-    {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"},
-    {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"},
-]
-
-[[package]]
-name = "typing-extensions"
-version = "4.12.2"
-description = "Backported and Experimental Type Hints for Python 3.8+"
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
-    {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
-]
-
-[[package]]
-name = "urllib3"
-version = "2.2.2"
-description = "HTTP library with thread-safe connection pooling, file post, and more."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"},
-    {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"},
-]
-
-[package.extras]
-brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
-h2 = ["h2 (>=4,<5)"]
-socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
-zstd = ["zstandard (>=0.18.0)"]
-
-[[package]]
-name = "watchdog"
-version = "2.3.1"
-description = "Filesystem events monitoring"
-optional = false
-python-versions = ">=3.6"
-files = [
-    {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d1f1200d4ec53b88bf04ab636f9133cb703eb19768a39351cee649de21a33697"},
-    {file = "watchdog-2.3.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:564e7739abd4bd348aeafbf71cc006b6c0ccda3160c7053c4a53b67d14091d42"},
-    {file = "watchdog-2.3.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:95ad708a9454050a46f741ba5e2f3468655ea22da1114e4c40b8cbdaca572565"},
-    {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a073c91a6ef0dda488087669586768195c3080c66866144880f03445ca23ef16"},
-    {file = "watchdog-2.3.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:aa8b028750b43e80eea9946d01925168eeadb488dfdef1d82be4b1e28067f375"},
-    {file = "watchdog-2.3.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:964fd236cd443933268ae49b59706569c8b741073dbfd7ca705492bae9d39aab"},
-    {file = "watchdog-2.3.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:91fd146d723392b3e6eb1ac21f122fcce149a194a2ba0a82c5e4d0ee29cd954c"},
-    {file = "watchdog-2.3.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:efe3252137392a471a2174d721e1037a0e6a5da7beb72a021e662b7000a9903f"},
-    {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:85bf2263290591b7c5fa01140601b64c831be88084de41efbcba6ea289874f44"},
-    {file = "watchdog-2.3.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:8f2df370cd8e4e18499dd0bfdef476431bcc396108b97195d9448d90924e3131"},
-    {file = "watchdog-2.3.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ea5d86d1bcf4a9d24610aa2f6f25492f441960cf04aed2bd9a97db439b643a7b"},
-    {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6f5d0f7eac86807275eba40b577c671b306f6f335ba63a5c5a348da151aba0fc"},
-    {file = "watchdog-2.3.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b848c71ef2b15d0ef02f69da8cc120d335cec0ed82a3fa7779e27a5a8527225"},
-    {file = "watchdog-2.3.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0d9878be36d2b9271e3abaa6f4f051b363ff54dbbe7e7df1af3c920e4311ee43"},
-    {file = "watchdog-2.3.1-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4cd61f98cb37143206818cb1786d2438626aa78d682a8f2ecee239055a9771d5"},
-    {file = "watchdog-2.3.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:3d2dbcf1acd96e7a9c9aefed201c47c8e311075105d94ce5e899f118155709fd"},
-    {file = "watchdog-2.3.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03f342a9432fe08107defbe8e405a2cb922c5d00c4c6c168c68b633c64ce6190"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:7a596f9415a378d0339681efc08d2249e48975daae391d58f2e22a3673b977cf"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:0e1dd6d449267cc7d6935d7fe27ee0426af6ee16578eed93bacb1be9ff824d2d"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_i686.whl", hash = "sha256:7a1876f660e32027a1a46f8a0fa5747ad4fcf86cb451860eae61a26e102c8c79"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:2caf77ae137935c1466f8cefd4a3aec7017b6969f425d086e6a528241cba7256"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:53f3e95081280898d9e4fc51c5c69017715929e4eea1ab45801d5e903dd518ad"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:9da7acb9af7e4a272089bd2af0171d23e0d6271385c51d4d9bde91fe918c53ed"},
-    {file = "watchdog-2.3.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:8a4d484e846dcd75e96b96d80d80445302621be40e293bfdf34a631cab3b33dc"},
-    {file = "watchdog-2.3.1-py3-none-win32.whl", hash = "sha256:a74155398434937ac2780fd257c045954de5b11b5c52fc844e2199ce3eecf4cf"},
-    {file = "watchdog-2.3.1-py3-none-win_amd64.whl", hash = "sha256:5defe4f0918a2a1a4afbe4dbb967f743ac3a93d546ea4674567806375b024adb"},
-    {file = "watchdog-2.3.1-py3-none-win_ia64.whl", hash = "sha256:4109cccf214b7e3462e8403ab1e5b17b302ecce6c103eb2fc3afa534a7f27b96"},
-    {file = "watchdog-2.3.1.tar.gz", hash = "sha256:d9f9ed26ed22a9d331820a8432c3680707ea8b54121ddcc9dc7d9f2ceeb36906"},
-]
-
-[package.extras]
-watchmedo = ["PyYAML (>=3.10)"]
-
-[[package]]
-name = "werkzeug"
-version = "2.3.8"
-description = "The comprehensive WSGI web application library."
-optional = false
-python-versions = ">=3.8"
-files = [
-    {file = "werkzeug-2.3.8-py3-none-any.whl", hash = "sha256:bba1f19f8ec89d4d607a3bd62f1904bd2e609472d93cd85e9d4e178f472c3748"},
-    {file = "werkzeug-2.3.8.tar.gz", hash = "sha256:554b257c74bbeb7a0d254160a4f8ffe185243f52a52035060b761ca62d977f03"},
-]
-
-[package.dependencies]
-MarkupSafe = ">=2.1.1"
-
-[package.extras]
-watchdog = ["watchdog (>=2.3)"]
-
-[[package]]
-name = "whitenoise"
-version = "5.2.0"
-description = "Radically simplified static file serving for WSGI applications"
-optional = false
-python-versions = ">=3.5, <4"
-files = [
-    {file = "whitenoise-5.2.0-py2.py3-none-any.whl", hash = "sha256:05d00198c777028d72d8b0bbd234db605ef6d60e9410125124002518a48e515d"},
-    {file = "whitenoise-5.2.0.tar.gz", hash = "sha256:05ce0be39ad85740a78750c86a93485c40f08ad8c62a6006de0233765996e5c7"},
-]
-
-[package.extras]
-brotli = ["Brotli"]
-
-[metadata]
-lock-version = "2.0"
-python-versions = "^3.9"
-content-hash = "e48879056ae0b1a538a554f75c399641dc5a4de7b82d8510244fa0219a709ca2"
diff --git a/pyproject.toml b/pyproject.toml
deleted file mode 100644
index 2e97ae1d4..000000000
--- a/pyproject.toml
+++ /dev/null
@@ -1,35 +0,0 @@
-[tool.poetry]
-authors = ['Joe Mancuso', 'Eduardo Aguad']
-description = "Masonite is a modern and developer centric Python web framework."
-license = "MIT"
-name = "masonite"
-version = "5.0.0"
-
-[tool.poetry.dependencies]
-python = "^3.9"
-inflection = ">=0.3,<0.4"
-exceptionite = ">=2.2,<3.0"
-pendulum = ">=2,<3"
-jinja2 = "<3.1.0"
-cleo = ">=0.8.1,<0.9"
-hupper = ">=1.10,<1.11"
-bcrypt = ">=3.2,<3.3"
-whitenoise = ">=5.2,<5.3"
-python-dotenv = ">=0.15,<0.16"
-masonite-orm = ">=2.14,<3"
-hashids = ">=1.3,<1.4"
-cryptography = ">=36,<37"
-tldextract = ">=2.2,<2.3"
-hfilesize = ">=0.1"
-dotty_dict = ">=1.3.0,<1.40"
-pyjwt = ">=2.3,<2.5"
-pytest = ">=7,<8"
-werkzeug = ">=2,<3"
-watchdog = ">=2,<3"
-
-[tool.poetry.dev-dependencies]
-pytest = "^7.0.0"
-
-[build-system]
-requires = ["poetry-core"]
-build-backend = "poetry.core.masonry.api"
diff --git a/requirements.txt b/requirements.txt
index 042198d36..3f0d139a5 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -9,9 +9,8 @@ hashids>=1.3,<1.4
 hfilesize>=0.1
 hupper>=1.10,<1.11
 inflection>=0.3,<0.4
-jinja2>=3.0.0,<3.1
+jinja2<3.2
 masonite-orm>=2,<3
-masonite>=4,<5
 pendulum>=2,<3
 pwnedapi
 vonage
@@ -20,7 +19,8 @@ python-dotenv>=0.15,<0.16
 responses
 slackblocks
 tldextract>=2.2,<2.3
-werkzeug>=2,<3
+werkzeug>=2,<3; python_version < '3.8'
+werkzeug>=3,<4; python_version >= '3.8'
 watchdog>=2,<3
 whitenoise>=5.2,<5.3
-pyjwt>=2.3,<2.5
+pyjwt>=2.4,<2.5
diff --git a/setup.py b/setup.py
index 392bc8987..ae8eb6a94 100644
--- a/setup.py
+++ b/setup.py
@@ -42,7 +42,7 @@
         "inflection>=0.3,<0.4",
         "exceptionite>=2.2,<3.0",
         "pendulum>=2,<3",
-        "jinja2<3.1.0",
+        "jinja2<3.2",
         "cleo>=0.8.1,<0.9",
         "hupper>=1.10,<1.11",
         "bcrypt>=3.2,<3.3",
@@ -54,10 +54,11 @@
         "tldextract>=2.2,<2.3",
         "hfilesize>=0.1",
         "dotty_dict>=1.3.0,<1.40",
-        "pyjwt>=2.3,<2.5",
+        "pyjwt>=2.4,<2.5",
         "pytest>=7,<8",
-        "werkzeug>=2,<3",
-        "watchdog>=2,<3",
+        "werkzeug>=2,<3; python_version < '3.8'",
+        "werkzeug>=3,<4; python_version >= '3.8'",
+        "watchdog>=2,<=4",
     ],
     # See https://pypi.python.org/pypi?%3Aaction=list_classifiers
     classifiers=[
@@ -143,8 +144,6 @@
         "masonite.helpers",
         "masonite.input",
         "masonite.loader",
-        "masonite.logging",
-        "masonite.logging.drivers",
         "masonite.mail.drivers",
         "masonite.mail",
         "masonite.middleware.route",
diff --git a/src/masonite/__init__.py b/src/masonite/__init__.py
index 3700e7a2b..caa48dd8f 100644
--- a/src/masonite/__init__.py
+++ b/src/masonite/__init__.py
@@ -1,1 +1,1 @@
-__version__ = "4.19.0"
+__version__ = "4.20.1"
diff --git a/src/masonite/cache/drivers/FileDriver.py b/src/masonite/cache/drivers/FileDriver.py
index 156343e61..4268f12b7 100644
--- a/src/masonite/cache/drivers/FileDriver.py
+++ b/src/masonite/cache/drivers/FileDriver.py
@@ -70,6 +70,8 @@ def remember(self, key, callable):
 
         callable(self)
 
+        return self.get(key)
+
     def forget(self, key):
         try:
             os.remove(os.path.join(self._get_directory(), key))
diff --git a/src/masonite/cache/drivers/MemcacheDriver.py b/src/masonite/cache/drivers/MemcacheDriver.py
index ce21e2349..2aa400b73 100644
--- a/src/masonite/cache/drivers/MemcacheDriver.py
+++ b/src/masonite/cache/drivers/MemcacheDriver.py
@@ -68,6 +68,8 @@ def remember(self, key, callable):
 
         callable(self)
 
+        return self.get(key)
+
     def forget(self, key):
         return self.get_connection().delete(f"{self.get_name()}_cache_{key}")
 
diff --git a/src/masonite/cache/drivers/RedisDriver.py b/src/masonite/cache/drivers/RedisDriver.py
index ec208aa3c..5bc760dec 100644
--- a/src/masonite/cache/drivers/RedisDriver.py
+++ b/src/masonite/cache/drivers/RedisDriver.py
@@ -1,6 +1,7 @@
 import json
 from typing import Any, TYPE_CHECKING
 
+import pendulum as pdlm
 if TYPE_CHECKING:
     from redis import Redis
 
@@ -9,13 +10,17 @@ class RedisDriver:
     def __init__(self, application):
         self.application = application
         self.connection = None
-        self._internal_cache: "dict|None" = None
+        self.options = {}
+        self._internal_cache: dict = None
 
     def set_options(self, options: dict) -> "RedisDriver":
         self.options = options
         return self
 
     def get_connection(self) -> "Redis":
+        if self.connection:
+            return self.connection
+
         try:
             from redis import Redis
         except ImportError:
@@ -23,45 +28,43 @@ def get_connection(self) -> "Redis":
                 "Could not find the 'redis' library. Run 'pip install redis' to fix this."
             )
 
-        if not self.connection:
-            self.connection = Redis(
-                **self.options.get("options", {}),
-                host=self.options.get("host"),
-                port=self.options.get("port"),
-                password=self.options.get("password"),
-                decode_responses=True,
-            )
-
-        # populate the internal cache the first time
-        # the connection is established
-        if self._internal_cache is None and self.connection:
-            self._load_from_store(self.connection)
+        self.connection = Redis(
+            **self.options.get("options", {}),
+            host=self.options.get("host"),
+            port=self.options.get("port"),
+            password=self.options.get("password"),
+            decode_responses=True,
+        )
 
         return self.connection
 
-    def _load_from_store(self, connection: "Redis" = None) -> None:
+    def _load_from_store(self) -> None:
         """
         copy all the "cache" key value pairs for faster access
         """
-        if not connection:
+        if self._internal_cache is not None:
             return
 
-        if self._internal_cache is None:
-            self._internal_cache = {}
+        self._internal_cache = {}
 
         cursor = "0"
         prefix = self.get_cache_namespace()
         while cursor != 0:
-            cursor, keys = connection.scan(
+            cursor, keys = self.get_connection().scan(
                 cursor=cursor, match=prefix + "*", count=100000
             )
             if keys:
-                values = connection.mget(*keys)
+                values = self.get_connection().mget(*keys)
                 store_data = dict(zip(keys, values))
                 for key, value in store_data.items():
                     key = key.replace(prefix, "")
                     value = self.unpack_value(value)
-                    self._internal_cache.setdefault(key, value)
+                    # we dont load the ttl (expiry)
+                    # because there is an O(N) performance hit
+                    self._internal_cache[key] = {
+                        "value": value,
+                        "expires": None,
+                    }
 
     def get_cache_namespace(self) -> str:
         """
@@ -72,37 +75,66 @@ def get_cache_namespace(self) -> str:
         return f"{namespace}cache:"
 
     def add(self, key: str, value: Any = None) -> Any:
-        if not value:
+        if value is None:
             return None
 
         self.put(key, value)
         return value
 
     def get(self, key: str, default: Any = None, **options) -> Any:
-        if default and not self.has(key):
-            self.put(key, default, **options)
-            return default
-
-        return self._internal_cache.get(key)
+        self._load_from_store()
+        if not self.has(key):
+            return default or None
+
+        key_expiry = self._internal_cache[key].get("expires", None)
+        if key_expiry is None:
+            # the ttl value can also provide info on the
+            # existence of the key in the store
+            ttl = self.get_connection().ttl(key)
+            if ttl == -1:
+                # key exists but has no set ttl
+                ttl = self.get_default_timeout()
+            elif ttl == -2:
+                # key not found in store
+                self._internal_cache.pop(key)
+                return default or None
+
+            key_expiry = self._expires_from_ttl(ttl)
+            self._internal_cache[key]["expires"] = key_expiry
+
+        if pdlm.now() > key_expiry:
+            # the key has expired so remove it from the cache
+            self._internal_cache.pop(key)
+            return default or None
+
+        # the key has not yet expired
+        return self._internal_cache.get(key)["value"]
 
     def put(self, key: str, value: Any = None, seconds: int = None, **options) -> Any:
         if not key or value is None:
             return None
 
-        time = self.get_expiration_time(seconds)
-
         store_value = value
         if isinstance(value, (dict, list, tuple)):
             store_value = json.dumps(value)
+        elif isinstance(value, int):
+            store_value = str(value)
 
+        self._load_from_store()
+        key_ttl = seconds or self.get_default_timeout()
         self.get_connection().set(
-            f"{self.get_cache_namespace()}{key}", store_value, ex=time
+            f"{self.get_cache_namespace()}{key}", store_value, ex=key_ttl
         )
-
-        if not self.has(key):
-            self._internal_cache.update({key: value})
+        expires = self._expires_from_ttl(key_ttl)
+        self._internal_cache.update({
+            key: {
+                "value": value,
+                "expires": expires,
+            }
+        })
 
     def has(self, key: str) -> bool:
+        self._load_from_store()
         return key in self._internal_cache
 
     def increment(self, key: str, amount: int = 1) -> int:
@@ -123,24 +155,31 @@ def remember(self, key: str, callable):
 
         callable(self)
 
+        return self.get(key)
+
     def forget(self, key: str) -> None:
+        if not self.has(key):
+            return
         self.get_connection().delete(f"{self.get_cache_namespace()}{key}")
         self._internal_cache.pop(key)
 
     def flush(self) -> None:
-        return self.get_connection().flushall()
+        self.get_connection().flushall()
+        self._internal_cache = None
 
-    def get_expiration_time(self, seconds: int) -> int:
-        if seconds is None:
-            seconds = 31557600 * 10
-
-        return seconds
+    def get_default_timeout(self) -> int:
+        # if unset default timeout of cache vars is 1 month
+        return int(self.options.get("timeout", 60 * 60 * 24 * 30))
 
     def unpack_value(self, value: Any) -> Any:
         value = str(value)
         if value.isdigit():
-            return str(value)
+            return int(value)
+
         try:
             return json.loads(value)
         except json.decoder.JSONDecodeError:
             return value
+
+    def _expires_from_ttl(self, ttl: int) -> pdlm.DateTime:
+        return pdlm.now().add(seconds=ttl)
diff --git a/src/masonite/cookies/Cookie.py b/src/masonite/cookies/Cookie.py
index 4ba03b611..9cb3a540e 100644
--- a/src/masonite/cookies/Cookie.py
+++ b/src/masonite/cookies/Cookie.py
@@ -1,23 +1,19 @@
+from ..configuration import config
+
+
 class Cookie:
-    def __init__(
-        self,
-        name,
-        value,
-        expires=None,
-        http_only=True,
-        path="/",
-        timezone=None,
-        secure=False,
-        samesite="Strict",
-    ):
+    def __init__(self, name, value, **options):
+        self.options = options
+
         self.name = name
         self.value = value
-        self.http_only = http_only
-        self.secure = secure
-        self.expires = expires
-        self.timezone = timezone
-        self.samesite = samesite
-        self.path = path
+        self.http_only = self.__get_option('http_only', True)
+        self.secure = self.__get_option('secure', False)
+        self.expires = self.__get_option('expires', None)
+        self.timezone = self.__get_option('timezone', None)
+        self.samesite = self.__get_option('samesite', 'Strict')
+        self.path = self.__get_option('path', '/')
+        self.encrypt = self.__get_option('encrypt', True)
 
     def render(self):
         response = f"{self.name}={self.value};"
@@ -36,3 +32,16 @@ def render(self):
             response += f"SameSite={self.samesite};"
 
         return response
+
+    def __get_option(self, key: str, default: any):
+        """
+            Get cookie options from config/session.py
+            if option key found in options then it return that
+            if not found in options then it will fetch from config
+            if not found in config then use the default value
+        """
+        if key in self.options:
+            return self.options[key]
+        else:
+            cookie = config('session.drivers.cookie')
+            return cookie[key] if key in cookie else default
diff --git a/src/masonite/drivers/queue/DatabaseDriver.py b/src/masonite/drivers/queue/DatabaseDriver.py
index dba74141d..4b38d3fe2 100644
--- a/src/masonite/drivers/queue/DatabaseDriver.py
+++ b/src/masonite/drivers/queue/DatabaseDriver.py
@@ -89,7 +89,8 @@ def consume(self):
                         getattr(obj, callback)(*args)
 
                     except AttributeError:
-                        obj(*args)
+                        if callable(obj):
+                            obj(*args)
 
                     self.success(
                         f"[{job['id']}][{pendulum.now(tz=self.options.get('tz', 'UTC')).to_datetime_string()}] Job Successfully Processed"
diff --git a/src/masonite/essentials/helpers/hashid.py b/src/masonite/essentials/helpers/hashid.py
index e9ec83a34..d3b82951e 100644
--- a/src/masonite/essentials/helpers/hashid.py
+++ b/src/masonite/essentials/helpers/hashid.py
@@ -3,7 +3,7 @@
 
 def hashid(*values, decode=False, min_length=7):
     hash_class = Hashids(min_length=min_length)
-    if type(values[0]) == dict and decode:
+    if isinstance(values[0], dict) and decode:
         new_dict = {}
         for key, value in values[0].items():
             if hasattr(value, "value"):
@@ -12,7 +12,7 @@ def hashid(*values, decode=False, min_length=7):
             if value and hash_class.decode(value):
                 value = hash_class.decode(value)
 
-            if type(value) == tuple:
+            if isinstance(value, tuple):
                 value = value[0]
             new_dict.update({key: value})
         return new_dict
diff --git a/src/masonite/facades/Log.py b/src/masonite/facades/Log.py
deleted file mode 100644
index 0c5ab7ef3..000000000
--- a/src/masonite/facades/Log.py
+++ /dev/null
@@ -1,5 +0,0 @@
-from .Facade import Facade
-
-
-class Log(metaclass=Facade):
-    key = "logger"
diff --git a/src/masonite/facades/Log.pyi b/src/masonite/facades/Log.pyi
deleted file mode 100644
index 1f6180bf9..000000000
--- a/src/masonite/facades/Log.pyi
+++ /dev/null
@@ -1,24 +0,0 @@
-from typing import TYPE_CHECKING, List
-
-if TYPE_CHECKING:
-    from ..logging.LoggerFactory import LoggerFactory
-
-class Log:
-    """Log facade."""
-
-    def log(level: str, message: str) -> None:
-        """Log a message with the given level."""
-        ...
-    def debug(message: str) -> None: ...
-    def info(message: str) -> None: ...
-    def notice(message: str) -> None: ...
-    def warning(message: str) -> None: ...
-    def error(message: str) -> None: ...
-    def critical(message: str) -> None: ...
-    def alert(message: str) -> None: ...
-    def emergency(message: str) -> None: ...
-    def stack(*channels: List[str]) -> "LoggerFactory":
-        """On-demand stack channels."""
-        ...
-    def channel(channel: str) -> "LoggerFactory": ...
-    def build(driver: str, options: dict = {}) -> "LoggerFactory": ...
diff --git a/src/masonite/facades/__init__.py b/src/masonite/facades/__init__.py
index 213565820..35f4608d2 100644
--- a/src/masonite/facades/__init__.py
+++ b/src/masonite/facades/__init__.py
@@ -17,4 +17,3 @@
 from .Cache import Cache
 from .RateLimiter import RateLimiter
 from .Broadcast import Broadcast
-from .Log import Log
diff --git a/src/masonite/logging/Logger.py b/src/masonite/logging/Logger.py
deleted file mode 100644
index 118756c72..000000000
--- a/src/masonite/logging/Logger.py
+++ /dev/null
@@ -1,126 +0,0 @@
-import logging
-from typing import TYPE_CHECKING, List
-
-if TYPE_CHECKING:
-    from ..foundation import Application
-
-from .LoggerFactory import LoggerFactory
-from ..exceptions import InvalidConfigurationSetup
-
-
-class Logger:
-    # 0       Emergency: system is unusable
-    # 1       Alert: action must be taken immediately
-    # 2       Critical: critical conditions
-    # 3       Error: error conditions
-    # 4       Warning: warning conditions
-    # 5       Notice: normal but significant condition
-    # 6       Informational: informational messages
-    # 7       Debug: debug-level messages
-
-    def __init__(self, application: "Application", options: dict = {}) -> None:
-        self.application = application
-        self.drivers = {}
-        self.options = options
-
-        # configure python logging module to add new levels
-        logging.NOTICE = 25
-        logging.ALERT = 60
-        logging.EMERGENCY = 70
-        new_levels = {
-            "notice": logging.NOTICE,
-            "alert": logging.ALERT,
-            "emergency": logging.EMERGENCY,
-        }
-        for name, levelno in new_levels.items():
-            logging.addLevelName(levelno, name.upper())
-
-        self.levels = {
-            "debug": logging.DEBUG,
-            "info": logging.INFO,
-            "notice": logging.NOTICE,
-            "warning": logging.WARNING,
-            "error": logging.ERROR,
-            "critical": logging.CRITICAL,
-            "alert": logging.ALERT,
-            "emergency": logging.EMERGENCY,
-        }
-
-    def get_default_level(self) -> str:
-        return self.options.get("channels.default.level")
-
-    def get_default_timezone(self) -> str:
-        return self.options.get("channels.default.timezone")
-
-    def get_default_format(self) -> str:
-        return self.options.get("channels.default.format")
-
-    def get_default_date_format(self) -> str:
-        return self.options.get("channels.default.date_format")
-
-    def add_driver(self, name: str, driver):
-        self.drivers.update({name: driver})
-
-    def set_options(self, options: dict) -> "Logger":
-        self.options = options
-        return self
-
-    def get_driver_from_channel(self, channel: str = None, options: dict = {}):
-        if channel is None:
-            channel = self.options.get("channels.default.driver")
-
-        # get driver for channel
-        driver_name = self.options.get(f"channels.{channel}.driver")
-        if not driver_name:
-            raise InvalidConfigurationSetup(
-                f"No config for channel '{channel}' in config/logging.py !"
-            )
-        return self.get_driver(
-            driver_name, channel, options or self.options.get(f"channels.{channel}")
-        )
-
-    def get_driver(self, driver: str, name: str = None, options: dict = {}):
-        return self.drivers[driver](self.application, name or driver, options)
-
-    def get_level_name(self, levelno: int) -> str:
-        for name, no in self.levels.items():
-            if no == levelno:
-                return name
-
-    def log(self, level: str, message: str) -> None:
-        """Log a message with the given level."""
-        return LoggerFactory(self).log(level, message)
-
-    def debug(self, message: str) -> None:
-        return LoggerFactory(self).debug(message)
-
-    def info(self, message: str) -> None:
-        return LoggerFactory(self).info(message)
-
-    def notice(self, message: str) -> None:
-        return LoggerFactory(self).notice(message)
-
-    def warning(self, message: str) -> None:
-        return LoggerFactory(self).warning(message)
-
-    def error(self, message: str) -> None:
-        return LoggerFactory(self).error(message)
-
-    def critical(self, message: str) -> None:
-        return LoggerFactory(self).critical(message)
-
-    def alert(self, message: str) -> None:
-        return LoggerFactory(self).alert(message)
-
-    def emergency(self, message: str) -> None:
-        return LoggerFactory(self).emergency(message)
-
-    def stack(self, *channels: List[str]) -> "LoggerFactory":
-        """On-demand stack channels."""
-        return LoggerFactory(self, driver="stack", options={"channels": channels})
-
-    def channel(self, channel: str) -> "LoggerFactory":
-        return LoggerFactory(self, channel=channel)
-
-    def build(self, driver: str, options: dict = {}) -> "LoggerFactory":
-        return LoggerFactory(self, driver, options=options)
diff --git a/src/masonite/logging/LoggerExceptionsListener.py b/src/masonite/logging/LoggerExceptionsListener.py
deleted file mode 100644
index 526704363..000000000
--- a/src/masonite/logging/LoggerExceptionsListener.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from ..facades import Log
-
-
-class LoggerExceptionsListener:
-    def handle(self, exception_type: str, exception: Exception):
-        Log.error(f"{exception_type}: {exception}")
diff --git a/src/masonite/logging/LoggerFactory.py b/src/masonite/logging/LoggerFactory.py
deleted file mode 100644
index 7320c6bca..000000000
--- a/src/masonite/logging/LoggerFactory.py
+++ /dev/null
@@ -1,51 +0,0 @@
-from typing import TYPE_CHECKING
-
-if TYPE_CHECKING:
-    from .Logger import Logger
-
-
-class LoggerFactory:
-    def __init__(
-        self,
-        logger: "Logger",
-        driver: str = None,
-        channel: str = None,
-        options: dict = {},
-    ) -> None:
-        self.logger = logger
-        self.driver = driver
-        self.channel = channel
-        self.options = options
-
-        if driver and not channel:
-            self.selected_driver = self.logger.get_driver(driver, options=options)
-        # log to default configured channel or given channel
-        else:
-            self.selected_driver = self.logger.get_driver_from_channel(channel, options)
-
-    def log(self, level: str, message: str) -> None:
-        self.selected_driver.log(level, message)
-
-    def debug(self, message: str) -> None:
-        self.selected_driver.debug(message)
-
-    def info(self, message: str) -> None:
-        self.selected_driver.info(message)
-
-    def notice(self, message: str) -> None:
-        self.selected_driver.notice(message)
-
-    def warning(self, message: str) -> None:
-        self.selected_driver.warning(message)
-
-    def error(self, message: str) -> None:
-        self.selected_driver.error(message)
-
-    def critical(self, message: str) -> None:
-        self.selected_driver.critical(message)
-
-    def alert(self, message: str) -> None:
-        self.selected_driver.alert(message)
-
-    def emergency(self, message: str) -> None:
-        self.selected_driver.emergency(message)
diff --git a/src/masonite/logging/LoggingProvider.py b/src/masonite/logging/LoggingProvider.py
deleted file mode 100644
index 2963678c3..000000000
--- a/src/masonite/logging/LoggingProvider.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from ..providers import Provider
-from ..facades import Config
-from .Logger import Logger
-from .drivers import (
-    TerminalDriver,
-    DailyFileDriver,
-    SingleFileDriver,
-    StackDriver,
-    SysLogDriver,
-    SlackDriver,
-)
-from .LoggerExceptionsListener import LoggerExceptionsListener
-
-
-class LoggingProvider(Provider):
-    def __init__(self, application):
-        self.application = application
-
-    def register(self):
-        logger = Logger(self.application).set_options(Config.get("logging"))
-        logger.add_driver("terminal", TerminalDriver)
-        logger.add_driver("daily", DailyFileDriver)
-        logger.add_driver("single", SingleFileDriver)
-        logger.add_driver("stack", StackDriver)
-        logger.add_driver("syslog", SysLogDriver)
-        logger.add_driver("slack", SlackDriver)
-        self.application.bind("logger", logger)
-
-        self.application.make("event").listen(
-            "masonite.exception.*", [LoggerExceptionsListener]
-        )
-
-    def boot(self):
-        pass
diff --git a/src/masonite/logging/__init__.py b/src/masonite/logging/__init__.py
deleted file mode 100644
index 73e3248e1..000000000
--- a/src/masonite/logging/__init__.py
+++ /dev/null
@@ -1,1 +0,0 @@
-from .LoggingProvider import LoggingProvider
diff --git a/src/masonite/logging/drivers/BaseDriver.py b/src/masonite/logging/drivers/BaseDriver.py
deleted file mode 100644
index 6e82ae24d..000000000
--- a/src/masonite/logging/drivers/BaseDriver.py
+++ /dev/null
@@ -1,76 +0,0 @@
-import pendulum
-
-
-class BaseDriver:
-    def __init__(self, application, name, options={}):
-        self.application = application
-        self.options = options
-        self.name = name
-        self.logger = self.application.make("logger")
-        self.levels = self.logger.levels
-
-        # for drivers which are using Python logging module
-        self.logging_logger = None
-        self.logging_handler = None
-
-    def set_options(self, options):
-        self.options = options
-        return self
-
-    def get_min_level(self):
-        return self.levels.get(
-            self.options.get("level", self.logger.get_default_level())
-        )
-
-    def get_format(self):
-        return self.options.get("format", self.logger.get_default_format())
-
-    def should_send(self, level):
-        return self.get_min_level() <= self.levels.get(level)
-
-    def get_time(self):
-        return pendulum.now().in_tz(
-            self.options.get("timezone", self.logger.get_default_timezone())
-        )
-
-    def get_formatted_time(self):
-        date_format = self.options.get(
-            "date_format", self.logger.get_default_date_format()
-        )
-        return self.get_time().format(date_format)
-
-    def set_logger(self):
-        for handler in self.logging_logger.handlers:
-            self.logging_logger.removeHandler(handler)
-        self.logging_logger.addHandler(self.logging_handler)
-        self.logging_logger.setLevel(self.get_min_level())
-
-    def send(self, level, message):
-        raise NotImplementedError()
-
-    def log(self, level, message):
-        return self.send(self.levels.get(level), message)
-
-    def debug(self, message):
-        return self.send(self.levels.get("debug"), message)
-
-    def info(self, message):
-        return self.send(self.levels.get("info"), message)
-
-    def notice(self, message):
-        return self.send(self.levels.get("notice"), message)
-
-    def warning(self, message):
-        return self.send(self.levels.get("warning"), message)
-
-    def error(self, message):
-        return self.send(self.levels.get("error"), message)
-
-    def critical(self, message):
-        return self.send(self.levels.get("critical"), message)
-
-    def alert(self, message):
-        return self.send(self.levels.get("alert"), message)
-
-    def emergency(self, message):
-        return self.send(self.levels.get("emergency"), message)
diff --git a/src/masonite/logging/drivers/DailyFileDriver.py b/src/masonite/logging/drivers/DailyFileDriver.py
deleted file mode 100644
index 315673f1b..000000000
--- a/src/masonite/logging/drivers/DailyFileDriver.py
+++ /dev/null
@@ -1,33 +0,0 @@
-import os
-import logging
-from datetime import datetime
-from logging.handlers import TimedRotatingFileHandler
-from .BaseDriver import BaseDriver
-from ...utils.location import base_path
-
-
-class DailyFileDriver(BaseDriver):
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-
-        file_path = datetime.now().strftime("%Y-%m-%d") + ".log"
-
-        abs_path = base_path(self.options.get("path", "logs/" + file_path))
-        if not os.path.exists(os.path.dirname(abs_path)):
-            os.makedirs(os.path.dirname(abs_path))
-        self.logging_handler = TimedRotatingFileHandler(
-            abs_path,
-            when=self.options.get("when", "d"),
-            interval=self.options.get("days", 7),
-            backupCount=self.options.get("keep", 10),
-        )
-        self.logging_handler.setFormatter(
-            logging.Formatter(self.get_format(), style="{")
-        )
-        self.logging_logger = logging.getLogger(self.name)
-
-    def send(self, level, message):
-        self.set_logger()
-        self.logging_logger.log(
-            level, message, extra={"timestamp": self.get_formatted_time()}
-        )
diff --git a/src/masonite/logging/drivers/SingleFileDriver.py b/src/masonite/logging/drivers/SingleFileDriver.py
deleted file mode 100644
index bf5350e83..000000000
--- a/src/masonite/logging/drivers/SingleFileDriver.py
+++ /dev/null
@@ -1,25 +0,0 @@
-import logging
-import os
-from .BaseDriver import BaseDriver
-from ...utils.location import base_path
-
-
-class SingleFileDriver(BaseDriver):
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-        abs_path = base_path(self.options.get("path", "logs/single.log"))
-        if not os.path.exists(os.path.dirname(abs_path)):
-            os.makedirs(os.path.dirname(abs_path))
-        self.logging_handler = logging.FileHandler(
-            abs_path,
-        )
-        self.logging_handler.setFormatter(
-            logging.Formatter(self.get_format(), style="{")
-        )
-        self.logging_logger = logging.getLogger(self.name)
-
-    def send(self, level, message):
-        self.set_logger()
-        self.logging_logger.log(
-            level, message, extra={"timestamp": self.get_formatted_time()}
-        )
diff --git a/src/masonite/logging/drivers/SlackDriver.py b/src/masonite/logging/drivers/SlackDriver.py
deleted file mode 100644
index 44d4f32fb..000000000
--- a/src/masonite/logging/drivers/SlackDriver.py
+++ /dev/null
@@ -1,133 +0,0 @@
-import logging
-import requests
-from typing import Dict, Any, Optional, Tuple
-
-
-from .BaseDriver import BaseDriver
-
-
-class SlackHandler(logging.Handler):
-    def __init__(self, url: str) -> None:
-        self.url = url
-        super(SlackHandler, self).__init__()
-        return
-
-    def emit(self, record: logging.LogRecord) -> None:
-        """emits message"""
-        msg: str = self.format(record)
-        requests.post(
-            self.url, data=str.encode(msg), headers={"Content-type": "application/json"}
-        )
-        return
-
-
-class SlackFormatter(logging.Formatter):
-    def __init__(self, name: str) -> None:
-        self.name = name
-        super(SlackFormatter, self).__init__()
-        return
-
-    def format(self, record: logging.LogRecord) -> str:
-        import json
-
-        def get_traceback() -> str:
-            """returns traceback"""
-            from traceback import format_exception
-
-            exc_info: Tuple = record.exc_info
-            return "".join(format_exception(*exc_info)) if exc_info else "None"
-
-        def get_color(level: int) -> Optional[str]:
-            """returns appropriate color based on logging level"""
-            colors: Dict[int, Optional[str]] = {
-                0: None,
-                10: "#FF00FF",
-                20: "good",
-                30: "warning",
-                40: "danger",
-                50: "#660000",
-            }
-            return colors[level]
-
-        data: Dict[str, Any] = {
-            "attachments": [
-                {
-                    "color": get_color(record.levelno),
-                    "title": self.name,
-                    "text": record.getMessage(),
-                    "fields": [
-                        {"title": "Module", "value": record.module, "short": True},
-                        {
-                            "title": "Level",
-                            "value": record.levelname.title(),
-                            "short": True,
-                        },
-                        # {"title": "Function", "value": record.funcName, "short": True},
-                        # {"title": "Line Number", "value": record.lineno, "short": True},
-                        # {
-                        #     "title": "Traceback",
-                        #     "value": get_traceback(),
-                        #     "short": False,
-                        # },
-                    ],
-                    "ts": int(record.created),
-                }
-            ]
-        }
-        return json.dumps(data)
-
-
-class SlackDriver(BaseDriver):
-    """Log message to Slack with Slack API."""
-
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-        self.logging_handler = SlackHandler(self.options.get("webhook_url"))
-        self.logging_handler.setFormatter(SlackFormatter(self.name))
-        self.logging_logger = logging.getLogger(self.name)
-
-    def send(self, level, message):
-        self.set_logger()
-        self.logging_logger.log(
-            level, message, extra={"timestamp": self.get_formatted_time()}
-        )
-
-    # def send(self, level, message):
-    #     # here we don't rely on logging module so we have to build
-    #     text = self.get_format()
-    #     # level, message, extra={"timestamp": self.get_formatted_time()}
-    #     payload = {
-    #         "token": self.token,
-    #         "channel": self.find_channel(self.channel),
-    #         "text": message,
-    #         "username": self.username,
-    #         "icon_emoji": self.emoji,
-    #         "as_user": False,
-    #         "reply_broadcast": True,
-    #         "unfurl_links": True,
-    #         "unfurl_media": True,
-    #     }
-    #     response = requests.post(self.send_url, payload).json()
-    #     if not response["ok"]:
-    #         raise Exception("{}. Check Slack API docs.".format(response["error"]))
-
-    # def find_channel(self, name):
-    #     """Calls the Slack API to find the channel name.
-    #     This is so we do not have to specify the channel ID's. Slack requires channel ID's
-    #     to be used.
-    #     Arguments:
-    #         name {string} -- The channel name to find.
-    #     Raises:
-    #         SlackChannelNotFound -- Thrown if the channel name is not found.
-    #     Returns:
-    #         self
-    #     """
-    #     response = requests.post(
-    #         "https://slack.com/api/channels.list", {"token": self.token}
-    #     )
-
-    #     for channel in response.json()["channels"]:
-    #         if channel["name"] == name.split("#")[1]:
-    #             return channel["id"]
-
-    #     raise SlackChannelNotFound("Could not find the {} channel".format(name))
diff --git a/src/masonite/logging/drivers/StackDriver.py b/src/masonite/logging/drivers/StackDriver.py
deleted file mode 100644
index 1c2445b20..000000000
--- a/src/masonite/logging/drivers/StackDriver.py
+++ /dev/null
@@ -1,12 +0,0 @@
-from .BaseDriver import BaseDriver
-
-
-class StackDriver(BaseDriver):
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-
-    def send(self, level, message):
-        logger = self.application.make("logger")
-        level_name = logger.get_level_name(level)
-        for channel in self.options.get("channels", []):
-            logger.channel(channel).log(level_name, message)
diff --git a/src/masonite/logging/drivers/SysLogDriver.py b/src/masonite/logging/drivers/SysLogDriver.py
deleted file mode 100644
index 684baa627..000000000
--- a/src/masonite/logging/drivers/SysLogDriver.py
+++ /dev/null
@@ -1,29 +0,0 @@
-import logging
-from logging.handlers import SysLogHandler, SYSLOG_UDP_PORT
-
-from .BaseDriver import BaseDriver
-
-
-class SysLogDriver(BaseDriver):
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-        if self.options.get("host") and self.options.get("port"):
-            address = (
-                self.options.get("host"),
-                self.options.get("port"),
-            )
-        elif self.options.get("address"):
-            address = self.options.get("address")
-        else:
-            address = ("localhost", SYSLOG_UDP_PORT)
-        self.logging_handler = SysLogHandler(address)
-        self.logging_handler.setFormatter(
-            logging.Formatter(self.get_format(), style="{")
-        )
-        self.logging_logger = logging.getLogger(self.name)
-
-    def send(self, level, message):
-        self.set_logger()
-        self.logging_logger.log(
-            level, message, extra={"timestamp": self.get_formatted_time()}
-        )
diff --git a/src/masonite/logging/drivers/TerminalDriver.py b/src/masonite/logging/drivers/TerminalDriver.py
deleted file mode 100644
index b5ca2a8d1..000000000
--- a/src/masonite/logging/drivers/TerminalDriver.py
+++ /dev/null
@@ -1,52 +0,0 @@
-import logging
-import sys
-
-from .BaseDriver import BaseDriver
-
-
-class ColorFormatter(logging.Formatter):
-    """Logging colored formatter, adapted from https://stackoverflow.com/a/56944256/3638629"""
-
-    magenta = "\x1b[35m"
-    grey = "\x1b[38;21m"
-    blue = "\x1b[38;5;39m"
-    yellow = "\x1b[38;5;226m"
-    red = "\x1b[38;5;196m"
-    bold_red = "\x1b[31;1m"
-    red_fg_yellow_bg = "\x1b[31;103m"
-    white_fg_red_bg = "\x1b[37;41m"
-    reset = "\x1b[0m"
-
-    def __init__(self, fmt=None, datefmt=None, style="%"):
-        super().__init__(fmt, datefmt, style)
-        self.fmt = fmt
-        self.style = style
-        self.FORMATS = {
-            logging.DEBUG: self.magenta + self.fmt + self.reset,
-            logging.INFO: self.grey + self.fmt + self.reset,
-            logging.NOTICE: self.blue + self.fmt + self.reset,
-            logging.WARNING: self.yellow + self.fmt + self.reset,
-            logging.ERROR: self.red + self.fmt + self.reset,
-            logging.CRITICAL: self.bold_red + self.fmt + self.reset,
-            logging.ALERT: self.red_fg_yellow_bg + self.fmt + self.reset,
-            logging.EMERGENCY: self.white_fg_red_bg + self.fmt + self.reset,
-        }
-
-    def format(self, record):
-        log_fmt = self.FORMATS.get(record.levelno)
-        formatter = logging.Formatter(log_fmt, datefmt=self.datefmt, style=self.style)
-        return formatter.format(record)
-
-
-class TerminalDriver(BaseDriver):
-    def __init__(self, application, name, options):
-        super().__init__(application, name, options)
-        self.logging_handler = logging.StreamHandler(sys.stdout)
-        self.logging_handler.setFormatter(ColorFormatter(self.get_format(), style="{"))
-        self.logging_logger = logging.getLogger(name)
-
-    def send(self, level, message):
-        self.set_logger()
-        self.logging_logger.log(
-            level, message, extra={"timestamp": self.get_formatted_time()}
-        )
diff --git a/src/masonite/logging/drivers/__init__.py b/src/masonite/logging/drivers/__init__.py
deleted file mode 100644
index 15040fdf6..000000000
--- a/src/masonite/logging/drivers/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from .TerminalDriver import TerminalDriver
-from .DailyFileDriver import DailyFileDriver
-from .SingleFileDriver import SingleFileDriver
-from .StackDriver import StackDriver
-from .SysLogDriver import SysLogDriver
-from .SlackDriver import SlackDriver
diff --git a/src/masonite/middleware/route/EncryptCookies.py b/src/masonite/middleware/route/EncryptCookies.py
index 6995d31e7..8234e50eb 100644
--- a/src/masonite/middleware/route/EncryptCookies.py
+++ b/src/masonite/middleware/route/EncryptCookies.py
@@ -4,6 +4,9 @@
 class EncryptCookies:
     def before(self, request, response):
         for _, cookie in request.cookie_jar.all().items():
+            if not cookie.encrypt:
+                continue
+
             try:
                 cookie.value = request.app.make("sign").unsign(cookie.value)
             except InvalidToken:
@@ -13,6 +16,9 @@ def before(self, request, response):
 
     def after(self, request, response):
         for _, cookie in response.cookie_jar.all().items():
+            if not cookie.encrypt:
+                continue
+
             try:
                 cookie.value = request.app.make("sign").sign(cookie.value)
             except InvalidToken:
diff --git a/src/masonite/middleware/route/SessionMiddleware.py b/src/masonite/middleware/route/SessionMiddleware.py
index 8d9a0b415..5e0a02afc 100644
--- a/src/masonite/middleware/route/SessionMiddleware.py
+++ b/src/masonite/middleware/route/SessionMiddleware.py
@@ -16,8 +16,15 @@ def before(self, request, response):
         request.app.make("response").with_success = self.with_success
         request.app.make("request").session = Session
 
-        # TODO: Remove in Masonite 5
-        request.app.make("view").share({"bag": MessageBag(Session.get("errors") or {}).helper})
+        # TODO: Check this in Masonite 5
+        # errors are stored in session flash so 'getting' them
+        # actually clears them out of the session
+        errors = Session.get("errors")
+        request.app.make("view").share({"errors": MessageBag(errors or {}).helper})
+        # if any errors then re-add them to the session
+        if errors:
+            Session.flash("errors", errors)
+
         return request
 
     def after(self, request, _):
diff --git a/src/masonite/request/request.py b/src/masonite/request/request.py
index 6636650da..6a38940f1 100644
--- a/src/masonite/request/request.py
+++ b/src/masonite/request/request.py
@@ -113,9 +113,9 @@ def only(self, *inputs: str) -> dict:
         """Pass arguments as string arguments such as request.only("arg1", "arg2") to get back a dictionary of only those inputs."""
         return self.input_bag.only(*inputs)
 
-    def old(self, key: str):
+    def old(self, key: str, default: str = "") -> str:
         """Get value from session for the given key."""
-        return old_helper(key)
+        return old_helper(key, default)
 
     def is_not_safe(self) -> bool:
         """Check if the current request is considered 'safe', meaning that the request method is
diff --git a/src/masonite/routes/Route.py b/src/masonite/routes/Route.py
index 5ee2bdb15..252727d88 100644
--- a/src/masonite/routes/Route.py
+++ b/src/masonite/routes/Route.py
@@ -157,7 +157,7 @@ def group(self, *routes, **options):
                 route.compile_route_to_regex()
 
             if options.get("name"):
-                route._name = options.get("name") + route._name
+                route._name = options.get("name", "") + (route._name or "")
 
             if options.get("domain"):
                 route.domain(options.get("domain"))
diff --git a/src/masonite/sessions/helpers.py b/src/masonite/sessions/helpers.py
index 494984331..a9f04295b 100644
--- a/src/masonite/sessions/helpers.py
+++ b/src/masonite/sessions/helpers.py
@@ -1,6 +1,6 @@
 from ..facades import Session
 
 
-def old(key: str) -> str:
-    """Helper used to get value from session for the given key."""
-    return Session.get(key) or ""
+def old(key: str, default: str = "") -> str:
+    """Helper used to get value from session for the given key, with a default option."""
+    return Session.get(key) or default
diff --git a/src/masonite/stubs/controllers/Controller.py b/src/masonite/stubs/controllers/Controller.py
index a42e6e35b..92af8ebd8 100644
--- a/src/masonite/stubs/controllers/Controller.py
+++ b/src/masonite/stubs/controllers/Controller.py
@@ -4,4 +4,4 @@
 
 class __class__(Controller):
     def show(self, view: View):
-        return view.render("")
+        return view.render("welcome")
diff --git a/src/masonite/utils/str.py b/src/masonite/utils/str.py
index 39a80d9ee..02b6513d3 100644
--- a/src/masonite/utils/str.py
+++ b/src/masonite/utils/str.py
@@ -80,7 +80,8 @@ def add_query_params(url: str, query_params: dict) -> str:
     """Add query params dict to a given url (which can already contain some query parameters)."""
     path_result = parse.urlsplit(url)
 
-    base_url = path_result.path
+    base_url = f"{path_result.scheme}://{path_result.hostname}" if path_result.hostname else ""
+    base_path = path_result.path
 
     # parse existing query parameters if any
     existing_query_params = dict(parse.parse_qsl(path_result.query))
@@ -88,9 +89,9 @@ def add_query_params(url: str, query_params: dict) -> str:
 
     # add query parameters to url if any
     if all_query_params:
-        base_url += "?" + parse.urlencode(all_query_params)
+        base_path += "?" + parse.urlencode(all_query_params)
 
-    return base_url
+    return f"{base_url}{base_path}"
 
 
 def get_controller_name(controller: "str|Any") -> str:
diff --git a/src/masonite/utils/structures.py b/src/masonite/utils/structures.py
index 69dbbfe0c..011a5a226 100644
--- a/src/masonite/utils/structures.py
+++ b/src/masonite/utils/structures.py
@@ -1,4 +1,5 @@
 """Helpers for multiple data structures"""
+
 import importlib
 from importlib.abc import Loader
 from dotty_dict import dotty
@@ -25,10 +26,13 @@ def load(path, object_name=None, default=None, raise_exception=False):
     try:
         module = importlib.import_module(module_path)
     except Exception as e:
+        error_message = (
+            f"'{module_path}' not found OR error when importing this module: {str(e)}"
+        )
+        print("Warning: " + error_message)
+
         if raise_exception:
-            raise LoaderNotFound(
-                f"'{module_path}' not found OR error when importing this module: {str(e)}"
-            )
+            raise LoaderNotFound(error_message)
         return None
 
     if object_name is None:
diff --git a/src/masonite/validation/Validator.py b/src/masonite/validation/Validator.py
index 940bb8e3d..c3de22848 100644
--- a/src/masonite/validation/Validator.py
+++ b/src/masonite/validation/Validator.py
@@ -759,10 +759,16 @@ def passes(self, attribute, key, dictionary):
                 all_clear = False
 
         if self.special != 0:
-            special_chars = "[^A-Za-z0-9]"
+            # custom specials are just a string of characters
+            # and may contain regex meta chars.
+            # so we search for them differently
             if self.special_chars:
-                special_chars = f"[{self.special_chars}]"
-            if len(re.findall(special_chars, attribute)) < self.special:
+                special_count = sum(attribute.count(c) for c in self.special_chars)
+            else:
+                std_specials = "[^A-Za-z0-9]"
+                special_count = len(re.findall(std_specials, attribute))
+
+            if special_count < self.special:
                 self.special_check = False
                 all_clear = False
 


Test patch:
diff --git a/tests/core/exceptions/test_exception_handler.py b/tests/core/exceptions/test_exception_handler.py
index 23cd12d3f..6dac2218a 100644
--- a/tests/core/exceptions/test_exception_handler.py
+++ b/tests/core/exceptions/test_exception_handler.py
@@ -2,7 +2,6 @@
 from src.masonite.routes import Route
 from src.masonite.controllers import Controller
 from src.masonite.exceptions import RouteNotFoundException
-from src.masonite.facades import Config
 
 
 class TestController(Controller):
@@ -79,12 +78,9 @@ def test_raising_http_exception_renders_404_error_page(self):
             self.get("/http").assertNotFound().assertContains("Page Not Found")
 
     def test_raising_exception_does_not_output_stack_trace_to_console(self):
-        # disable logging
-        Config.set("logging.channels.default.level", "critical")
         with self.debugMode(False):
             self.get("/simple")
             self.assertConsoleEmpty()
-        Config.set("logging.channels.default.level", "info")
 
     def test_accepting_json_returns_500_error_payload(self):
         with self.debugMode(False):
diff --git a/tests/core/middleware/test_encrypt_cookies.py b/tests/core/middleware/test_encrypt_cookies.py
index 2f9014e4b..909ac14d0 100644
--- a/tests/core/middleware/test_encrypt_cookies.py
+++ b/tests/core/middleware/test_encrypt_cookies.py
@@ -15,3 +15,16 @@ def test_encrypts_cookies(self):
         response.cookie("test", "value")
         EncryptCookies().after(request, response)
         self.assertNotEqual(response.cookie("test"), "value")
+
+    def test_encrypt_cookies_opt_out(self):
+        request = self.make_request(
+            {"HTTP_COOKIE": f"test_key=test value"}
+        )
+
+        response = self.make_response()
+        EncryptCookies().before(request, None)
+        self.assertEqual(request.cookie("test_key", encrypt=False), "test value")
+
+        response.cookie("test", "value")
+        EncryptCookies().after(request, response)
+        self.assertNotEqual(response.cookie("test_key", encrypt=False), "test value")
diff --git a/tests/core/request/test_http_requests.py b/tests/core/request/test_http_requests.py
index cb3d74b5c..0801f31bc 100644
--- a/tests/core/request/test_http_requests.py
+++ b/tests/core/request/test_http_requests.py
@@ -47,7 +47,7 @@ def test_server_error_with_debug_on(self):
     def test_old_helper(self):
         self.get("/test-with-input", {"name": "Sam"})
         assert self.application.make("request").old("name") == "Sam"
-        assert self.application.make("request").old("wrong-input") == ""
+        assert self.application.make("request").old("wrong-input", "default") == "default"
 
     def test_get_route(self):
         self.get("/")
diff --git a/tests/core/response/test_response_helpers.py b/tests/core/response/test_response_helpers.py
index a652d903a..76b066505 100644
--- a/tests/core/response/test_response_helpers.py
+++ b/tests/core/response/test_response_helpers.py
@@ -1,5 +1,6 @@
-from tests import TestCase
+from src.masonite.middleware import SessionMiddleware
 from src.masonite.routes import Route
+from tests import TestCase
 
 
 class TestResponseHelpers(TestCase):
@@ -17,3 +18,36 @@ def test_with_errors(self):
         self.get("/test-with-errors").assertSessionHasErrors().assertSessionHasErrors(
             ["email"]
         )
+
+
+class TestResponseWithMiddleware(TestCase):
+    def setUp(self):
+        super().setUp()
+        self.application.make("middleware").add(
+            {
+                "web": SessionMiddleware,
+            }
+        )
+        self.addRoutes(
+            Route.get("/test-with-errors", "WelcomeController@with_errors").middleware(
+                "web"
+            ),
+            Route.get(
+                "/test-with-input", "WelcomeController@form_with_input"
+            ).middleware("web"),
+        )
+
+    def test_with_input(self):
+        (
+            self.get("/test-with-input", {"name": "Sam"})
+            .assertSessionHas("name", "Sam")
+            .assertSessionHasNoErrors()
+        )
+
+    def test_with_errors(self):
+        (
+            self.get("/test-with-errors")
+            .assertSessionHasErrors()
+            .assertSessionHasErrors(["email"])
+            .assertSessionHasNoErrors()
+        )
diff --git a/tests/core/response/test_response_redirections.py b/tests/core/response/test_response_redirections.py
index 114251819..ef00b8963 100644
--- a/tests/core/response/test_response_redirections.py
+++ b/tests/core/response/test_response_redirections.py
@@ -34,3 +34,13 @@ def test_redirect_to_url(self):
         self.assertEqual(
             self.response.header_bag.get("Location").value, "/login?key=value"
         )
+
+    def test_redirect_to_external_url(self):
+        self.response.redirect(url="https://google.cl/login")
+        self.assertEqual(self.response.get_status(), 302)
+        self.assertEqual(self.response.header_bag.get("Location").value, "https://google.cl/login")
+
+        self.response.redirect(url="https://google.cl/login", query_params={"key": "value"})
+        self.assertEqual(
+            self.response.header_bag.get("Location").value, "https://google.cl/login?key=value"
+        )
\ No newline at end of file
diff --git a/tests/features/cache/test_file_cache.py b/tests/features/cache/test_file_cache.py
index adb308235..26a277813 100644
--- a/tests/features/cache/test_file_cache.py
+++ b/tests/features/cache/test_file_cache.py
@@ -42,8 +42,8 @@ def test_forget(self):
         self.assertEqual(self.driver.get("forget"), None)
 
     def test_remember(self):
-        self.driver.remember("remember", lambda cache: (cache.put("remember", "1", 10)))
-        self.assertEqual(self.driver.get("remember"), "1")
+        data_to_remember = self.driver.remember("remember", lambda cache: (cache.put("remember", "1", 10)))
+        self.assertEqual(data_to_remember, "1")
 
     def test_remember_datatypes(self):
         self.driver.remember(
@@ -60,7 +60,7 @@ def test_flush(self):
         self.driver.flush()
         self.assertIsNone(self.driver.get("dic"))
 
-    def test_get_can_forget_expired(self): 
+    def test_get_can_forget_expired(self):
         self.driver.put("forget_expired", "1", 1)
         time.sleep(1)
         self.assertEqual(self.driver.get("forget_expired"), None)
diff --git a/tests/features/cache/test_redis_cache.py b/tests/features/cache/test_redis_cache.py
index 61e69c2ab..696699f6a 100644
--- a/tests/features/cache/test_redis_cache.py
+++ b/tests/features/cache/test_redis_cache.py
@@ -11,7 +11,7 @@ def setUp(self):
         self.application.make("cache")
         self.driver = self.application.make("cache").store("redis")
 
-    def test_can_add_file_driver(self):
+    def test_can_add_redis_driver(self):
         self.assertEqual(self.driver.add("add_key", "value"), "value")
 
     def test_can_get_driver(self):
@@ -23,9 +23,13 @@ def test_can_increment(self):
         self.driver.put("count", "1")
         self.assertEqual(self.driver.get("count"), "1")
         self.driver.increment("count")
-        self.assertEqual(self.driver.get("count"), "2")
+        self.assertEqual(self.driver.get("count"), 2)
+        self.driver.increment("count", 3)
+        self.assertEqual(self.driver.get("count"), 5)
         self.driver.decrement("count")
-        self.assertEqual(self.driver.get("count"), "1")
+        self.assertEqual(self.driver.get("count"), 4)
+        self.driver.decrement("count", 2)
+        self.assertEqual(self.driver.get("count"), 2)
 
     def test_will_not_get_expired(self):
         self.driver.put("expire", "1", 1)
diff --git a/tests/features/logging/test_logger.py b/tests/features/logging/test_logger.py
deleted file mode 100644
index 9bcb29485..000000000
--- a/tests/features/logging/test_logger.py
+++ /dev/null
@@ -1,71 +0,0 @@
-import pendulum
-import tempfile
-
-from tests import TestCase
-from src.masonite.facades import Log, Config
-
-
-class TestLogger(TestCase):
-    def setUp(self):
-        super().setUp()
-        self.timestamp = pendulum.datetime(2022, 10, 10, 9, 0, 0)
-        self.fakeTime(self.timestamp)
-
-        self.log_file_path = Config.get("logging.channels.single.path")
-        self.log_file = tempfile.NamedTemporaryFile(mode="w+")
-        Config.set("logging.channels.single.path", self.log_file.name)
-
-    def tearDown(self):
-        super().tearDown()
-        self.restoreTime()
-        Config.set("logging.channels.single.path", self.log_file)
-
-    def test_terminal_logging(self):
-        Log.error("message")
-        self.assertConsoleOutputContains("2022-10-10 09:00:00 - ERROR: message")
-
-    def test_terminal_logging_with_other_level(self):
-        Log.info("other message")
-        self.assertConsoleOutputContains("2022-10-10 09:00:00 - INFO: other message")
-
-    def test_that_messages_under_min_level_are_not_logged(self):
-        Log.debug("other message")
-        self.assertConsoleEmpty()
-
-    def test_timezone_can_be_changed(self):
-        old_timezone = Config.get("logging.channels.default.timezone")
-        Config.set("logging.channels.default.timezone", "Europe/Paris")
-
-        Log.info("other message")
-        timestamp_in_tz = self.timestamp.in_tz("Europe/Paris").format(
-            "YYYY-MM-DD HH:mm:ss"
-        )
-        self.assertConsoleOutputContains(f"{timestamp_in_tz} - INFO: other message")
-
-        Config.set("logging.channels.default.timezone", old_timezone)
-
-    def test_stack_channels(self):
-        Log.stack("single", "console").warning("message")
-        # check logged in file
-        self.assertEqual(
-            str(self.log_file.readline()),
-            "2022-10-10 09:00:00 - WARNING: message\n",
-        )
-        # check logged in console
-        self.assertConsoleOutputContains("2022-10-10 09:00:00 - WARNING: message")
-
-    def test_file_logging(self):
-        Log.channel("single").warning("Some warning")
-        self.assertEqual(
-            str(self.log_file.readline()),
-            "2022-10-10 09:00:00 - WARNING: Some warning\n",
-        )
-
-    def test_on_demand_channel(self):
-        Log.build(
-            "daily", {"path": self.log_file.name, "format": "{message}"}
-        ).critical("Some message")
-        self.assertEqual(
-            self.log_file.readline(),
-            "Some message\n",
-        )
diff --git a/tests/features/validation/test_request_validation.py b/tests/features/validation/test_request_validation.py
index 02259c615..3af415aa5 100644
--- a/tests/features/validation/test_request_validation.py
+++ b/tests/features/validation/test_request_validation.py
@@ -1,5 +1,5 @@
 from tests import TestCase
-from masonite.validation import email, isnt, is_in, numeric
+from src.masonite.validation import email, isnt, is_in, numeric
 from src.masonite.validation import Validator
 
 
diff --git a/tests/features/validation/test_validation.py b/tests/features/validation/test_validation.py
index c43d5cf6a..7737bab06 100644
--- a/tests/features/validation/test_validation.py
+++ b/tests/features/validation/test_validation.py
@@ -1677,14 +1677,26 @@ def test_strong(self):
         # test custom special characters
         validate = Validator().validate(
             {
-                "password": "secret&-",
+                "password": "$e]cret&-",
             },
-            strong(["password"], length=5, uppercase=0, special=2, special_chars="*&^", numbers=0, lowercase=4),
+            strong(
+                ["password"],
+                length=5,
+                uppercase=0,
+                special=4,
+                special_chars="^$*&()[]",
+                numbers=0,
+                lowercase=4,
+            ),
         )
 
         self.assertEqual(
             validate.all(),
-            {"password": ["The password field must contain at least 2 of these characters: '*&^'"]},
+            {
+                "password": [
+                    "The password field must contain at least 4 of these characters: '^$*&()[]'"
+                ]
+            },
         )
 
         validate = Validator().validate(
diff --git a/tests/integrations/config/logging.py b/tests/integrations/config/logging.py
deleted file mode 100644
index 7868e14e6..000000000
--- a/tests/integrations/config/logging.py
+++ /dev/null
@@ -1,34 +0,0 @@
-CHANNELS = {
-    "default": {
-        "driver": "console",
-        "level": "info",
-        "timezone": "UTC",
-        "format": "{timestamp} - {levelname}: {message}",
-        "date_format": "YYYY-MM-DD HH:mm:ss",
-    },
-    "console": {
-        "driver": "terminal",
-        # "format": "> {timestamp} - {levelname}: {message}",
-        # "date_format": "YYYY-MM-DD HH:mm:ss",
-    },
-    "single": {
-        "driver": "single",
-        "path": "logs/masonite.log",
-    },
-    "daily": {
-        "driver": "daily",
-        "days": 7,
-        "keep": 10,
-    },
-    "all": {"driver": "stack", "channels": ["single", "daily", "console"]},
-    "syslog": {"driver": "syslog", "address": "/var/log/system.log"},
-    "papertrail": {
-        "driver": "syslog",
-        "host": "logs.papertrailapp.com",
-        "port": None,  # specify here the port as an integer
-    },
-    "slack": {
-        "driver": "slack",
-        "webhook_url": "",
-    },
-}
diff --git a/tests/integrations/config/providers.py b/tests/integrations/config/providers.py
index 7ed36ff9e..5905dcce2 100644
--- a/tests/integrations/config/providers.py
+++ b/tests/integrations/config/providers.py
@@ -24,7 +24,6 @@
 from src.masonite.notification.providers import NotificationProvider
 from src.masonite.validation.providers.ValidationProvider import ValidationProvider
 from src.masonite.api.providers import ApiProvider
-from src.masonite.logging import LoggingProvider
 from ..test_package import MyTestPackageProvider
 
 from tests.integrations.providers import AppProvider
@@ -54,5 +53,4 @@
     AppProvider,
     ORMProvider,
     ApiProvider,
-    LoggingProvider,
 ]
diff --git a/tests/routes/test_routes.py b/tests/routes/test_routes.py
index 2b6bd3d77..10fae589e 100644
--- a/tests/routes/test_routes.py
+++ b/tests/routes/test_routes.py
@@ -132,12 +132,14 @@ def test_group_naming(self):
             Route.group(
                 Route.get("/group", "WelcomeController@show").name(".index"),
                 Route.post("/login", "WelcomeController@show").name(".index"),
+                Route.post("/login", "WelcomeController@show"),
                 prefix="/testing",
                 name="dashboard",
             )
         )
 
         route = router.find_by_name("dashboard.index")
+        route = router.find_by_name("dashboard")
         self.assertTrue(route)
 
     def test_compile_year(self):