+
\ No newline at end of file
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..f8136b0
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,19 @@
+[tool.poetry]
+name = "python-template"
+version = "0.1.0"
+description = ""
+authors = ["Your Name "]
+
+[tool.poetry.dependencies]
+python = ">=3.8.0,<3.9"
+numpy = "^1.22.2"
+replit = "^3.2.4"
+requests = "^2.27.1"
+discord = "^1.7.3"
+Flask = "^2.0.3"
+
+[tool.poetry.dev-dependencies]
+
+[build-system]
+requires = ["poetry-core>=1.0.0"]
+build-backend = "poetry.core.masonry.api"
\ No newline at end of file
diff --git a/replit.nix b/replit.nix
new file mode 100644
index 0000000..4f1aec1
--- /dev/null
+++ b/replit.nix
@@ -0,0 +1,18 @@
+{ pkgs }: {
+ deps = [
+ pkgs.python38Full
+ ];
+ env = {
+ PYTHON_LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath [
+ # Neded for pandas / numpy
+ pkgs.stdenv.cc.cc.lib
+ pkgs.zlib
+ # Needed for pygame
+ pkgs.glib
+ # Needed for matplotlib
+ pkgs.xorg.libX11
+ ];
+ PYTHONBIN = "${pkgs.python38Full}/bin/python3.8";
+ LANG = "en_US.UTF-8";
+ };
+}
\ No newline at end of file
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/INSTALLER b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/METADATA b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/METADATA
new file mode 100644
index 0000000..d617f5f
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/METADATA
@@ -0,0 +1,125 @@
+Metadata-Version: 2.1
+Name: Flask
+Version: 2.0.3
+Summary: A simple framework for building complex web applications.
+Home-page: https://palletsprojects.com/p/flask
+Author: Armin Ronacher
+Author-email: armin.ronacher@active-4.com
+Maintainer: Pallets
+Maintainer-email: contact@palletsprojects.com
+License: BSD-3-Clause
+Project-URL: Donate, https://palletsprojects.com/donate
+Project-URL: Documentation, https://flask.palletsprojects.com/
+Project-URL: Changes, https://flask.palletsprojects.com/changes/
+Project-URL: Source Code, https://github.com/pallets/flask/
+Project-URL: Issue Tracker, https://github.com/pallets/flask/issues/
+Project-URL: Twitter, https://twitter.com/PalletsTeam
+Project-URL: Chat, https://discord.gg/pallets
+Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Environment :: Web Environment
+Classifier: Framework :: Flask
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: BSD License
+Classifier: Operating System :: OS Independent
+Classifier: Programming Language :: Python
+Classifier: Topic :: Internet :: WWW/HTTP :: Dynamic Content
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI
+Classifier: Topic :: Internet :: WWW/HTTP :: WSGI :: Application
+Classifier: Topic :: Software Development :: Libraries :: Application Frameworks
+Requires-Python: >=3.6
+Description-Content-Type: text/x-rst
+License-File: LICENSE.rst
+Requires-Dist: Werkzeug (>=2.0)
+Requires-Dist: Jinja2 (>=3.0)
+Requires-Dist: itsdangerous (>=2.0)
+Requires-Dist: click (>=7.1.2)
+Provides-Extra: async
+Requires-Dist: asgiref (>=3.2) ; extra == 'async'
+Provides-Extra: dotenv
+Requires-Dist: python-dotenv ; extra == 'dotenv'
+
+Flask
+=====
+
+Flask is a lightweight `WSGI`_ web application framework. It is designed
+to make getting started quick and easy, with the ability to scale up to
+complex applications. It began as a simple wrapper around `Werkzeug`_
+and `Jinja`_ and has become one of the most popular Python web
+application frameworks.
+
+Flask offers suggestions, but doesn't enforce any dependencies or
+project layout. It is up to the developer to choose the tools and
+libraries they want to use. There are many extensions provided by the
+community that make adding new functionality easy.
+
+.. _WSGI: https://wsgi.readthedocs.io/
+.. _Werkzeug: https://werkzeug.palletsprojects.com/
+.. _Jinja: https://jinja.palletsprojects.com/
+
+
+Installing
+----------
+
+Install and update using `pip`_:
+
+.. code-block:: text
+
+ $ pip install -U Flask
+
+.. _pip: https://pip.pypa.io/en/stable/getting-started/
+
+
+A Simple Example
+----------------
+
+.. code-block:: python
+
+ # save this as app.py
+ from flask import Flask
+
+ app = Flask(__name__)
+
+ @app.route("/")
+ def hello():
+ return "Hello, World!"
+
+.. code-block:: text
+
+ $ flask run
+ * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
+
+
+Contributing
+------------
+
+For guidance on setting up a development environment and how to make a
+contribution to Flask, see the `contributing guidelines`_.
+
+.. _contributing guidelines: https://github.com/pallets/flask/blob/main/CONTRIBUTING.rst
+
+
+Donate
+------
+
+The Pallets organization develops and supports Flask and the libraries
+it uses. In order to grow the community of contributors and users, and
+allow the maintainers to devote more time to the projects, `please
+donate today`_.
+
+.. _please donate today: https://palletsprojects.com/donate
+
+
+Links
+-----
+
+- Documentation: https://flask.palletsprojects.com/
+- Changes: https://flask.palletsprojects.com/changes/
+- PyPI Releases: https://pypi.org/project/Flask/
+- Source Code: https://github.com/pallets/flask/
+- Issue Tracker: https://github.com/pallets/flask/issues/
+- Website: https://palletsprojects.com/p/flask/
+- Twitter: https://twitter.com/PalletsTeam
+- Chat: https://discord.gg/pallets
+
+
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/RECORD b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/RECORD
new file mode 100644
index 0000000..4ecc093
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/RECORD
@@ -0,0 +1,53 @@
+../../../bin/flask,sha256=QYgeCqTAn_3fWCfQnj5HXC9fs-blcYQh2_94j-UlPoE,227
+Flask-2.0.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Flask-2.0.3.dist-info/LICENSE.rst,sha256=SJqOEQhQntmKN7uYPhHg9-HTHwvY-Zp5yESOf_N9B-o,1475
+Flask-2.0.3.dist-info/METADATA,sha256=jK50YtxZfODLQP_GF1sNH6dOXRCI5bBLrAc7pWQwuXw,3839
+Flask-2.0.3.dist-info/RECORD,,
+Flask-2.0.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+Flask-2.0.3.dist-info/WHEEL,sha256=G16H4A3IeoQmnOrYV4ueZGKSjhipXx8zc8nu9FGlvMA,92
+Flask-2.0.3.dist-info/direct_url.json,sha256=vezzzEhDxsJLTfWoszWXVMCAfp5oc5RJ5iinbGUHLpU,173
+Flask-2.0.3.dist-info/entry_points.txt,sha256=s3MqQpduU25y4dq3ftBYD6bMVdVnbMpZP-sUNw0zw0k,41
+Flask-2.0.3.dist-info/top_level.txt,sha256=dvi65F6AeGWVU0TBpYiC04yM60-FX1gJFkK31IKQr5c,6
+flask/__init__.py,sha256=ubQS5Xt6LMjPSwGO3Jksi5yx8AyuU0vT_VdHjt0j97A,2251
+flask/__main__.py,sha256=bYt9eEaoRQWdejEHFD8REx9jxVEdZptECFsV7F49Ink,30
+flask/__pycache__/__init__.cpython-38.pyc,,
+flask/__pycache__/__main__.cpython-38.pyc,,
+flask/__pycache__/app.cpython-38.pyc,,
+flask/__pycache__/blueprints.cpython-38.pyc,,
+flask/__pycache__/cli.cpython-38.pyc,,
+flask/__pycache__/config.cpython-38.pyc,,
+flask/__pycache__/ctx.cpython-38.pyc,,
+flask/__pycache__/debughelpers.cpython-38.pyc,,
+flask/__pycache__/globals.cpython-38.pyc,,
+flask/__pycache__/helpers.cpython-38.pyc,,
+flask/__pycache__/logging.cpython-38.pyc,,
+flask/__pycache__/scaffold.cpython-38.pyc,,
+flask/__pycache__/sessions.cpython-38.pyc,,
+flask/__pycache__/signals.cpython-38.pyc,,
+flask/__pycache__/templating.cpython-38.pyc,,
+flask/__pycache__/testing.cpython-38.pyc,,
+flask/__pycache__/typing.cpython-38.pyc,,
+flask/__pycache__/views.cpython-38.pyc,,
+flask/__pycache__/wrappers.cpython-38.pyc,,
+flask/app.py,sha256=ectBbi9hGmVHAse5TNcFQZIDRkDAxYUAnLgfuKD0Xws,81975
+flask/blueprints.py,sha256=AkAVXZ_MMkjwjklzCAMdBNowTiM0wVQPynnUnXjTL2M,23781
+flask/cli.py,sha256=9v7FDIwWZ3QZsR6ka-qMYzMxSThfmQ4PEA4lkI38R6c,32287
+flask/config.py,sha256=70Uyjh1Jzb9MfTCT7NDhuZWAzyIEu-TIyk6-22MP3zQ,11285
+flask/ctx.py,sha256=Rmw5VOFQdbomLoCQPbU_0FbQkuB56CtpnQVU4yzXYB8,17589
+flask/debughelpers.py,sha256=W82-xrRmodjopBngI9roYH-q08EbQwN2HEGfDAi6SA0,6184
+flask/globals.py,sha256=cWd-R2hUH3VqPhnmQNww892tQS6Yjqg_wg8UvW1M7NM,1723
+flask/helpers.py,sha256=kstplLDtD0Isobilp87Lfmwq1tk2spnHjUf_O5-EhoE,30618
+flask/json/__init__.py,sha256=_YIqOsy8YOSyoLbplFtNcKvF5kwNKenmJ87Ub2Myc0k,12104
+flask/json/__pycache__/__init__.cpython-38.pyc,,
+flask/json/__pycache__/tag.cpython-38.pyc,,
+flask/json/tag.py,sha256=fys3HBLssWHuMAIJuTcf2K0bCtosePBKXIWASZEEjnU,8857
+flask/logging.py,sha256=1o_hirVGqdj7SBdETnhX7IAjklG89RXlrwz_2CjzQQE,2273
+flask/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+flask/scaffold.py,sha256=fM9mRy7QBh9fhJ0VTogVx900dDa5oxz8FOw6OK5F-TU,32796
+flask/sessions.py,sha256=46jK4JlcdeBiYbDWTZJn_6u8EqDV-ByRdhlKrbgFi5M,15714
+flask/signals.py,sha256=H7QwDciK-dtBxinjKpexpglP0E6k0MJILiFWTItfmqU,2136
+flask/templating.py,sha256=l96VD39JQ0nue4Bcj7wZ4-FWWs-ppLxvgBCpwDQ4KAk,5626
+flask/testing.py,sha256=T3mr2PLQEkfxoftSTxmGfTtb_FSX3PgfGT8DUGNPWuk,10840
+flask/typing.py,sha256=L5JMltVjj8fovGS1hrMpb13IPfsFDESCCnpRN5CPT4U,1844
+flask/views.py,sha256=nhq31TRB5Z-z2mjFGZACaaB2Et5XPCmWhWxJxOvLWww,5948
+flask/wrappers.py,sha256=VndbHPRBSUUOejmd2Y3ydkoCVUtsS2OJIdJEVIkBVD8,5604
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/REQUESTED b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/direct_url.json b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/direct_url.json
new file mode 100644
index 0000000..f033626
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/direct_url.json
@@ -0,0 +1 @@
+{"archive_info": {}, "url": "file:///home/runner/.cache/pypoetry/artifacts/cd/4b/12/2ef50ad12f8373130d91ea66343bfa1fb25be1e5b370671bbcca3bf5a1/Flask-2.0.3-py3-none-any.whl"}
\ No newline at end of file
diff --git a/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/entry_points.txt b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/entry_points.txt
new file mode 100644
index 0000000..137232d
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/Flask-2.0.3.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[console_scripts]
+flask = flask.cli:main
diff --git a/venv/lib64/python3.8/site-packages/SecretStorage-3.3.1.dist-info/RECORD b/venv/lib64/python3.8/site-packages/SecretStorage-3.3.1.dist-info/RECORD
new file mode 100644
index 0000000..20ad0fe
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/SecretStorage-3.3.1.dist-info/RECORD
@@ -0,0 +1,21 @@
+SecretStorage-3.3.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+SecretStorage-3.3.1.dist-info/LICENSE,sha256=cPa_yndjPDXvohgyjtpUhtcFTCkU1hggmA43h5dSCiU,1504
+SecretStorage-3.3.1.dist-info/METADATA,sha256=ozeU7sep7B1qsoQ4UrHv6CdsUPNrJWZ6_TRmocPSnHI,3943
+SecretStorage-3.3.1.dist-info/RECORD,,
+SecretStorage-3.3.1.dist-info/WHEEL,sha256=g4nMs7d-Xl9-xC9XovUrsDHGXt-FT0E17Yqo92DEfvY,92
+SecretStorage-3.3.1.dist-info/top_level.txt,sha256=hveSi1OWGaEt3kEVbjmZ0M-ASPxi6y-nTPVa-d3c0B4,14
+secretstorage/__init__.py,sha256=pHaVJFUsWYM7EQv3VeqZkZqhan8ndIQMP4mQ7pDXgOA,3180
+secretstorage/__pycache__/__init__.cpython-38.pyc,,
+secretstorage/__pycache__/collection.cpython-38.pyc,,
+secretstorage/__pycache__/defines.cpython-38.pyc,,
+secretstorage/__pycache__/dhcrypto.cpython-38.pyc,,
+secretstorage/__pycache__/exceptions.cpython-38.pyc,,
+secretstorage/__pycache__/item.cpython-38.pyc,,
+secretstorage/__pycache__/util.cpython-38.pyc,,
+secretstorage/collection.py,sha256=vaep-OCM65Z7xznmH25jQWCJ_fLaZ2RpY5pIdNZJz6U,8408
+secretstorage/defines.py,sha256=x2lf3W2Ks8TV52tldb-Fn1u_Rmd5-AfeXBx2HzeGXy0,824
+secretstorage/dhcrypto.py,sha256=MVeCaOEbjda4YnXWPcq4VU_eIMUvJtGiEsWUCXC7PJo,2417
+secretstorage/exceptions.py,sha256=MEgrgRxY7-iW_QI3FH7WN3JGupA-Fzl8_r1-Y3XwwHU,1576
+secretstorage/item.py,sha256=3NJzakoFWeg59kFjgzGRGlvgg3BgrgT-56QMrFVL9fw,5241
+secretstorage/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+secretstorage/util.py,sha256=mXIlvP_phVO6BbN4KH8sYW0dfEFxhbr0hEViGTzJcAY,6002
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__init__.py b/venv/lib64/python3.8/site-packages/aiohttp/__init__.py
new file mode 100644
index 0000000..23cd5c9
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/aiohttp/__init__.py
@@ -0,0 +1,217 @@
+__version__ = "3.7.4"
+
+from typing import Tuple
+
+from . import hdrs as hdrs
+from .client import (
+ BaseConnector as BaseConnector,
+ ClientConnectionError as ClientConnectionError,
+ ClientConnectorCertificateError as ClientConnectorCertificateError,
+ ClientConnectorError as ClientConnectorError,
+ ClientConnectorSSLError as ClientConnectorSSLError,
+ ClientError as ClientError,
+ ClientHttpProxyError as ClientHttpProxyError,
+ ClientOSError as ClientOSError,
+ ClientPayloadError as ClientPayloadError,
+ ClientProxyConnectionError as ClientProxyConnectionError,
+ ClientRequest as ClientRequest,
+ ClientResponse as ClientResponse,
+ ClientResponseError as ClientResponseError,
+ ClientSession as ClientSession,
+ ClientSSLError as ClientSSLError,
+ ClientTimeout as ClientTimeout,
+ ClientWebSocketResponse as ClientWebSocketResponse,
+ ContentTypeError as ContentTypeError,
+ Fingerprint as Fingerprint,
+ InvalidURL as InvalidURL,
+ NamedPipeConnector as NamedPipeConnector,
+ RequestInfo as RequestInfo,
+ ServerConnectionError as ServerConnectionError,
+ ServerDisconnectedError as ServerDisconnectedError,
+ ServerFingerprintMismatch as ServerFingerprintMismatch,
+ ServerTimeoutError as ServerTimeoutError,
+ TCPConnector as TCPConnector,
+ TooManyRedirects as TooManyRedirects,
+ UnixConnector as UnixConnector,
+ WSServerHandshakeError as WSServerHandshakeError,
+ request as request,
+)
+from .cookiejar import CookieJar as CookieJar, DummyCookieJar as DummyCookieJar
+from .formdata import FormData as FormData
+from .helpers import BasicAuth as BasicAuth, ChainMapProxy as ChainMapProxy
+from .http import (
+ HttpVersion as HttpVersion,
+ HttpVersion10 as HttpVersion10,
+ HttpVersion11 as HttpVersion11,
+ WebSocketError as WebSocketError,
+ WSCloseCode as WSCloseCode,
+ WSMessage as WSMessage,
+ WSMsgType as WSMsgType,
+)
+from .multipart import (
+ BadContentDispositionHeader as BadContentDispositionHeader,
+ BadContentDispositionParam as BadContentDispositionParam,
+ BodyPartReader as BodyPartReader,
+ MultipartReader as MultipartReader,
+ MultipartWriter as MultipartWriter,
+ content_disposition_filename as content_disposition_filename,
+ parse_content_disposition as parse_content_disposition,
+)
+from .payload import (
+ PAYLOAD_REGISTRY as PAYLOAD_REGISTRY,
+ AsyncIterablePayload as AsyncIterablePayload,
+ BufferedReaderPayload as BufferedReaderPayload,
+ BytesIOPayload as BytesIOPayload,
+ BytesPayload as BytesPayload,
+ IOBasePayload as IOBasePayload,
+ JsonPayload as JsonPayload,
+ Payload as Payload,
+ StringIOPayload as StringIOPayload,
+ StringPayload as StringPayload,
+ TextIOPayload as TextIOPayload,
+ get_payload as get_payload,
+ payload_type as payload_type,
+)
+from .payload_streamer import streamer as streamer
+from .resolver import (
+ AsyncResolver as AsyncResolver,
+ DefaultResolver as DefaultResolver,
+ ThreadedResolver as ThreadedResolver,
+)
+from .signals import Signal as Signal
+from .streams import (
+ EMPTY_PAYLOAD as EMPTY_PAYLOAD,
+ DataQueue as DataQueue,
+ EofStream as EofStream,
+ FlowControlDataQueue as FlowControlDataQueue,
+ StreamReader as StreamReader,
+)
+from .tracing import (
+ TraceConfig as TraceConfig,
+ TraceConnectionCreateEndParams as TraceConnectionCreateEndParams,
+ TraceConnectionCreateStartParams as TraceConnectionCreateStartParams,
+ TraceConnectionQueuedEndParams as TraceConnectionQueuedEndParams,
+ TraceConnectionQueuedStartParams as TraceConnectionQueuedStartParams,
+ TraceConnectionReuseconnParams as TraceConnectionReuseconnParams,
+ TraceDnsCacheHitParams as TraceDnsCacheHitParams,
+ TraceDnsCacheMissParams as TraceDnsCacheMissParams,
+ TraceDnsResolveHostEndParams as TraceDnsResolveHostEndParams,
+ TraceDnsResolveHostStartParams as TraceDnsResolveHostStartParams,
+ TraceRequestChunkSentParams as TraceRequestChunkSentParams,
+ TraceRequestEndParams as TraceRequestEndParams,
+ TraceRequestExceptionParams as TraceRequestExceptionParams,
+ TraceRequestRedirectParams as TraceRequestRedirectParams,
+ TraceRequestStartParams as TraceRequestStartParams,
+ TraceResponseChunkReceivedParams as TraceResponseChunkReceivedParams,
+)
+
+__all__: Tuple[str, ...] = (
+ "hdrs",
+ # client
+ "BaseConnector",
+ "ClientConnectionError",
+ "ClientConnectorCertificateError",
+ "ClientConnectorError",
+ "ClientConnectorSSLError",
+ "ClientError",
+ "ClientHttpProxyError",
+ "ClientOSError",
+ "ClientPayloadError",
+ "ClientProxyConnectionError",
+ "ClientResponse",
+ "ClientRequest",
+ "ClientResponseError",
+ "ClientSSLError",
+ "ClientSession",
+ "ClientTimeout",
+ "ClientWebSocketResponse",
+ "ContentTypeError",
+ "Fingerprint",
+ "InvalidURL",
+ "RequestInfo",
+ "ServerConnectionError",
+ "ServerDisconnectedError",
+ "ServerFingerprintMismatch",
+ "ServerTimeoutError",
+ "TCPConnector",
+ "TooManyRedirects",
+ "UnixConnector",
+ "NamedPipeConnector",
+ "WSServerHandshakeError",
+ "request",
+ # cookiejar
+ "CookieJar",
+ "DummyCookieJar",
+ # formdata
+ "FormData",
+ # helpers
+ "BasicAuth",
+ "ChainMapProxy",
+ # http
+ "HttpVersion",
+ "HttpVersion10",
+ "HttpVersion11",
+ "WSMsgType",
+ "WSCloseCode",
+ "WSMessage",
+ "WebSocketError",
+ # multipart
+ "BadContentDispositionHeader",
+ "BadContentDispositionParam",
+ "BodyPartReader",
+ "MultipartReader",
+ "MultipartWriter",
+ "content_disposition_filename",
+ "parse_content_disposition",
+ # payload
+ "AsyncIterablePayload",
+ "BufferedReaderPayload",
+ "BytesIOPayload",
+ "BytesPayload",
+ "IOBasePayload",
+ "JsonPayload",
+ "PAYLOAD_REGISTRY",
+ "Payload",
+ "StringIOPayload",
+ "StringPayload",
+ "TextIOPayload",
+ "get_payload",
+ "payload_type",
+ # payload_streamer
+ "streamer",
+ # resolver
+ "AsyncResolver",
+ "DefaultResolver",
+ "ThreadedResolver",
+ # signals
+ "Signal",
+ "DataQueue",
+ "EMPTY_PAYLOAD",
+ "EofStream",
+ "FlowControlDataQueue",
+ "StreamReader",
+ # tracing
+ "TraceConfig",
+ "TraceConnectionCreateEndParams",
+ "TraceConnectionCreateStartParams",
+ "TraceConnectionQueuedEndParams",
+ "TraceConnectionQueuedStartParams",
+ "TraceConnectionReuseconnParams",
+ "TraceDnsCacheHitParams",
+ "TraceDnsCacheMissParams",
+ "TraceDnsResolveHostEndParams",
+ "TraceDnsResolveHostStartParams",
+ "TraceRequestChunkSentParams",
+ "TraceRequestEndParams",
+ "TraceRequestExceptionParams",
+ "TraceRequestRedirectParams",
+ "TraceRequestStartParams",
+ "TraceResponseChunkReceivedParams",
+)
+
+try:
+ from .worker import GunicornUVLoopWebWorker, GunicornWebWorker
+
+ __all__ += ("GunicornWebWorker", "GunicornUVLoopWebWorker")
+except ImportError: # pragma: no cover
+ pass
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..4b24e13
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/abc.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/abc.cpython-38.pyc
new file mode 100644
index 0000000..e1c772d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/abc.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/base_protocol.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/base_protocol.cpython-38.pyc
new file mode 100644
index 0000000..19971f0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/base_protocol.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client.cpython-38.pyc
new file mode 100644
index 0000000..51d6fb7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_exceptions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_exceptions.cpython-38.pyc
new file mode 100644
index 0000000..ee3b706
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_exceptions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_proto.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_proto.cpython-38.pyc
new file mode 100644
index 0000000..d568b39
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_proto.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_reqrep.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_reqrep.cpython-38.pyc
new file mode 100644
index 0000000..290aac1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_reqrep.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_ws.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_ws.cpython-38.pyc
new file mode 100644
index 0000000..6cfb0c7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/client_ws.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/connector.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/connector.cpython-38.pyc
new file mode 100644
index 0000000..afdf518
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/connector.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/cookiejar.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/cookiejar.cpython-38.pyc
new file mode 100644
index 0000000..31ecdf9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/cookiejar.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/formdata.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/formdata.cpython-38.pyc
new file mode 100644
index 0000000..ccf2d22
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/formdata.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/frozenlist.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/frozenlist.cpython-38.pyc
new file mode 100644
index 0000000..7e8a7cb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/frozenlist.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/hdrs.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/hdrs.cpython-38.pyc
new file mode 100644
index 0000000..7ed0b48
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/hdrs.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/helpers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/helpers.cpython-38.pyc
new file mode 100644
index 0000000..ddb476c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/helpers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http.cpython-38.pyc
new file mode 100644
index 0000000..013de80
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_exceptions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_exceptions.cpython-38.pyc
new file mode 100644
index 0000000..aee6841
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_exceptions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_parser.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_parser.cpython-38.pyc
new file mode 100644
index 0000000..9dbf522
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_parser.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_websocket.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_websocket.cpython-38.pyc
new file mode 100644
index 0000000..3f24403
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_websocket.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_writer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_writer.cpython-38.pyc
new file mode 100644
index 0000000..919a48b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/http_writer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/locks.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/locks.cpython-38.pyc
new file mode 100644
index 0000000..93187f4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/locks.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/log.cpython-38.pyc
new file mode 100644
index 0000000..0d99cf5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/multipart.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/multipart.cpython-38.pyc
new file mode 100644
index 0000000..da3346d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/multipart.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload.cpython-38.pyc
new file mode 100644
index 0000000..8142c3f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload_streamer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload_streamer.cpython-38.pyc
new file mode 100644
index 0000000..d6c4776
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/payload_streamer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-38.pyc
new file mode 100644
index 0000000..9cb9c56
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/pytest_plugin.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/resolver.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/resolver.cpython-38.pyc
new file mode 100644
index 0000000..313f807
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/resolver.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/signals.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/signals.cpython-38.pyc
new file mode 100644
index 0000000..e29fb5f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/signals.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/streams.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/streams.cpython-38.pyc
new file mode 100644
index 0000000..35b3bbc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/streams.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-38.pyc
new file mode 100644
index 0000000..1c9f9a8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tcp_helpers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/test_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/test_utils.cpython-38.pyc
new file mode 100644
index 0000000..b03931e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/test_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tracing.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tracing.cpython-38.pyc
new file mode 100644
index 0000000..95f07c5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/tracing.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/typedefs.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/typedefs.cpython-38.pyc
new file mode 100644
index 0000000..8e9cdac
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/typedefs.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web.cpython-38.pyc
new file mode 100644
index 0000000..eecd5f5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_app.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_app.cpython-38.pyc
new file mode 100644
index 0000000..ead30b2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_app.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_exceptions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_exceptions.cpython-38.pyc
new file mode 100644
index 0000000..a4f23dc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_exceptions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-38.pyc
new file mode 100644
index 0000000..7b82a35
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_fileresponse.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_log.cpython-38.pyc
new file mode 100644
index 0000000..bd3a853
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_middlewares.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_middlewares.cpython-38.pyc
new file mode 100644
index 0000000..00f6adf
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_middlewares.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_protocol.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_protocol.cpython-38.pyc
new file mode 100644
index 0000000..b453db4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_protocol.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_request.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_request.cpython-38.pyc
new file mode 100644
index 0000000..e246b41
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_request.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_response.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_response.cpython-38.pyc
new file mode 100644
index 0000000..7fd80de
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_response.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_routedef.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_routedef.cpython-38.pyc
new file mode 100644
index 0000000..bc0b70b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_routedef.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_runner.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_runner.cpython-38.pyc
new file mode 100644
index 0000000..700c933
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_runner.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_server.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_server.cpython-38.pyc
new file mode 100644
index 0000000..797f87d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_server.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-38.pyc
new file mode 100644
index 0000000..f45fe6a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_urldispatcher.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_ws.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_ws.cpython-38.pyc
new file mode 100644
index 0000000..15eab92
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/web_ws.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/worker.cpython-38.pyc b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/worker.cpython-38.pyc
new file mode 100644
index 0000000..9457a7a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/__pycache__/worker.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/_frozenlist.cpython-38-x86_64-linux-gnu.so b/venv/lib64/python3.8/site-packages/aiohttp/_frozenlist.cpython-38-x86_64-linux-gnu.so
new file mode 100644
index 0000000..a60c2e4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/_frozenlist.cpython-38-x86_64-linux-gnu.so differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/_helpers.cpython-38-x86_64-linux-gnu.so b/venv/lib64/python3.8/site-packages/aiohttp/_helpers.cpython-38-x86_64-linux-gnu.so
new file mode 100644
index 0000000..c567aa9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/_helpers.cpython-38-x86_64-linux-gnu.so differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/_http_parser.cpython-38-x86_64-linux-gnu.so b/venv/lib64/python3.8/site-packages/aiohttp/_http_parser.cpython-38-x86_64-linux-gnu.so
new file mode 100644
index 0000000..696e4c7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/_http_parser.cpython-38-x86_64-linux-gnu.so differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/_http_writer.cpython-38-x86_64-linux-gnu.so b/venv/lib64/python3.8/site-packages/aiohttp/_http_writer.cpython-38-x86_64-linux-gnu.so
new file mode 100644
index 0000000..56347c0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/_http_writer.cpython-38-x86_64-linux-gnu.so differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/_websocket.cpython-38-x86_64-linux-gnu.so b/venv/lib64/python3.8/site-packages/aiohttp/_websocket.cpython-38-x86_64-linux-gnu.so
new file mode 100644
index 0000000..ea4b09b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/aiohttp/_websocket.cpython-38-x86_64-linux-gnu.so differ
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/http_parser.py b/venv/lib64/python3.8/site-packages/aiohttp/http_parser.py
new file mode 100644
index 0000000..71ba815
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/aiohttp/http_parser.py
@@ -0,0 +1,901 @@
+import abc
+import asyncio
+import collections
+import re
+import string
+import zlib
+from enum import IntEnum
+from typing import Any, List, Optional, Tuple, Type, Union
+
+from multidict import CIMultiDict, CIMultiDictProxy, istr
+from yarl import URL
+
+from . import hdrs
+from .base_protocol import BaseProtocol
+from .helpers import NO_EXTENSIONS, BaseTimerContext
+from .http_exceptions import (
+ BadStatusLine,
+ ContentEncodingError,
+ ContentLengthError,
+ InvalidHeader,
+ LineTooLong,
+ TransferEncodingError,
+)
+from .http_writer import HttpVersion, HttpVersion10
+from .log import internal_logger
+from .streams import EMPTY_PAYLOAD, StreamReader
+from .typedefs import RawHeaders
+
+try:
+ import brotli
+
+ HAS_BROTLI = True
+except ImportError: # pragma: no cover
+ HAS_BROTLI = False
+
+
+__all__ = (
+ "HeadersParser",
+ "HttpParser",
+ "HttpRequestParser",
+ "HttpResponseParser",
+ "RawRequestMessage",
+ "RawResponseMessage",
+)
+
+ASCIISET = set(string.printable)
+
+# See https://tools.ietf.org/html/rfc7230#section-3.1.1
+# and https://tools.ietf.org/html/rfc7230#appendix-B
+#
+# method = token
+# tchar = "!" / "#" / "$" / "%" / "&" / "'" / "*" / "+" / "-" / "." /
+# "^" / "_" / "`" / "|" / "~" / DIGIT / ALPHA
+# token = 1*tchar
+METHRE = re.compile(r"[!#$%&'*+\-.^_`|~0-9A-Za-z]+")
+VERSRE = re.compile(r"HTTP/(\d+).(\d+)")
+HDRRE = re.compile(rb"[\x00-\x1F\x7F()<>@,;:\[\]={} \t\\\\\"]")
+
+RawRequestMessage = collections.namedtuple(
+ "RawRequestMessage",
+ [
+ "method",
+ "path",
+ "version",
+ "headers",
+ "raw_headers",
+ "should_close",
+ "compression",
+ "upgrade",
+ "chunked",
+ "url",
+ ],
+)
+
+RawResponseMessage = collections.namedtuple(
+ "RawResponseMessage",
+ [
+ "version",
+ "code",
+ "reason",
+ "headers",
+ "raw_headers",
+ "should_close",
+ "compression",
+ "upgrade",
+ "chunked",
+ ],
+)
+
+
+class ParseState(IntEnum):
+
+ PARSE_NONE = 0
+ PARSE_LENGTH = 1
+ PARSE_CHUNKED = 2
+ PARSE_UNTIL_EOF = 3
+
+
+class ChunkState(IntEnum):
+ PARSE_CHUNKED_SIZE = 0
+ PARSE_CHUNKED_CHUNK = 1
+ PARSE_CHUNKED_CHUNK_EOF = 2
+ PARSE_MAYBE_TRAILERS = 3
+ PARSE_TRAILERS = 4
+
+
+class HeadersParser:
+ def __init__(
+ self,
+ max_line_size: int = 8190,
+ max_headers: int = 32768,
+ max_field_size: int = 8190,
+ ) -> None:
+ self.max_line_size = max_line_size
+ self.max_headers = max_headers
+ self.max_field_size = max_field_size
+
+ def parse_headers(
+ self, lines: List[bytes]
+ ) -> Tuple["CIMultiDictProxy[str]", RawHeaders]:
+ headers = CIMultiDict() # type: CIMultiDict[str]
+ raw_headers = []
+
+ lines_idx = 1
+ line = lines[1]
+ line_count = len(lines)
+
+ while line:
+ # Parse initial header name : value pair.
+ try:
+ bname, bvalue = line.split(b":", 1)
+ except ValueError:
+ raise InvalidHeader(line) from None
+
+ bname = bname.strip(b" \t")
+ bvalue = bvalue.lstrip()
+ if HDRRE.search(bname):
+ raise InvalidHeader(bname)
+ if len(bname) > self.max_field_size:
+ raise LineTooLong(
+ "request header name {}".format(
+ bname.decode("utf8", "xmlcharrefreplace")
+ ),
+ str(self.max_field_size),
+ str(len(bname)),
+ )
+
+ header_length = len(bvalue)
+
+ # next line
+ lines_idx += 1
+ line = lines[lines_idx]
+
+ # consume continuation lines
+ continuation = line and line[0] in (32, 9) # (' ', '\t')
+
+ if continuation:
+ bvalue_lst = [bvalue]
+ while continuation:
+ header_length += len(line)
+ if header_length > self.max_field_size:
+ raise LineTooLong(
+ "request header field {}".format(
+ bname.decode("utf8", "xmlcharrefreplace")
+ ),
+ str(self.max_field_size),
+ str(header_length),
+ )
+ bvalue_lst.append(line)
+
+ # next line
+ lines_idx += 1
+ if lines_idx < line_count:
+ line = lines[lines_idx]
+ if line:
+ continuation = line[0] in (32, 9) # (' ', '\t')
+ else:
+ line = b""
+ break
+ bvalue = b"".join(bvalue_lst)
+ else:
+ if header_length > self.max_field_size:
+ raise LineTooLong(
+ "request header field {}".format(
+ bname.decode("utf8", "xmlcharrefreplace")
+ ),
+ str(self.max_field_size),
+ str(header_length),
+ )
+
+ bvalue = bvalue.strip()
+ name = bname.decode("utf-8", "surrogateescape")
+ value = bvalue.decode("utf-8", "surrogateescape")
+
+ headers.add(name, value)
+ raw_headers.append((bname, bvalue))
+
+ return (CIMultiDictProxy(headers), tuple(raw_headers))
+
+
+class HttpParser(abc.ABC):
+ def __init__(
+ self,
+ protocol: Optional[BaseProtocol] = None,
+ loop: Optional[asyncio.AbstractEventLoop] = None,
+ limit: int = 2 ** 16,
+ max_line_size: int = 8190,
+ max_headers: int = 32768,
+ max_field_size: int = 8190,
+ timer: Optional[BaseTimerContext] = None,
+ code: Optional[int] = None,
+ method: Optional[str] = None,
+ readall: bool = False,
+ payload_exception: Optional[Type[BaseException]] = None,
+ response_with_body: bool = True,
+ read_until_eof: bool = False,
+ auto_decompress: bool = True,
+ ) -> None:
+ self.protocol = protocol
+ self.loop = loop
+ self.max_line_size = max_line_size
+ self.max_headers = max_headers
+ self.max_field_size = max_field_size
+ self.timer = timer
+ self.code = code
+ self.method = method
+ self.readall = readall
+ self.payload_exception = payload_exception
+ self.response_with_body = response_with_body
+ self.read_until_eof = read_until_eof
+
+ self._lines = [] # type: List[bytes]
+ self._tail = b""
+ self._upgraded = False
+ self._payload = None
+ self._payload_parser = None # type: Optional[HttpPayloadParser]
+ self._auto_decompress = auto_decompress
+ self._limit = limit
+ self._headers_parser = HeadersParser(max_line_size, max_headers, max_field_size)
+
+ @abc.abstractmethod
+ def parse_message(self, lines: List[bytes]) -> Any:
+ pass
+
+ def feed_eof(self) -> Any:
+ if self._payload_parser is not None:
+ self._payload_parser.feed_eof()
+ self._payload_parser = None
+ else:
+ # try to extract partial message
+ if self._tail:
+ self._lines.append(self._tail)
+
+ if self._lines:
+ if self._lines[-1] != "\r\n":
+ self._lines.append(b"")
+ try:
+ return self.parse_message(self._lines)
+ except Exception:
+ return None
+
+ def feed_data(
+ self,
+ data: bytes,
+ SEP: bytes = b"\r\n",
+ EMPTY: bytes = b"",
+ CONTENT_LENGTH: istr = hdrs.CONTENT_LENGTH,
+ METH_CONNECT: str = hdrs.METH_CONNECT,
+ SEC_WEBSOCKET_KEY1: istr = hdrs.SEC_WEBSOCKET_KEY1,
+ ) -> Tuple[List[Any], bool, bytes]:
+
+ messages = []
+
+ if self._tail:
+ data, self._tail = self._tail + data, b""
+
+ data_len = len(data)
+ start_pos = 0
+ loop = self.loop
+
+ while start_pos < data_len:
+
+ # read HTTP message (request/response line + headers), \r\n\r\n
+ # and split by lines
+ if self._payload_parser is None and not self._upgraded:
+ pos = data.find(SEP, start_pos)
+ # consume \r\n
+ if pos == start_pos and not self._lines:
+ start_pos = pos + 2
+ continue
+
+ if pos >= start_pos:
+ # line found
+ self._lines.append(data[start_pos:pos])
+ start_pos = pos + 2
+
+ # \r\n\r\n found
+ if self._lines[-1] == EMPTY:
+ try:
+ msg = self.parse_message(self._lines)
+ finally:
+ self._lines.clear()
+
+ # payload length
+ length = msg.headers.get(CONTENT_LENGTH)
+ if length is not None:
+ try:
+ length = int(length)
+ except ValueError:
+ raise InvalidHeader(CONTENT_LENGTH)
+ if length < 0:
+ raise InvalidHeader(CONTENT_LENGTH)
+
+ # do not support old websocket spec
+ if SEC_WEBSOCKET_KEY1 in msg.headers:
+ raise InvalidHeader(SEC_WEBSOCKET_KEY1)
+
+ self._upgraded = msg.upgrade
+
+ method = getattr(msg, "method", self.method)
+
+ assert self.protocol is not None
+ # calculate payload
+ if (
+ (length is not None and length > 0)
+ or msg.chunked
+ and not msg.upgrade
+ ):
+ payload = StreamReader(
+ self.protocol,
+ timer=self.timer,
+ loop=loop,
+ limit=self._limit,
+ )
+ payload_parser = HttpPayloadParser(
+ payload,
+ length=length,
+ chunked=msg.chunked,
+ method=method,
+ compression=msg.compression,
+ code=self.code,
+ readall=self.readall,
+ response_with_body=self.response_with_body,
+ auto_decompress=self._auto_decompress,
+ )
+ if not payload_parser.done:
+ self._payload_parser = payload_parser
+ elif method == METH_CONNECT:
+ payload = StreamReader(
+ self.protocol,
+ timer=self.timer,
+ loop=loop,
+ limit=self._limit,
+ )
+ self._upgraded = True
+ self._payload_parser = HttpPayloadParser(
+ payload,
+ method=msg.method,
+ compression=msg.compression,
+ readall=True,
+ auto_decompress=self._auto_decompress,
+ )
+ else:
+ if (
+ getattr(msg, "code", 100) >= 199
+ and length is None
+ and self.read_until_eof
+ ):
+ payload = StreamReader(
+ self.protocol,
+ timer=self.timer,
+ loop=loop,
+ limit=self._limit,
+ )
+ payload_parser = HttpPayloadParser(
+ payload,
+ length=length,
+ chunked=msg.chunked,
+ method=method,
+ compression=msg.compression,
+ code=self.code,
+ readall=True,
+ response_with_body=self.response_with_body,
+ auto_decompress=self._auto_decompress,
+ )
+ if not payload_parser.done:
+ self._payload_parser = payload_parser
+ else:
+ payload = EMPTY_PAYLOAD # type: ignore
+
+ messages.append((msg, payload))
+ else:
+ self._tail = data[start_pos:]
+ data = EMPTY
+ break
+
+ # no parser, just store
+ elif self._payload_parser is None and self._upgraded:
+ assert not self._lines
+ break
+
+ # feed payload
+ elif data and start_pos < data_len:
+ assert not self._lines
+ assert self._payload_parser is not None
+ try:
+ eof, data = self._payload_parser.feed_data(data[start_pos:])
+ except BaseException as exc:
+ if self.payload_exception is not None:
+ self._payload_parser.payload.set_exception(
+ self.payload_exception(str(exc))
+ )
+ else:
+ self._payload_parser.payload.set_exception(exc)
+
+ eof = True
+ data = b""
+
+ if eof:
+ start_pos = 0
+ data_len = len(data)
+ self._payload_parser = None
+ continue
+ else:
+ break
+
+ if data and start_pos < data_len:
+ data = data[start_pos:]
+ else:
+ data = EMPTY
+
+ return messages, self._upgraded, data
+
+ def parse_headers(
+ self, lines: List[bytes]
+ ) -> Tuple[
+ "CIMultiDictProxy[str]", RawHeaders, Optional[bool], Optional[str], bool, bool
+ ]:
+ """Parses RFC 5322 headers from a stream.
+
+ Line continuations are supported. Returns list of header name
+ and value pairs. Header name is in upper case.
+ """
+ headers, raw_headers = self._headers_parser.parse_headers(lines)
+ close_conn = None
+ encoding = None
+ upgrade = False
+ chunked = False
+
+ # keep-alive
+ conn = headers.get(hdrs.CONNECTION)
+ if conn:
+ v = conn.lower()
+ if v == "close":
+ close_conn = True
+ elif v == "keep-alive":
+ close_conn = False
+ elif v == "upgrade":
+ upgrade = True
+
+ # encoding
+ enc = headers.get(hdrs.CONTENT_ENCODING)
+ if enc:
+ enc = enc.lower()
+ if enc in ("gzip", "deflate", "br"):
+ encoding = enc
+
+ # chunking
+ te = headers.get(hdrs.TRANSFER_ENCODING)
+ if te and "chunked" in te.lower():
+ chunked = True
+
+ return (headers, raw_headers, close_conn, encoding, upgrade, chunked)
+
+ def set_upgraded(self, val: bool) -> None:
+ """Set connection upgraded (to websocket) mode.
+ :param bool val: new state.
+ """
+ self._upgraded = val
+
+
+class HttpRequestParser(HttpParser):
+ """Read request status line. Exception .http_exceptions.BadStatusLine
+ could be raised in case of any errors in status line.
+ Returns RawRequestMessage.
+ """
+
+ def parse_message(self, lines: List[bytes]) -> Any:
+ # request line
+ line = lines[0].decode("utf-8", "surrogateescape")
+ try:
+ method, path, version = line.split(None, 2)
+ except ValueError:
+ raise BadStatusLine(line) from None
+
+ if len(path) > self.max_line_size:
+ raise LineTooLong(
+ "Status line is too long", str(self.max_line_size), str(len(path))
+ )
+
+ path_part, _hash_separator, url_fragment = path.partition("#")
+ path_part, _question_mark_separator, qs_part = path_part.partition("?")
+
+ # method
+ if not METHRE.match(method):
+ raise BadStatusLine(method)
+
+ # version
+ try:
+ if version.startswith("HTTP/"):
+ n1, n2 = version[5:].split(".", 1)
+ version_o = HttpVersion(int(n1), int(n2))
+ else:
+ raise BadStatusLine(version)
+ except Exception:
+ raise BadStatusLine(version)
+
+ # read headers
+ (
+ headers,
+ raw_headers,
+ close,
+ compression,
+ upgrade,
+ chunked,
+ ) = self.parse_headers(lines)
+
+ if close is None: # then the headers weren't set in the request
+ if version_o <= HttpVersion10: # HTTP 1.0 must asks to not close
+ close = True
+ else: # HTTP 1.1 must ask to close.
+ close = False
+
+ return RawRequestMessage(
+ method,
+ path,
+ version_o,
+ headers,
+ raw_headers,
+ close,
+ compression,
+ upgrade,
+ chunked,
+ # NOTE: `yarl.URL.build()` is used to mimic what the Cython-based
+ # NOTE: parser does, otherwise it results into the same
+ # NOTE: HTTP Request-Line input producing different
+ # NOTE: `yarl.URL()` objects
+ URL.build(
+ path=path_part,
+ query_string=qs_part,
+ fragment=url_fragment,
+ encoded=True,
+ ),
+ )
+
+
+class HttpResponseParser(HttpParser):
+ """Read response status line and headers.
+
+ BadStatusLine could be raised in case of any errors in status line.
+ Returns RawResponseMessage"""
+
+ def parse_message(self, lines: List[bytes]) -> Any:
+ line = lines[0].decode("utf-8", "surrogateescape")
+ try:
+ version, status = line.split(None, 1)
+ except ValueError:
+ raise BadStatusLine(line) from None
+
+ try:
+ status, reason = status.split(None, 1)
+ except ValueError:
+ reason = ""
+
+ if len(reason) > self.max_line_size:
+ raise LineTooLong(
+ "Status line is too long", str(self.max_line_size), str(len(reason))
+ )
+
+ # version
+ match = VERSRE.match(version)
+ if match is None:
+ raise BadStatusLine(line)
+ version_o = HttpVersion(int(match.group(1)), int(match.group(2)))
+
+ # The status code is a three-digit number
+ try:
+ status_i = int(status)
+ except ValueError:
+ raise BadStatusLine(line) from None
+
+ if status_i > 999:
+ raise BadStatusLine(line)
+
+ # read headers
+ (
+ headers,
+ raw_headers,
+ close,
+ compression,
+ upgrade,
+ chunked,
+ ) = self.parse_headers(lines)
+
+ if close is None:
+ close = version_o <= HttpVersion10
+
+ return RawResponseMessage(
+ version_o,
+ status_i,
+ reason.strip(),
+ headers,
+ raw_headers,
+ close,
+ compression,
+ upgrade,
+ chunked,
+ )
+
+
+class HttpPayloadParser:
+ def __init__(
+ self,
+ payload: StreamReader,
+ length: Optional[int] = None,
+ chunked: bool = False,
+ compression: Optional[str] = None,
+ code: Optional[int] = None,
+ method: Optional[str] = None,
+ readall: bool = False,
+ response_with_body: bool = True,
+ auto_decompress: bool = True,
+ ) -> None:
+ self._length = 0
+ self._type = ParseState.PARSE_NONE
+ self._chunk = ChunkState.PARSE_CHUNKED_SIZE
+ self._chunk_size = 0
+ self._chunk_tail = b""
+ self._auto_decompress = auto_decompress
+ self.done = False
+
+ # payload decompression wrapper
+ if response_with_body and compression and self._auto_decompress:
+ real_payload = DeflateBuffer(
+ payload, compression
+ ) # type: Union[StreamReader, DeflateBuffer]
+ else:
+ real_payload = payload
+
+ # payload parser
+ if not response_with_body:
+ # don't parse payload if it's not expected to be received
+ self._type = ParseState.PARSE_NONE
+ real_payload.feed_eof()
+ self.done = True
+
+ elif chunked:
+ self._type = ParseState.PARSE_CHUNKED
+ elif length is not None:
+ self._type = ParseState.PARSE_LENGTH
+ self._length = length
+ if self._length == 0:
+ real_payload.feed_eof()
+ self.done = True
+ else:
+ if readall and code != 204:
+ self._type = ParseState.PARSE_UNTIL_EOF
+ elif method in ("PUT", "POST"):
+ internal_logger.warning( # pragma: no cover
+ "Content-Length or Transfer-Encoding header is required"
+ )
+ self._type = ParseState.PARSE_NONE
+ real_payload.feed_eof()
+ self.done = True
+
+ self.payload = real_payload
+
+ def feed_eof(self) -> None:
+ if self._type == ParseState.PARSE_UNTIL_EOF:
+ self.payload.feed_eof()
+ elif self._type == ParseState.PARSE_LENGTH:
+ raise ContentLengthError(
+ "Not enough data for satisfy content length header."
+ )
+ elif self._type == ParseState.PARSE_CHUNKED:
+ raise TransferEncodingError(
+ "Not enough data for satisfy transfer length header."
+ )
+
+ def feed_data(
+ self, chunk: bytes, SEP: bytes = b"\r\n", CHUNK_EXT: bytes = b";"
+ ) -> Tuple[bool, bytes]:
+ # Read specified amount of bytes
+ if self._type == ParseState.PARSE_LENGTH:
+ required = self._length
+ chunk_len = len(chunk)
+
+ if required >= chunk_len:
+ self._length = required - chunk_len
+ self.payload.feed_data(chunk, chunk_len)
+ if self._length == 0:
+ self.payload.feed_eof()
+ return True, b""
+ else:
+ self._length = 0
+ self.payload.feed_data(chunk[:required], required)
+ self.payload.feed_eof()
+ return True, chunk[required:]
+
+ # Chunked transfer encoding parser
+ elif self._type == ParseState.PARSE_CHUNKED:
+ if self._chunk_tail:
+ chunk = self._chunk_tail + chunk
+ self._chunk_tail = b""
+
+ while chunk:
+
+ # read next chunk size
+ if self._chunk == ChunkState.PARSE_CHUNKED_SIZE:
+ pos = chunk.find(SEP)
+ if pos >= 0:
+ i = chunk.find(CHUNK_EXT, 0, pos)
+ if i >= 0:
+ size_b = chunk[:i] # strip chunk-extensions
+ else:
+ size_b = chunk[:pos]
+
+ try:
+ size = int(bytes(size_b), 16)
+ except ValueError:
+ exc = TransferEncodingError(
+ chunk[:pos].decode("ascii", "surrogateescape")
+ )
+ self.payload.set_exception(exc)
+ raise exc from None
+
+ chunk = chunk[pos + 2 :]
+ if size == 0: # eof marker
+ self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
+ else:
+ self._chunk = ChunkState.PARSE_CHUNKED_CHUNK
+ self._chunk_size = size
+ self.payload.begin_http_chunk_receiving()
+ else:
+ self._chunk_tail = chunk
+ return False, b""
+
+ # read chunk and feed buffer
+ if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK:
+ required = self._chunk_size
+ chunk_len = len(chunk)
+
+ if required > chunk_len:
+ self._chunk_size = required - chunk_len
+ self.payload.feed_data(chunk, chunk_len)
+ return False, b""
+ else:
+ self._chunk_size = 0
+ self.payload.feed_data(chunk[:required], required)
+ chunk = chunk[required:]
+ self._chunk = ChunkState.PARSE_CHUNKED_CHUNK_EOF
+ self.payload.end_http_chunk_receiving()
+
+ # toss the CRLF at the end of the chunk
+ if self._chunk == ChunkState.PARSE_CHUNKED_CHUNK_EOF:
+ if chunk[:2] == SEP:
+ chunk = chunk[2:]
+ self._chunk = ChunkState.PARSE_CHUNKED_SIZE
+ else:
+ self._chunk_tail = chunk
+ return False, b""
+
+ # if stream does not contain trailer, after 0\r\n
+ # we should get another \r\n otherwise
+ # trailers needs to be skiped until \r\n\r\n
+ if self._chunk == ChunkState.PARSE_MAYBE_TRAILERS:
+ head = chunk[:2]
+ if head == SEP:
+ # end of stream
+ self.payload.feed_eof()
+ return True, chunk[2:]
+ # Both CR and LF, or only LF may not be received yet. It is
+ # expected that CRLF or LF will be shown at the very first
+ # byte next time, otherwise trailers should come. The last
+ # CRLF which marks the end of response might not be
+ # contained in the same TCP segment which delivered the
+ # size indicator.
+ if not head:
+ return False, b""
+ if head == SEP[:1]:
+ self._chunk_tail = head
+ return False, b""
+ self._chunk = ChunkState.PARSE_TRAILERS
+
+ # read and discard trailer up to the CRLF terminator
+ if self._chunk == ChunkState.PARSE_TRAILERS:
+ pos = chunk.find(SEP)
+ if pos >= 0:
+ chunk = chunk[pos + 2 :]
+ self._chunk = ChunkState.PARSE_MAYBE_TRAILERS
+ else:
+ self._chunk_tail = chunk
+ return False, b""
+
+ # Read all bytes until eof
+ elif self._type == ParseState.PARSE_UNTIL_EOF:
+ self.payload.feed_data(chunk, len(chunk))
+
+ return False, b""
+
+
+class DeflateBuffer:
+ """DeflateStream decompress stream and feed data into specified stream."""
+
+ def __init__(self, out: StreamReader, encoding: Optional[str]) -> None:
+ self.out = out
+ self.size = 0
+ self.encoding = encoding
+ self._started_decoding = False
+
+ if encoding == "br":
+ if not HAS_BROTLI: # pragma: no cover
+ raise ContentEncodingError(
+ "Can not decode content-encoding: brotli (br). "
+ "Please install `brotlipy`"
+ )
+ self.decompressor = brotli.Decompressor()
+ else:
+ zlib_mode = 16 + zlib.MAX_WBITS if encoding == "gzip" else zlib.MAX_WBITS
+ self.decompressor = zlib.decompressobj(wbits=zlib_mode)
+
+ def set_exception(self, exc: BaseException) -> None:
+ self.out.set_exception(exc)
+
+ def feed_data(self, chunk: bytes, size: int) -> None:
+ if not size:
+ return
+
+ self.size += size
+
+ # RFC1950
+ # bits 0..3 = CM = 0b1000 = 8 = "deflate"
+ # bits 4..7 = CINFO = 1..7 = windows size.
+ if (
+ not self._started_decoding
+ and self.encoding == "deflate"
+ and chunk[0] & 0xF != 8
+ ):
+ # Change the decoder to decompress incorrectly compressed data
+ # Actually we should issue a warning about non-RFC-compliant data.
+ self.decompressor = zlib.decompressobj(wbits=-zlib.MAX_WBITS)
+
+ try:
+ chunk = self.decompressor.decompress(chunk)
+ except Exception:
+ raise ContentEncodingError(
+ "Can not decode content-encoding: %s" % self.encoding
+ )
+
+ self._started_decoding = True
+
+ if chunk:
+ self.out.feed_data(chunk, len(chunk))
+
+ def feed_eof(self) -> None:
+ chunk = self.decompressor.flush()
+
+ if chunk or self.size > 0:
+ self.out.feed_data(chunk, len(chunk))
+ if self.encoding == "deflate" and not self.decompressor.eof:
+ raise ContentEncodingError("deflate")
+
+ self.out.feed_eof()
+
+ def begin_http_chunk_receiving(self) -> None:
+ self.out.begin_http_chunk_receiving()
+
+ def end_http_chunk_receiving(self) -> None:
+ self.out.end_http_chunk_receiving()
+
+
+HttpRequestParserPy = HttpRequestParser
+HttpResponseParserPy = HttpResponseParser
+RawRequestMessagePy = RawRequestMessage
+RawResponseMessagePy = RawResponseMessage
+
+try:
+ if not NO_EXTENSIONS:
+ from ._http_parser import ( # type: ignore
+ HttpRequestParser,
+ HttpResponseParser,
+ RawRequestMessage,
+ RawResponseMessage,
+ )
+
+ HttpRequestParserC = HttpRequestParser
+ HttpResponseParserC = HttpResponseParser
+ RawRequestMessageC = RawRequestMessage
+ RawResponseMessageC = RawResponseMessage
+except ImportError: # pragma: no cover
+ pass
diff --git a/venv/lib64/python3.8/site-packages/aiohttp/web_middlewares.py b/venv/lib64/python3.8/site-packages/aiohttp/web_middlewares.py
new file mode 100644
index 0000000..8a8967e
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/aiohttp/web_middlewares.py
@@ -0,0 +1,121 @@
+import re
+from typing import TYPE_CHECKING, Awaitable, Callable, Tuple, Type, TypeVar
+
+from .web_exceptions import HTTPPermanentRedirect, _HTTPMove
+from .web_request import Request
+from .web_response import StreamResponse
+from .web_urldispatcher import SystemRoute
+
+__all__ = (
+ "middleware",
+ "normalize_path_middleware",
+)
+
+if TYPE_CHECKING: # pragma: no cover
+ from .web_app import Application
+
+_Func = TypeVar("_Func")
+
+
+async def _check_request_resolves(request: Request, path: str) -> Tuple[bool, Request]:
+ alt_request = request.clone(rel_url=path)
+
+ match_info = await request.app.router.resolve(alt_request)
+ alt_request._match_info = match_info # type: ignore
+
+ if match_info.http_exception is None:
+ return True, alt_request
+
+ return False, request
+
+
+def middleware(f: _Func) -> _Func:
+ f.__middleware_version__ = 1 # type: ignore
+ return f
+
+
+_Handler = Callable[[Request], Awaitable[StreamResponse]]
+_Middleware = Callable[[Request, _Handler], Awaitable[StreamResponse]]
+
+
+def normalize_path_middleware(
+ *,
+ append_slash: bool = True,
+ remove_slash: bool = False,
+ merge_slashes: bool = True,
+ redirect_class: Type[_HTTPMove] = HTTPPermanentRedirect
+) -> _Middleware:
+ """
+ Middleware factory which produces a middleware that normalizes
+ the path of a request. By normalizing it means:
+
+ - Add or remove a trailing slash to the path.
+ - Double slashes are replaced by one.
+
+ The middleware returns as soon as it finds a path that resolves
+ correctly. The order if both merge and append/remove are enabled is
+ 1) merge slashes
+ 2) append/remove slash
+ 3) both merge slashes and append/remove slash.
+ If the path resolves with at least one of those conditions, it will
+ redirect to the new path.
+
+ Only one of `append_slash` and `remove_slash` can be enabled. If both
+ are `True` the factory will raise an assertion error
+
+ If `append_slash` is `True` the middleware will append a slash when
+ needed. If a resource is defined with trailing slash and the request
+ comes without it, it will append it automatically.
+
+ If `remove_slash` is `True`, `append_slash` must be `False`. When enabled
+ the middleware will remove trailing slashes and redirect if the resource
+ is defined
+
+ If merge_slashes is True, merge multiple consecutive slashes in the
+ path into one.
+ """
+
+ correct_configuration = not (append_slash and remove_slash)
+ assert correct_configuration, "Cannot both remove and append slash"
+
+ @middleware
+ async def impl(request: Request, handler: _Handler) -> StreamResponse:
+ if isinstance(request.match_info.route, SystemRoute):
+ paths_to_check = []
+ if "?" in request.raw_path:
+ path, query = request.raw_path.split("?", 1)
+ query = "?" + query
+ else:
+ query = ""
+ path = request.raw_path
+
+ if merge_slashes:
+ paths_to_check.append(re.sub("//+", "/", path))
+ if append_slash and not request.path.endswith("/"):
+ paths_to_check.append(path + "/")
+ if remove_slash and request.path.endswith("/"):
+ paths_to_check.append(path[:-1])
+ if merge_slashes and append_slash:
+ paths_to_check.append(re.sub("//+", "/", path + "/"))
+ if merge_slashes and remove_slash:
+ merged_slashes = re.sub("//+", "/", path)
+ paths_to_check.append(merged_slashes[:-1])
+
+ for path in paths_to_check:
+ path = re.sub("^//+", "/", path) # SECURITY: GHSA-v6wp-4m6f-gcjg
+ resolves, request = await _check_request_resolves(request, path)
+ if resolves:
+ raise redirect_class(request.raw_path + query)
+
+ return await handler(request)
+
+ return impl
+
+
+def _fix_request_current_app(app: "Application") -> _Middleware:
+ @middleware
+ async def impl(request: Request, handler: _Handler) -> StreamResponse:
+ with request.match_info.set_current_app(app):
+ return await handler(request)
+
+ return impl
diff --git a/venv/lib64/python3.8/site-packages/async_timeout/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/async_timeout/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..0318c7d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/async_timeout/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..b97efe2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/converters.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/converters.cpython-38.pyc
new file mode 100644
index 0000000..1dca73a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/converters.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/exceptions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/exceptions.cpython-38.pyc
new file mode 100644
index 0000000..8bc3181
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/filters.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/filters.cpython-38.pyc
new file mode 100644
index 0000000..6599fb7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/filters.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/setters.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/setters.cpython-38.pyc
new file mode 100644
index 0000000..7b17065
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/setters.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/attrs/__pycache__/validators.cpython-38.pyc b/venv/lib64/python3.8/site-packages/attrs/__pycache__/validators.cpython-38.pyc
new file mode 100644
index 0000000..f060b8c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/attrs/__pycache__/validators.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/backports.entry_points_selectable-1.1.1.dist-info/RECORD b/venv/lib64/python3.8/site-packages/backports.entry_points_selectable-1.1.1.dist-info/RECORD
new file mode 100644
index 0000000..d3c81e3
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/backports.entry_points_selectable-1.1.1.dist-info/RECORD
@@ -0,0 +1,10 @@
+backports.entry_points_selectable-1.1.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+backports.entry_points_selectable-1.1.1.dist-info/LICENSE,sha256=2z8CRrH5J48VhFuZ_sR4uLUG63ZIeZNyL4xuJUKF-vg,1050
+backports.entry_points_selectable-1.1.1.dist-info/METADATA,sha256=JR4LLuqLGDNbRXwyrJ8o2UscKfiDPSp-XMy-Fo23Ccw,4014
+backports.entry_points_selectable-1.1.1.dist-info/RECORD,,
+backports.entry_points_selectable-1.1.1.dist-info/WHEEL,sha256=WzZ8cwjh8l0jtULNjYq1Hpr-WCqCRgPr--TX4P5I1Wo,110
+backports.entry_points_selectable-1.1.1.dist-info/top_level.txt,sha256=cGjaLMOoBR1FK0ApojtzWVmViTtJ7JGIK_HwXiEsvtU,10
+backports/__init__.py,sha256=iOEMwnlORWezdO8-2vxBIPSR37D7JGjluZ8f55vzxls,81
+backports/__pycache__/__init__.cpython-38.pyc,,
+backports/__pycache__/entry_points_selectable.cpython-38.pyc,,
+backports/entry_points_selectable.py,sha256=p6WRKhYFNocmWtTassxkXAbSwyqO01hJMq60y4rPyxE,7444
diff --git a/venv/lib64/python3.8/site-packages/cachy-0.3.0.dist-info/RECORD b/venv/lib64/python3.8/site-packages/cachy-0.3.0.dist-info/RECORD
new file mode 100644
index 0000000..b3fa65d
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/cachy-0.3.0.dist-info/RECORD
@@ -0,0 +1,53 @@
+cachy-0.3.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+cachy-0.3.0.dist-info/LICENSE,sha256=eddrvsOJnRZIIWOjZcf2XoenKZk6HWX5YPQYHi7LgaA,1062
+cachy-0.3.0.dist-info/METADATA,sha256=KK9dg-znFQygldlGs2epsfIRu37fMgVaQCO6Vi5TjGs,1472
+cachy-0.3.0.dist-info/RECORD,,
+cachy-0.3.0.dist-info/WHEEL,sha256=k_UtF7DeTKrUqc0FULNabrogAWgCy8zJZKQiwD2AkC4,89
+cachy/__init__.py,sha256=y41ImV85TJlxPUkY7wNYgAhG2VQEo5_g_03WbczZ5_E,124
+cachy/__pycache__/__init__.cpython-38.pyc,,
+cachy/__pycache__/cache_manager.cpython-38.pyc,,
+cachy/__pycache__/helpers.cpython-38.pyc,,
+cachy/__pycache__/redis_tagged_cache.cpython-38.pyc,,
+cachy/__pycache__/repository.cpython-38.pyc,,
+cachy/__pycache__/tag_set.cpython-38.pyc,,
+cachy/__pycache__/tagged_cache.cpython-38.pyc,,
+cachy/__pycache__/utils.cpython-38.pyc,,
+cachy/cache_manager.py,sha256=-eL3UqPRy6uTGqyYzZmqGkYt8PrxhIx9ziu8uZIWIWQ,7339
+cachy/contracts/__init__.py,sha256=O9CT1B2F-cVB8elT0EoCJbgkcffjvlmqteqavs4giDg,25
+cachy/contracts/__pycache__/__init__.cpython-38.pyc,,
+cachy/contracts/__pycache__/factory.cpython-38.pyc,,
+cachy/contracts/__pycache__/repository.cpython-38.pyc,,
+cachy/contracts/__pycache__/store.cpython-38.pyc,,
+cachy/contracts/__pycache__/taggable_store.cpython-38.pyc,,
+cachy/contracts/factory.py,sha256=F6USJ2ooGjTOFNS8gqmKxg8LHK3SZ2RgcbBxQI1QYsE,323
+cachy/contracts/repository.py,sha256=-3eqnXR8j5MiRIPlOYpec1X9DuIYNFbf_pn86XO8oDM,2942
+cachy/contracts/store.py,sha256=oxQWQEwiHIDOQj1b7CGnztrQdeFFHG5iAEVluZ-bAh8,2594
+cachy/contracts/taggable_store.py,sha256=ObQILbeu_CLBKV17r1dn3IJWjoPi4WiNboFKW7JW6RA,497
+cachy/helpers.py,sha256=pDSGH7MD2ARvumlPl6KhycFHIP_QQk5KsWRA6Vfs08U,101
+cachy/redis_tagged_cache.py,sha256=FZ8mmAd0y-QmXc7DCA0W-oJkUT7HgX-xX82QOosJV-E,2171
+cachy/repository.py,sha256=ZZHdMXeUrxvT2PJSmL9hTqeUr7fUkq527UvrZ3aQMyg,8250
+cachy/serializers/__init__.py,sha256=RuQDghzeLKWxWs8YKju6dOp75AsTcookQqOjYj9nfjs,202
+cachy/serializers/__pycache__/__init__.cpython-38.pyc,,
+cachy/serializers/__pycache__/json_serializer.cpython-38.pyc,,
+cachy/serializers/__pycache__/msgpack_serializer.cpython-38.pyc,,
+cachy/serializers/__pycache__/pickle_serializer.cpython-38.pyc,,
+cachy/serializers/__pycache__/serializer.cpython-38.pyc,,
+cachy/serializers/json_serializer.py,sha256=UNjSMa0auB9cVI-Ru6NB5dtvXKqSQ1Ne66fllOLwxT0,683
+cachy/serializers/msgpack_serializer.py,sha256=UX31MOUri5KwgECKOczoTaWAeJfvVeVQujKXz560xyI,814
+cachy/serializers/pickle_serializer.py,sha256=Hc-OOLQnLfOCvYGdRO3umd2z38MNjz7IUBPLI0Ksecc,848
+cachy/serializers/serializer.py,sha256=d_1G10DNG0Myq4tO43T1RmESyZjRRiHubhKsI21D4no,513
+cachy/stores/__init__.py,sha256=9kcnXzYQl9SU9EOYfMeTZH5bT7H1y2mPZkHYuIahZDk,207
+cachy/stores/__pycache__/__init__.cpython-38.pyc,,
+cachy/stores/__pycache__/dict_store.cpython-38.pyc,,
+cachy/stores/__pycache__/file_store.cpython-38.pyc,,
+cachy/stores/__pycache__/memcached_store.cpython-38.pyc,,
+cachy/stores/__pycache__/null_store.cpython-38.pyc,,
+cachy/stores/__pycache__/redis_store.cpython-38.pyc,,
+cachy/stores/dict_store.py,sha256=Y8QN_yg3yzq6QxaX24Sg62lRLt0qODTV-XdVuosaNpw,3700
+cachy/stores/file_store.py,sha256=5RakbtGquztkcPBtYGg7GQ64R0lG9638zFgwbZ2TcvQ,5806
+cachy/stores/memcached_store.py,sha256=hZ1bMNDqj49eRKN3rCpO80j4XVfm1jbddyFRWIXGXRA,2984
+cachy/stores/null_store.py,sha256=2kYMfN4G9TlrAH7YMx60TT3BmNwfEA2z1AezMJcL_gk,2026
+cachy/stores/redis_store.py,sha256=0qHMDEDXxo0BIwPa1kjrSCJaeFTTipabo4yQTTSzivs,3318
+cachy/tag_set.py,sha256=R7kJUapYsd5zsnQ4MoWL9E9XgCuhUGdHXwcccpJEtwM,1665
+cachy/tagged_cache.py,sha256=A7yl7jVdMyITIM8P3aL-X_OAuEmHQP8XPz2jNMdtbzM,5835
+cachy/utils.py,sha256=w2JpCwjLDE-GpdUyuRnkQA4hXyj-cml9etZ4ReuSQGQ,1309
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..9a6b358
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/cache_manager.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/cache_manager.cpython-38.pyc
new file mode 100644
index 0000000..b9b4afe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/cache_manager.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/helpers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/helpers.cpython-38.pyc
new file mode 100644
index 0000000..eae6d5f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/helpers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/redis_tagged_cache.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/redis_tagged_cache.cpython-38.pyc
new file mode 100644
index 0000000..1d72018
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/redis_tagged_cache.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/repository.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/repository.cpython-38.pyc
new file mode 100644
index 0000000..0533cc2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/repository.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/tag_set.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/tag_set.cpython-38.pyc
new file mode 100644
index 0000000..14f050b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/tag_set.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/tagged_cache.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/tagged_cache.cpython-38.pyc
new file mode 100644
index 0000000..e29406b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/tagged_cache.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/__pycache__/utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/__pycache__/utils.cpython-38.pyc
new file mode 100644
index 0000000..30029c9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..0dac16d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/factory.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/factory.cpython-38.pyc
new file mode 100644
index 0000000..a7b9ef8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/factory.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/repository.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/repository.cpython-38.pyc
new file mode 100644
index 0000000..9518a08
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/repository.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/store.cpython-38.pyc
new file mode 100644
index 0000000..5502822
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/taggable_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/taggable_store.cpython-38.pyc
new file mode 100644
index 0000000..abfa15a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/contracts/__pycache__/taggable_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..eb58723
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/json_serializer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/json_serializer.cpython-38.pyc
new file mode 100644
index 0000000..fc70718
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/json_serializer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/msgpack_serializer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/msgpack_serializer.cpython-38.pyc
new file mode 100644
index 0000000..35a8fea
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/msgpack_serializer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/pickle_serializer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/pickle_serializer.cpython-38.pyc
new file mode 100644
index 0000000..ce86f92
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/pickle_serializer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/serializer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/serializer.cpython-38.pyc
new file mode 100644
index 0000000..ff05273
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/serializers/__pycache__/serializer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..10f9ae1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/dict_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/dict_store.cpython-38.pyc
new file mode 100644
index 0000000..870ef85
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/dict_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/file_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/file_store.cpython-38.pyc
new file mode 100644
index 0000000..efd83ca
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/file_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/memcached_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/memcached_store.cpython-38.pyc
new file mode 100644
index 0000000..fccf351
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/memcached_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/null_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/null_store.cpython-38.pyc
new file mode 100644
index 0000000..c9c74e4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/null_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/redis_store.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/redis_store.cpython-38.pyc
new file mode 100644
index 0000000..9b20e6c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cachy/stores/__pycache__/redis_store.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/certifi-2021.10.8.dist-info/RECORD b/venv/lib64/python3.8/site-packages/certifi-2021.10.8.dist-info/RECORD
new file mode 100644
index 0000000..8bc571d
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/certifi-2021.10.8.dist-info/RECORD
@@ -0,0 +1,13 @@
+certifi-2021.10.8.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+certifi-2021.10.8.dist-info/LICENSE,sha256=vp2C82ES-Hp_HXTs1Ih-FGe7roh4qEAEoAEXseR1o-I,1049
+certifi-2021.10.8.dist-info/METADATA,sha256=iB_zbT1uX_8_NC7iGv0YEB-9b3idhQwHrFTSq8R1kD8,2994
+certifi-2021.10.8.dist-info/RECORD,,
+certifi-2021.10.8.dist-info/WHEEL,sha256=ADKeyaGyKF5DwBNE0sRE5pvW-bSkFMJfBuhzZ3rceP4,110
+certifi-2021.10.8.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8
+certifi/__init__.py,sha256=xWdRgntT3j1V95zkRipGOg_A1UfEju2FcpujhysZLRI,62
+certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243
+certifi/__pycache__/__init__.cpython-38.pyc,,
+certifi/__pycache__/__main__.cpython-38.pyc,,
+certifi/__pycache__/core.cpython-38.pyc,,
+certifi/cacert.pem,sha256=-og4Keu4zSpgL5shwfhd4kz0eUnVILzrGCi0zRy2kGw,265969
+certifi/core.py,sha256=V0uyxKOYdz6ulDSusclrLmjbPgOXsD0BnEf0SQ7OnoE,2303
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..9da4ec9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/api.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/api.cpython-38.pyc
new file mode 100644
index 0000000..c876083
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/api.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/backend_ctypes.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/backend_ctypes.cpython-38.pyc
new file mode 100644
index 0000000..bc6d860
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/backend_ctypes.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/cffi_opcode.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/cffi_opcode.cpython-38.pyc
new file mode 100644
index 0000000..5326bc9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/cffi_opcode.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/commontypes.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/commontypes.cpython-38.pyc
new file mode 100644
index 0000000..29e4d4b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/commontypes.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/cparser.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/cparser.cpython-38.pyc
new file mode 100644
index 0000000..d1b09fe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/cparser.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/error.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/error.cpython-38.pyc
new file mode 100644
index 0000000..17e2924
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/error.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/ffiplatform.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/ffiplatform.cpython-38.pyc
new file mode 100644
index 0000000..78a62c8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/ffiplatform.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/lock.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/lock.cpython-38.pyc
new file mode 100644
index 0000000..f3c6f46
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/lock.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/model.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/model.cpython-38.pyc
new file mode 100644
index 0000000..caa9ac7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/model.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/pkgconfig.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/pkgconfig.cpython-38.pyc
new file mode 100644
index 0000000..a82b7ea
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/pkgconfig.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/recompiler.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/recompiler.cpython-38.pyc
new file mode 100644
index 0000000..ec1d31f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/recompiler.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/setuptools_ext.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/setuptools_ext.cpython-38.pyc
new file mode 100644
index 0000000..f8473f4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/setuptools_ext.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_cpy.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_cpy.cpython-38.pyc
new file mode 100644
index 0000000..052206d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_cpy.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_gen.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_gen.cpython-38.pyc
new file mode 100644
index 0000000..9a8d4dc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/vengine_gen.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cffi/__pycache__/verifier.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cffi/__pycache__/verifier.cpython-38.pyc
new file mode 100644
index 0000000..c4a6316
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cffi/__pycache__/verifier.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER b/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD b/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD
new file mode 100644
index 0000000..03a9c74
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/chardet-3.0.4.dist-info/RECORD
@@ -0,0 +1,91 @@
+../../../bin/chardetect,sha256=xGOtRC9bH4Njk5bR4U6EseCjckcXHcCD7m6lwrycVOk,240
+chardet-3.0.4.dist-info/DESCRIPTION.rst,sha256=PQ4sBsMyKFZkjC6QpmbpLn0UtCNyeb-ZqvCGEgyZMGk,2174
+chardet-3.0.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+chardet-3.0.4.dist-info/METADATA,sha256=RV_2I4B1Z586DL8oVO5Kp7X5bUdQ5EuKAvNoAEF8wSw,3239
+chardet-3.0.4.dist-info/RECORD,,
+chardet-3.0.4.dist-info/WHEEL,sha256=o2k-Qa-RMNIJmUdIc7KU6VWR_ErNRbWNlxDIpl7lm34,110
+chardet-3.0.4.dist-info/entry_points.txt,sha256=fAMmhu5eJ-zAJ-smfqQwRClQ3-nozOCmvJ6-E8lgGJo,60
+chardet-3.0.4.dist-info/metadata.json,sha256=0htbRM18ujyGZDdfowgAqj6Hq2eQtwzwyhaEveKntgo,1375
+chardet-3.0.4.dist-info/top_level.txt,sha256=AowzBbZy4x8EirABDdJSLJZMkJ_53iIag8xfKR6D7kI,8
+chardet/__init__.py,sha256=YsP5wQlsHJ2auF1RZJfypiSrCA7_bQiRm3ES_NI76-Y,1559
+chardet/__pycache__/__init__.cpython-38.pyc,,
+chardet/__pycache__/big5freq.cpython-38.pyc,,
+chardet/__pycache__/big5prober.cpython-38.pyc,,
+chardet/__pycache__/chardistribution.cpython-38.pyc,,
+chardet/__pycache__/charsetgroupprober.cpython-38.pyc,,
+chardet/__pycache__/charsetprober.cpython-38.pyc,,
+chardet/__pycache__/codingstatemachine.cpython-38.pyc,,
+chardet/__pycache__/compat.cpython-38.pyc,,
+chardet/__pycache__/cp949prober.cpython-38.pyc,,
+chardet/__pycache__/enums.cpython-38.pyc,,
+chardet/__pycache__/escprober.cpython-38.pyc,,
+chardet/__pycache__/escsm.cpython-38.pyc,,
+chardet/__pycache__/eucjpprober.cpython-38.pyc,,
+chardet/__pycache__/euckrfreq.cpython-38.pyc,,
+chardet/__pycache__/euckrprober.cpython-38.pyc,,
+chardet/__pycache__/euctwfreq.cpython-38.pyc,,
+chardet/__pycache__/euctwprober.cpython-38.pyc,,
+chardet/__pycache__/gb2312freq.cpython-38.pyc,,
+chardet/__pycache__/gb2312prober.cpython-38.pyc,,
+chardet/__pycache__/hebrewprober.cpython-38.pyc,,
+chardet/__pycache__/jisfreq.cpython-38.pyc,,
+chardet/__pycache__/jpcntx.cpython-38.pyc,,
+chardet/__pycache__/langbulgarianmodel.cpython-38.pyc,,
+chardet/__pycache__/langcyrillicmodel.cpython-38.pyc,,
+chardet/__pycache__/langgreekmodel.cpython-38.pyc,,
+chardet/__pycache__/langhebrewmodel.cpython-38.pyc,,
+chardet/__pycache__/langhungarianmodel.cpython-38.pyc,,
+chardet/__pycache__/langthaimodel.cpython-38.pyc,,
+chardet/__pycache__/langturkishmodel.cpython-38.pyc,,
+chardet/__pycache__/latin1prober.cpython-38.pyc,,
+chardet/__pycache__/mbcharsetprober.cpython-38.pyc,,
+chardet/__pycache__/mbcsgroupprober.cpython-38.pyc,,
+chardet/__pycache__/mbcssm.cpython-38.pyc,,
+chardet/__pycache__/sbcharsetprober.cpython-38.pyc,,
+chardet/__pycache__/sbcsgroupprober.cpython-38.pyc,,
+chardet/__pycache__/sjisprober.cpython-38.pyc,,
+chardet/__pycache__/universaldetector.cpython-38.pyc,,
+chardet/__pycache__/utf8prober.cpython-38.pyc,,
+chardet/__pycache__/version.cpython-38.pyc,,
+chardet/big5freq.py,sha256=D_zK5GyzoVsRes0HkLJziltFQX0bKCLOrFe9_xDvO_8,31254
+chardet/big5prober.py,sha256=kBxHbdetBpPe7xrlb-e990iot64g_eGSLd32lB7_h3M,1757
+chardet/chardistribution.py,sha256=3woWS62KrGooKyqz4zQSnjFbJpa6V7g02daAibTwcl8,9411
+chardet/charsetgroupprober.py,sha256=6bDu8YIiRuScX4ca9Igb0U69TA2PGXXDej6Cc4_9kO4,3787
+chardet/charsetprober.py,sha256=KSmwJErjypyj0bRZmC5F5eM7c8YQgLYIjZXintZNstg,5110
+chardet/cli/__init__.py,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
+chardet/cli/__pycache__/__init__.cpython-38.pyc,,
+chardet/cli/__pycache__/chardetect.cpython-38.pyc,,
+chardet/cli/chardetect.py,sha256=YBO8L4mXo0WR6_-Fjh_8QxPBoEBNqB9oNxNrdc54AQs,2738
+chardet/codingstatemachine.py,sha256=VYp_6cyyki5sHgXDSZnXW4q1oelHc3cu9AyQTX7uug8,3590
+chardet/compat.py,sha256=PKTzHkSbtbHDqS9PyujMbX74q1a8mMpeQTDVsQhZMRw,1134
+chardet/cp949prober.py,sha256=TZ434QX8zzBsnUvL_8wm4AQVTZ2ZkqEEQL_lNw9f9ow,1855
+chardet/enums.py,sha256=Aimwdb9as1dJKZaFNUH2OhWIVBVd6ZkJJ_WK5sNY8cU,1661
+chardet/escprober.py,sha256=kkyqVg1Yw3DIOAMJ2bdlyQgUFQhuHAW8dUGskToNWSc,3950
+chardet/escsm.py,sha256=RuXlgNvTIDarndvllNCk5WZBIpdCxQ0kcd9EAuxUh84,10510
+chardet/eucjpprober.py,sha256=iD8Jdp0ISRjgjiVN7f0e8xGeQJ5GM2oeZ1dA8nbSeUw,3749
+chardet/euckrfreq.py,sha256=-7GdmvgWez4-eO4SuXpa7tBiDi5vRXQ8WvdFAzVaSfo,13546
+chardet/euckrprober.py,sha256=MqFMTQXxW4HbzIpZ9lKDHB3GN8SP4yiHenTmf8g_PxY,1748
+chardet/euctwfreq.py,sha256=No1WyduFOgB5VITUA7PLyC5oJRNzRyMbBxaKI1l16MA,31621
+chardet/euctwprober.py,sha256=13p6EP4yRaxqnP4iHtxHOJ6R2zxHq1_m8hTRjzVZ95c,1747
+chardet/gb2312freq.py,sha256=JX8lsweKLmnCwmk8UHEQsLgkr_rP_kEbvivC4qPOrlc,20715
+chardet/gb2312prober.py,sha256=gGvIWi9WhDjE-xQXHvNIyrnLvEbMAYgyUSZ65HUfylw,1754
+chardet/hebrewprober.py,sha256=c3SZ-K7hvyzGY6JRAZxJgwJ_sUS9k0WYkvMY00YBYFo,13838
+chardet/jisfreq.py,sha256=vpmJv2Bu0J8gnMVRPHMFefTRvo_ha1mryLig8CBwgOg,25777
+chardet/jpcntx.py,sha256=PYlNqRUQT8LM3cT5FmHGP0iiscFlTWED92MALvBungo,19643
+chardet/langbulgarianmodel.py,sha256=1HqQS9Pbtnj1xQgxitJMvw8X6kKr5OockNCZWfEQrPE,12839
+chardet/langcyrillicmodel.py,sha256=LODajvsetH87yYDDQKA2CULXUH87tI223dhfjh9Zx9c,17948
+chardet/langgreekmodel.py,sha256=8YAW7bU8YwSJap0kIJSbPMw1BEqzGjWzqcqf0WgUKAA,12688
+chardet/langhebrewmodel.py,sha256=JSnqmE5E62tDLTPTvLpQsg5gOMO4PbdWRvV7Avkc0HA,11345
+chardet/langhungarianmodel.py,sha256=RhapYSG5l0ZaO-VV4Fan5sW0WRGQqhwBM61yx3yxyOA,12592
+chardet/langthaimodel.py,sha256=8l0173Gu_W6G8mxmQOTEF4ls2YdE7FxWf3QkSxEGXJQ,11290
+chardet/langturkishmodel.py,sha256=W22eRNJsqI6uWAfwXSKVWWnCerYqrI8dZQTm_M0lRFk,11102
+chardet/latin1prober.py,sha256=S2IoORhFk39FEFOlSFWtgVybRiP6h7BlLldHVclNkU8,5370
+chardet/mbcharsetprober.py,sha256=AR95eFH9vuqSfvLQZN-L5ijea25NOBCoXqw8s5O9xLQ,3413
+chardet/mbcsgroupprober.py,sha256=h6TRnnYq2OxG1WdD5JOyxcdVpn7dG0q-vB8nWr5mbh4,2012
+chardet/mbcssm.py,sha256=SY32wVIF3HzcjY3BaEspy9metbNSKxIIB0RKPn7tjpI,25481
+chardet/sbcharsetprober.py,sha256=LDSpCldDCFlYwUkGkwD2oFxLlPWIWXT09akH_2PiY74,5657
+chardet/sbcsgroupprober.py,sha256=1IprcCB_k1qfmnxGC6MBbxELlKqD3scW6S8YIwdeyXA,3546
+chardet/sjisprober.py,sha256=IIt-lZj0WJqK4rmUZzKZP4GJlE8KUEtFYVuY96ek5MQ,3774
+chardet/universaldetector.py,sha256=qL0174lSZE442eB21nnktT9_VcAye07laFWUeUrjttY,12485
+chardet/utf8prober.py,sha256=IdD8v3zWOsB8OLiyPi-y_fqwipRFxV9Nc1eKBLSuIEw,2766
+chardet/version.py,sha256=sp3B08mrDXB-pf3K9fqJ_zeDHOCLC8RrngQyDFap_7g,242
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..a6cc37b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5freq.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5freq.cpython-38.pyc
new file mode 100644
index 0000000..955be46
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5freq.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5prober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5prober.cpython-38.pyc
new file mode 100644
index 0000000..c572337
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/big5prober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/chardistribution.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/chardistribution.cpython-38.pyc
new file mode 100644
index 0000000..289b47a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/chardistribution.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetgroupprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetgroupprober.cpython-38.pyc
new file mode 100644
index 0000000..0c5cf12
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetgroupprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetprober.cpython-38.pyc
new file mode 100644
index 0000000..1d779e4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/charsetprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/codingstatemachine.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/codingstatemachine.cpython-38.pyc
new file mode 100644
index 0000000..58c2b6c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/codingstatemachine.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/compat.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/compat.cpython-38.pyc
new file mode 100644
index 0000000..51381b3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/cp949prober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/cp949prober.cpython-38.pyc
new file mode 100644
index 0000000..935761c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/cp949prober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/enums.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/enums.cpython-38.pyc
new file mode 100644
index 0000000..1ca3954
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/enums.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/escprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/escprober.cpython-38.pyc
new file mode 100644
index 0000000..a849b2d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/escprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/escsm.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/escsm.cpython-38.pyc
new file mode 100644
index 0000000..8573cd6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/escsm.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/eucjpprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/eucjpprober.cpython-38.pyc
new file mode 100644
index 0000000..b15d222
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/eucjpprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrfreq.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrfreq.cpython-38.pyc
new file mode 100644
index 0000000..1dc4770
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrfreq.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrprober.cpython-38.pyc
new file mode 100644
index 0000000..b0c0f6f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euckrprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwfreq.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwfreq.cpython-38.pyc
new file mode 100644
index 0000000..1a197f6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwfreq.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwprober.cpython-38.pyc
new file mode 100644
index 0000000..7f87e8e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/euctwprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312freq.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312freq.cpython-38.pyc
new file mode 100644
index 0000000..b3443c0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312freq.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312prober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312prober.cpython-38.pyc
new file mode 100644
index 0000000..bce1ac1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/gb2312prober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/hebrewprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/hebrewprober.cpython-38.pyc
new file mode 100644
index 0000000..c198fba
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/hebrewprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/jisfreq.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/jisfreq.cpython-38.pyc
new file mode 100644
index 0000000..112a274
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/jisfreq.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/jpcntx.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/jpcntx.cpython-38.pyc
new file mode 100644
index 0000000..339b5fb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/jpcntx.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc
new file mode 100644
index 0000000..1a23197
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langbulgarianmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc
new file mode 100644
index 0000000..eb83a80
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langcyrillicmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langgreekmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langgreekmodel.cpython-38.pyc
new file mode 100644
index 0000000..bff548c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langgreekmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhebrewmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhebrewmodel.cpython-38.pyc
new file mode 100644
index 0000000..f4ae693
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhebrewmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhungarianmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhungarianmodel.cpython-38.pyc
new file mode 100644
index 0000000..f5206bb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langhungarianmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langthaimodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langthaimodel.cpython-38.pyc
new file mode 100644
index 0000000..33e00bd
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langthaimodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/langturkishmodel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langturkishmodel.cpython-38.pyc
new file mode 100644
index 0000000..87732d2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/langturkishmodel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/latin1prober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/latin1prober.cpython-38.pyc
new file mode 100644
index 0000000..61873e6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/latin1prober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcharsetprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcharsetprober.cpython-38.pyc
new file mode 100644
index 0000000..4507696
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcharsetprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc
new file mode 100644
index 0000000..88a9948
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcsgroupprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcssm.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcssm.cpython-38.pyc
new file mode 100644
index 0000000..38b4b1c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/mbcssm.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcharsetprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcharsetprober.cpython-38.pyc
new file mode 100644
index 0000000..94e0da0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcharsetprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc
new file mode 100644
index 0000000..73ac214
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sbcsgroupprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/sjisprober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sjisprober.cpython-38.pyc
new file mode 100644
index 0000000..518e7dd
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/sjisprober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/universaldetector.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/universaldetector.cpython-38.pyc
new file mode 100644
index 0000000..4fc08a2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/universaldetector.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/utf8prober.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/utf8prober.cpython-38.pyc
new file mode 100644
index 0000000..0ba3757
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/utf8prober.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/__pycache__/version.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/__pycache__/version.cpython-38.pyc
new file mode 100644
index 0000000..50e2121
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..4b11595
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/chardetect.cpython-38.pyc b/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/chardetect.cpython-38.pyc
new file mode 100644
index 0000000..8a246a1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/chardet/cli/__pycache__/chardetect.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..abb4e98
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/__pycache__/_compat.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/__pycache__/_compat.cpython-38.pyc
new file mode 100644
index 0000000..8db2e14
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/__pycache__/_compat.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/__pycache__/application.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/__pycache__/application.cpython-38.pyc
new file mode 100644
index 0000000..d3b6e77
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/__pycache__/application.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/__pycache__/helpers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/__pycache__/helpers.cpython-38.pyc
new file mode 100644
index 0000000..8496f43
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/__pycache__/helpers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/__pycache__/parser.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/__pycache__/parser.cpython-38.pyc
new file mode 100644
index 0000000..95a9b2d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/__pycache__/parser.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..920fdde
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/base_command.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/base_command.cpython-38.pyc
new file mode 100644
index 0000000..90f6255
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/base_command.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/command.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/command.cpython-38.pyc
new file mode 100644
index 0000000..3f7b9a0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/command.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/completions_command.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/completions_command.cpython-38.pyc
new file mode 100644
index 0000000..28fa4d1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/__pycache__/completions_command.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..75446b7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/templates.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/templates.cpython-38.pyc
new file mode 100644
index 0000000..a058b68
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/commands/completions/__pycache__/templates.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..59afa8c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/application_config.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/application_config.cpython-38.pyc
new file mode 100644
index 0000000..ccbfc3a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/config/__pycache__/application_config.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..dee60e4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/buffered_io.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/buffered_io.cpython-38.pyc
new file mode 100644
index 0000000..a936df0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/buffered_io.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/console_io.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/console_io.cpython-38.pyc
new file mode 100644
index 0000000..75a203f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/console_io.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/io_mixin.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/io_mixin.cpython-38.pyc
new file mode 100644
index 0000000..32d2472
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/io/__pycache__/io_mixin.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..1622999
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/application_tester.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/application_tester.cpython-38.pyc
new file mode 100644
index 0000000..d47fcc6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/application_tester.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/command_tester.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/command_tester.cpython-38.pyc
new file mode 100644
index 0000000..be304a1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cleo/testers/__pycache__/command_tester.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/clikit-0.6.2.dist-info/RECORD b/venv/lib64/python3.8/site-packages/clikit-0.6.2.dist-info/RECORD
new file mode 100644
index 0000000..b2253f9
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/clikit-0.6.2.dist-info/RECORD
@@ -0,0 +1,255 @@
+clikit-0.6.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+clikit-0.6.2.dist-info/LICENSE,sha256=8vm0YLpxnaZiat0mTTeC8nWk_3qrZ3vtoIszCRHiOts,1062
+clikit-0.6.2.dist-info/METADATA,sha256=VQIBgL3IqQgxgXx87aCwJD8YktAA1q3aRyfwuJr2fr4,1581
+clikit-0.6.2.dist-info/RECORD,,
+clikit-0.6.2.dist-info/WHEEL,sha256=BcHwX75L5o9y8NN94BU-O_IP_7AP-vrh-M6RWGoded0,87
+clikit/__init__.py,sha256=672ya2xDu_gkHfPFkW8oh4YATmywus0kDO_H5-IvsCw,208
+clikit/__pycache__/__init__.cpython-38.pyc,,
+clikit/__pycache__/console_application.cpython-38.pyc,,
+clikit/adapter/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+clikit/adapter/__pycache__/__init__.cpython-38.pyc,,
+clikit/adapter/__pycache__/style_converter.cpython-38.pyc,,
+clikit/adapter/style_converter.py,sha256=jdauKvcNCaSF_LatoaO942wU00Sh24aY-74hq4IEcR8,860
+clikit/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+clikit/api/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/__pycache__/exceptions.cpython-38.pyc,,
+clikit/api/application/__init__.py,sha256=FoOc_AS7QiydMuCon44T4ZiOCyIEjr27cH5uT618-OE,37
+clikit/api/application/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/application/__pycache__/application.cpython-38.pyc,,
+clikit/api/application/application.py,sha256=Tv2Me8HWf44ULl7kh59qctwvnr-rr1nP4fo-S5XbR68,1775
+clikit/api/args/__init__.py,sha256=sZQSI_WC4tcrpqsuxnEcAYeS1ZbcOTxWJYgI9sheTcs,89
+clikit/api/args/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/args/__pycache__/args.cpython-38.pyc,,
+clikit/api/args/__pycache__/args_parser.cpython-38.pyc,,
+clikit/api/args/__pycache__/exceptions.cpython-38.pyc,,
+clikit/api/args/__pycache__/raw_args.cpython-38.pyc,,
+clikit/api/args/args.py,sha256=3OQ5m6dWfShmQxbNqwgAJg9gsx20dASMd4S7C_IFP5Y,3837
+clikit/api/args/args_parser.py,sha256=chddl-5uf83oreakhusFWAFWZstuTgdTIbslWHY_Q1M,350
+clikit/api/args/exceptions.py,sha256=FSRjsZQJHf2EhDDLQZG3ehy7KnDVYnFjGgDNTvilZZA,1999
+clikit/api/args/format/__init__.py,sha256=GgBjypUc6-OOeOXxZcavu5l7Qu_OdlqKcusTGHZHIZE,225
+clikit/api/args/format/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/abstract_option.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/args_format.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/args_format_builder.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/argument.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/command_name.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/command_option.cpython-38.pyc,,
+clikit/api/args/format/__pycache__/option.cpython-38.pyc,,
+clikit/api/args/format/abstract_option.py,sha256=zzqZ7dhBy-ZQKPyM-ixf-1dkvhD2h34xXhuS2gRLsfc,4360
+clikit/api/args/format/args_format.py,sha256=da0dG9Q79t-_j-m_LoThPA7w5HIvjYs55Gvrn2lhQ2c,8371
+clikit/api/args/format/args_format_builder.py,sha256=VaJl79nHpdnqz6fm6eJmuCAJNtBkjDKN8bWBq89lKQw,11308
+clikit/api/args/format/argument.py,sha256=mMYpY--eJqd5CNQpHrLGPFzVohMVXcg7-CnQtu2RR_E,5222
+clikit/api/args/format/command_name.py,sha256=R5mHuudJ0sKy47qVBMpQhI2cBaDdqTvvATsWRgJQo14,828
+clikit/api/args/format/command_option.py,sha256=tBMRIm2eAVEpYDh_GPmyDbhKq9xpjvn7g8bpWWyrXqg,1792
+clikit/api/args/format/option.py,sha256=NbSSFjH6ujR0a16_AZf-mT3dcYnozGW5dANidoEiNDA,5312
+clikit/api/args/raw_args.py,sha256=lmtJHySybizLekRblhyfjApOGg50da2GlQc0Eh02yHc,812
+clikit/api/command/__init__.py,sha256=0791MZSWZM0hNoIp54JgGEolyRxZVvbrshEmrGneAbo,79
+clikit/api/command/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/command/__pycache__/command.cpython-38.pyc,,
+clikit/api/command/__pycache__/command_collection.cpython-38.pyc,,
+clikit/api/command/__pycache__/exceptions.cpython-38.pyc,,
+clikit/api/command/command.py,sha256=n4CyIcKpA02tL-u_hagjN5NQy3tbGHGiJLGu_VLxNag,5500
+clikit/api/command/command_collection.py,sha256=DgOihRbOFw9YxAo0DJlKXLdic_J2160eqCRCK1HJ5Fw,1930
+clikit/api/command/exceptions.py,sha256=cur-caKkWd7PkKgOjL725CwrO4lUGXOtE1zo1vx2ugY,683
+clikit/api/config/__init__.py,sha256=eyPIKClyLxlsbmAGfRAmUT1ZnnqNmiXNYd8mMMtZn30,92
+clikit/api/config/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/config/__pycache__/application_config.cpython-38.pyc,,
+clikit/api/config/__pycache__/command_config.cpython-38.pyc,,
+clikit/api/config/__pycache__/config.cpython-38.pyc,,
+clikit/api/config/application_config.py,sha256=N_LDUeYWbBv_GNNuv1W4GovBGUGCQvT-jWNbr0TUr2E,7640
+clikit/api/config/command_config.py,sha256=9hO6llUVX0x2z13EkAJB06XJruZBzbiEA9CJo8K7kaA,7280
+clikit/api/config/config.py,sha256=2ifrvAYJ7XnUj2-hmP8azD8tjGvooPnRHadZymBzHJk,4101
+clikit/api/event/__init__.py,sha256=iK44q99DJj6jI3-FSTbg87ZKSDQKpxuZfjhDazzElHk,315
+clikit/api/event/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/event/__pycache__/config_event.cpython-38.pyc,,
+clikit/api/event/__pycache__/console_events.cpython-38.pyc,,
+clikit/api/event/__pycache__/event.cpython-38.pyc,,
+clikit/api/event/__pycache__/event_dispatcher.cpython-38.pyc,,
+clikit/api/event/__pycache__/pre_handle_event.cpython-38.pyc,,
+clikit/api/event/__pycache__/pre_resolve_event.cpython-38.pyc,,
+clikit/api/event/config_event.py,sha256=gQVVvrRueYvV0z3OQCNR7Fhi84MgjjBVW0zn6Ha7UVI,384
+clikit/api/event/console_events.py,sha256=RHK8n_BGZZ3toZBrqgaEGk1Wg-dLz760h17dg1uO7bc,74
+clikit/api/event/event.py,sha256=pJPgJesyg5JX8PPA2-zi5kHUk3AbDXXgCyIYBuGtJmo,328
+clikit/api/event/event_dispatcher.py,sha256=RZvQ1BiYj4l3cb5H0crn6YRT5_T_oOO8cXq0qEIbusg,3055
+clikit/api/event/pre_handle_event.py,sha256=EoFIuh1I_R0T5vF7je0dDVG9pU5PYNhNZjHsAOPdcEU,1166
+clikit/api/event/pre_resolve_event.py,sha256=vs6LUs0Yq1pJKCcqjw7X2xcf6gip75BQXpKtMYwu_u8,1049
+clikit/api/exceptions.py,sha256=vWBJqhYXNFBgg4rIIKN07hPiA42HmvqUSz1j9s1N6oA,97
+clikit/api/formatter/__init__.py,sha256=qyU1_SK11VRjYiwty4WTK9g5XtftpTHMPG7YUOsmW_8,90
+clikit/api/formatter/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/formatter/__pycache__/formatter.cpython-38.pyc,,
+clikit/api/formatter/__pycache__/style.cpython-38.pyc,,
+clikit/api/formatter/__pycache__/style_set.cpython-38.pyc,,
+clikit/api/formatter/formatter.py,sha256=mWprIFsHO6DYF0vrA8H7FACr-GnEruTLsY-Y1W8Czgs,665
+clikit/api/formatter/style.py,sha256=lmvl2iEc26IWQO-bhS5JJT-Gemt1mkMG_xfQD2mcvC0,2810
+clikit/api/formatter/style_set.py,sha256=9MJO-uadkgbUkMtxyynlUpvh9-9DezEuEU0CN2ig-no,981
+clikit/api/io/__init__.py,sha256=wFO8kFY6aNF0NycVG4AYe5J_A5LtFv8O6ivFQJJk-SU,187
+clikit/api/io/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/io/__pycache__/flags.cpython-38.pyc,,
+clikit/api/io/__pycache__/input.cpython-38.pyc,,
+clikit/api/io/__pycache__/input_stream.cpython-38.pyc,,
+clikit/api/io/__pycache__/io.cpython-38.pyc,,
+clikit/api/io/__pycache__/io_exception.cpython-38.pyc,,
+clikit/api/io/__pycache__/output.cpython-38.pyc,,
+clikit/api/io/__pycache__/output_stream.cpython-38.pyc,,
+clikit/api/io/__pycache__/section_output.cpython-38.pyc,,
+clikit/api/io/flags.py,sha256=BxVtAqib2JKrxa8enKb7jgPHrbowS3Jh1wpmM1Uxwe8,254
+clikit/api/io/input.py,sha256=TmKlYFDII96sH3oM_7JAYn6x7i4Mq8imRrOItVcmzLM,1867
+clikit/api/io/input_stream.py,sha256=vPrnCvz7DYubNqUCt6ggzUgSXa-PoGi8ifKKcaDest0,731
+clikit/api/io/io.py,sha256=_t1qM3sWJB6nky1s77fl7R8Zqq2vSEgI6HowdWJ9jH0,6991
+clikit/api/io/io_exception.py,sha256=23tAhDkTgMpZw3AVHAQtwDsLxrMcSEmFDqhAj0zaU1M,92
+clikit/api/io/output.py,sha256=wuqKMJ0nsga5Brx0i1rSsSwqttnkYNrbSRqX7fs7Gjw,6291
+clikit/api/io/output_stream.py,sha256=37S8vcrlh1GJgwWKN05w3N9Us1mvDj-uJuNfDeSD1U0,857
+clikit/api/io/section_output.py,sha256=sRj6HRSCHm6RrI_m4UEDImshBDO45EniRXbhQeekVBY,3088
+clikit/api/resolver/__init__.py,sha256=8Jatu87gG0XzW9Gc6u-W4TWbtsnDJvsTc_fitbIYJwA,92
+clikit/api/resolver/__pycache__/__init__.cpython-38.pyc,,
+clikit/api/resolver/__pycache__/command_resolver.cpython-38.pyc,,
+clikit/api/resolver/__pycache__/exceptions.cpython-38.pyc,,
+clikit/api/resolver/__pycache__/resolved_command.cpython-38.pyc,,
+clikit/api/resolver/command_resolver.py,sha256=tJzXF9CmCkYuHmeq3rCJ848gDcOZwE-eqCUGAKUV4lg,344
+clikit/api/resolver/exceptions.py,sha256=s5syhgaE4KsacyBfPj3wLCBIqSp4QdYfqT02btZ8o34,779
+clikit/api/resolver/resolved_command.py,sha256=mS0sHUQ-P9BMRv6eP-iCvfsdOeEVbqmCuB-FitsIpps,447
+clikit/args/__init__.py,sha256=YuDLMbpDBTRRX8RsDGFwqp9Qi83P0x_U2s9pAQQguRs,119
+clikit/args/__pycache__/__init__.cpython-38.pyc,,
+clikit/args/__pycache__/argv_args.cpython-38.pyc,,
+clikit/args/__pycache__/default_args_parser.cpython-38.pyc,,
+clikit/args/__pycache__/string_args.cpython-38.pyc,,
+clikit/args/__pycache__/token_parser.cpython-38.pyc,,
+clikit/args/argv_args.py,sha256=7FiSchlyhz40VzsYK7uJsaSO4XD9x05chjDVLKAppwI,1262
+clikit/args/default_args_parser.py,sha256=B_F9Mn3G8RC6dPRPxKT2qlfsq7Vk0o-KVslXObl0oy8,11723
+clikit/args/inputs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+clikit/args/inputs/__pycache__/__init__.cpython-38.pyc,,
+clikit/args/string_args.py,sha256=YSQnT9_KSKqnNwibwJ6VhDBFJ9VIbwBA88iMrIH2ScI,1067
+clikit/args/token_parser.py,sha256=8LW5qEck6mEwcwgfPBwwGTo1tfu88q5P7zNDFIrvRRQ,3031
+clikit/config/__init__.py,sha256=dxmVY0lZ0-Htf-Kkm7MnrFW541lkeeIBnQG10Q5y0LI,65
+clikit/config/__pycache__/__init__.cpython-38.pyc,,
+clikit/config/__pycache__/default_application_config.cpython-38.pyc,,
+clikit/config/default_application_config.py,sha256=lhKuZosg23WQ9V4H7nsNoVckCVXc18E13sxMAjqZK5w,5874
+clikit/console_application.py,sha256=quUwTfCWa402UgJLp3Lyn-6f4v8KUFyAhsdGIMecQbg,6000
+clikit/formatter/__init__.py,sha256=5goy4-OUK8L7uUmsrpkFLdQjlRAqktlYyzu1D5qYMmI,175
+clikit/formatter/__pycache__/__init__.cpython-38.pyc,,
+clikit/formatter/__pycache__/ansi_formatter.cpython-38.pyc,,
+clikit/formatter/__pycache__/default_style_set.cpython-38.pyc,,
+clikit/formatter/__pycache__/null_formatter.cpython-38.pyc,,
+clikit/formatter/__pycache__/plain_formatter.cpython-38.pyc,,
+clikit/formatter/ansi_formatter.py,sha256=1PI5JSHWVXuTmFIM0LUaGtpYNAFbJ-_fuCAD4STLF-8,1868
+clikit/formatter/default_style_set.py,sha256=FByMJFRdM4sBTusTQUM3tm8AWD0c9jKSSS4EdFLGyZM,600
+clikit/formatter/null_formatter.py,sha256=S13YSVuwaoqpcWr-wnGg0DcvegSC7HJ-c-uVMSnUjbw,496
+clikit/formatter/plain_formatter.py,sha256=AFGtMvG_2bUpfKia7I8zxEKZzLd2nJlU0C5hcGldXCg,1533
+clikit/handler/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+clikit/handler/__pycache__/__init__.cpython-38.pyc,,
+clikit/handler/__pycache__/callback_handler.cpython-38.pyc,,
+clikit/handler/callback_handler.py,sha256=mkmYrJKbU9sEsQBXe5xV-V4o6EZUz-76vy2Z54M09lY,385
+clikit/handler/help/__init__.py,sha256=g6dt8GiW2Nw6S2KDpGB86L4H9fnvmQY4ha9IphC9AJU,47
+clikit/handler/help/__pycache__/__init__.cpython-38.pyc,,
+clikit/handler/help/__pycache__/help_handler.cpython-38.pyc,,
+clikit/handler/help/__pycache__/help_text_handler.cpython-38.pyc,,
+clikit/handler/help/help_handler.py,sha256=oILYXTH4H8GQUyTCCdL27V1X9BVyYbsgduuXP_HrRps,238
+clikit/handler/help/help_text_handler.py,sha256=50fAdymanRcJG-QKuLK1Wu1pryYjB0zYTHgohrveHi0,862
+clikit/io/__init__.py,sha256=CFfM1isCq0Ox3jcgKy_ti36LjEIKb-WCqQLV4Ek5hP4,98
+clikit/io/__pycache__/__init__.cpython-38.pyc,,
+clikit/io/__pycache__/buffered_io.cpython-38.pyc,,
+clikit/io/__pycache__/console_io.cpython-38.pyc,,
+clikit/io/__pycache__/null_io.cpython-38.pyc,,
+clikit/io/buffered_io.py,sha256=ONUdINgS6TdAdUZm58kiQre89qrV4f0caQbYszLM-Oo,1662
+clikit/io/console_io.py,sha256=YLq0LiTZkJMCaNvY5zfFrHaUaNclCUovi2ru-I-LQig,1605
+clikit/io/input_stream/__init__.py,sha256=vn5CqtOFVFzTFufMZmqE9JR2DMQfv7kEUxJ3EIOKnSQ,204
+clikit/io/input_stream/__pycache__/__init__.cpython-38.pyc,,
+clikit/io/input_stream/__pycache__/null_input_stream.cpython-38.pyc,,
+clikit/io/input_stream/__pycache__/standard_input_stream.cpython-38.pyc,,
+clikit/io/input_stream/__pycache__/stream_input_stream.cpython-38.pyc,,
+clikit/io/input_stream/__pycache__/string_input_stream.cpython-38.pyc,,
+clikit/io/input_stream/null_input_stream.py,sha256=oX5Q-RXznMBaIGYMIdWXJ_7MKUDlTK_iHCsrpwfWcec,717
+clikit/io/input_stream/standard_input_stream.py,sha256=Q1EusqAASNZBNkqj8KlQ4R-zEzjtZ6uhFokqv1BNhs4,289
+clikit/io/input_stream/stream_input_stream.py,sha256=HRwmNsi6rQ64jniCA4REkabKPfrN_PlB0cFyDxSOakM,1429
+clikit/io/input_stream/string_input_stream.py,sha256=1-5Zcb2d9LWFeERQlcFybNXhG8UFGtXtDoh1LzgIzcQ,879
+clikit/io/null_io.py,sha256=3EeBEC1kDgUeE6J2qa1bjHQplkqjwCTlgho1ZLvnZ9w,494
+clikit/io/output_stream/__init__.py,sha256=ZNqXJn6KLAB58ZPw24wHz0jOVgvfoluHa6WwwKBivBY,267
+clikit/io/output_stream/__pycache__/__init__.cpython-38.pyc,,
+clikit/io/output_stream/__pycache__/buffered_output_stream.cpython-38.pyc,,
+clikit/io/output_stream/__pycache__/error_output_stream.cpython-38.pyc,,
+clikit/io/output_stream/__pycache__/null_output_stream.cpython-38.pyc,,
+clikit/io/output_stream/__pycache__/standard_output_stream.cpython-38.pyc,,
+clikit/io/output_stream/__pycache__/stream_output_stream.cpython-38.pyc,,
+clikit/io/output_stream/buffered_output_stream.py,sha256=U9L9epHTfAj3Zxwsw0lEwKFoTBuSnMNuU_TDjSf_vZc,1315
+clikit/io/output_stream/error_output_stream.py,sha256=yyoW9GX3vKDawDQt5PnXyvrvY8_18nP5jKXYvsnnuiQ,287
+clikit/io/output_stream/null_output_stream.py,sha256=GF_2uHunXMQXvdZXSzTwzDHDAanNwGs8eivljK3EiMM,799
+clikit/io/output_stream/standard_output_stream.py,sha256=IzKfjNrH3yMokxQOwWNrpUynuNPbaFjlJqT0enNsU1w,296
+clikit/io/output_stream/stream_output_stream.py,sha256=3vig_hyp0dODsoQkzq4fojSG3wlmieWV_zamCn2TX-U,3314
+clikit/resolver/__init__.py,sha256=Px1AAiadk2G-y-zaZzxQQGOZn3EPTnVh7s9iDn4riyg,46
+clikit/resolver/__pycache__/__init__.cpython-38.pyc,,
+clikit/resolver/__pycache__/default_resolver.cpython-38.pyc,,
+clikit/resolver/__pycache__/help_resolver.cpython-38.pyc,,
+clikit/resolver/__pycache__/resolve_result.cpython-38.pyc,,
+clikit/resolver/default_resolver.py,sha256=qrRq3EuP3caXg5wcVz6rlzs-JWqMYeqsdXvPNF29nCU,5684
+clikit/resolver/help_resolver.py,sha256=_A78t21jZLsHYDFDict0-sgha_V_sBS9tzie8kBMHVc,1036
+clikit/resolver/resolve_result.py,sha256=DiSzIMeo01-rzfaZ1ARKk9HQuLm8CkKuYqSeoCDr28A,1394
+clikit/ui/__init__.py,sha256=60I_pzuR0mkk9uBc_oLK78uo1VLcSnqk55HU8muONag,66
+clikit/ui/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/__pycache__/component.cpython-38.pyc,,
+clikit/ui/__pycache__/rectangle.cpython-38.pyc,,
+clikit/ui/alignment/__init__.py,sha256=z6aQyThJze0J1Pk0mNXCVlW8Ipk52n0rfviV4EHSA5w,44
+clikit/ui/alignment/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/alignment/__pycache__/label_alignment.cpython-38.pyc,,
+clikit/ui/alignment/label_alignment.py,sha256=W2Gnw2FNJHkrIeH2pcJYrPlI5FG2xnIRuYL5zNNCMEg,1212
+clikit/ui/component.py,sha256=6kXOcriR5JawgA4XRHaJ0Ue-Klj6MeI0V0GlK2JyBCM,229
+clikit/ui/components/__init__.py,sha256=tPsp8TeueoiQHeCPlw6ridPJ5WS5lLwk4iNhf3Zu58U,515
+clikit/ui/components/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/components/__pycache__/border_util.cpython-38.pyc,,
+clikit/ui/components/__pycache__/cell_wrapper.cpython-38.pyc,,
+clikit/ui/components/__pycache__/choice_question.cpython-38.pyc,,
+clikit/ui/components/__pycache__/confirmation_question.cpython-38.pyc,,
+clikit/ui/components/__pycache__/empty_line.cpython-38.pyc,,
+clikit/ui/components/__pycache__/exception_trace.cpython-38.pyc,,
+clikit/ui/components/__pycache__/labeled_paragraph.cpython-38.pyc,,
+clikit/ui/components/__pycache__/name_version.cpython-38.pyc,,
+clikit/ui/components/__pycache__/paragraph.cpython-38.pyc,,
+clikit/ui/components/__pycache__/progress_bar.cpython-38.pyc,,
+clikit/ui/components/__pycache__/progress_indicator.cpython-38.pyc,,
+clikit/ui/components/__pycache__/question.cpython-38.pyc,,
+clikit/ui/components/__pycache__/table.cpython-38.pyc,,
+clikit/ui/components/border_util.py,sha256=NqkT5mwJfg9jbxZ4I_IX9X26mMfGSIYWuRZ7RQPGTjI,4840
+clikit/ui/components/cell_wrapper.py,sha256=5OFhcsXYyHoTGDc4oNLhs9-hAzOcNBBDQxjlB4DKFlQ,7243
+clikit/ui/components/choice_question.py,sha256=J1-9YMPlOliKPiFieuvNQdB-XuCEbZao7089QtzaxXE,4148
+clikit/ui/components/confirmation_question.py,sha256=_GJtLWjxSyUvW7gKAbRO9pzjb4KTEjKbJb9dKeJyu9k,992
+clikit/ui/components/empty_line.py,sha256=jGEfFp12wpGRboEPr_BxEpust_vYEoK6kD3eseG9RY8,218
+clikit/ui/components/exception_trace.py,sha256=GUCWdyF9gAVm8yCxKZsiRmypAUG1ef0_bt_YBvE04To,15913
+clikit/ui/components/labeled_paragraph.py,sha256=gPO8eqKokwF2UN4zwC8l0QAKN3spdd631W6niboEJO8,1990
+clikit/ui/components/name_version.py,sha256=Wj1h0V5YlWDaLIgld5HOurBJMDObbK2lh-S4lA1MoH8,880
+clikit/ui/components/paragraph.py,sha256=XD4CFVWVtisRUQil8BrgScvJ6boqvDxH85m0AHTUsZs,688
+clikit/ui/components/progress_bar.py,sha256=C8xEIOrtvH2w38f1va1BKIj5Or--C_3bS7S7Kn3XWDc,12664
+clikit/ui/components/progress_indicator.py,sha256=FIJ78hbtirvAUZKmCchM0LQaNlPBdwxkBSMM6Cc9VLA,5470
+clikit/ui/components/question.py,sha256=zRZzdtkHrorbZ_34bJyov1nYhwkWMKREfiFrxut9MGo,7607
+clikit/ui/components/table.py,sha256=jn77Mj6Ur6YOmZltaBq772ou2slmRUqP-CvtZn0B5Rw,5232
+clikit/ui/help/__init__.py,sha256=PE4DRHjZpUNQ_oVZtDgYkkg4ryT3zJgPzpkVnFVR8Xg,84
+clikit/ui/help/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/help/__pycache__/abstract_help.cpython-38.pyc,,
+clikit/ui/help/__pycache__/application_help.cpython-38.pyc,,
+clikit/ui/help/__pycache__/command_help.cpython-38.pyc,,
+clikit/ui/help/abstract_help.py,sha256=61pjHbV0z-ajdRqi5bDXmeIoduhIuBY5Q92TghL8MzU,5482
+clikit/ui/help/application_help.py,sha256=gC4XiwLKuCZSZqvkVfHF11QUtCtlVSR3iyCFXHfRXxg,3437
+clikit/ui/help/command_help.py,sha256=XTcqms6r-6MJRxfpwZxQrBidb8wAgK8FFVU2nyUV1GU,6056
+clikit/ui/layout/__init__.py,sha256=FwOogbjZsOLTotD0PlxYNIZsuzki29Yxy21VtZm8Hks,38
+clikit/ui/layout/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/layout/__pycache__/block_layout.cpython-38.pyc,,
+clikit/ui/layout/block_layout.py,sha256=QC-w2bR5cSghF89GlzE6Mcw4UMwynS1ShiafwS6At9w,1262
+clikit/ui/rectangle.py,sha256=N9a9cGix0dlf-4jsGm66EgIjTctSnZXHNxv5c_yYniY,89
+clikit/ui/style/__init__.py,sha256=sWYW20D0opwjM8zyqxeIgXQFdlx6YU9yhjHiILPtLVw,69
+clikit/ui/style/__pycache__/__init__.cpython-38.pyc,,
+clikit/ui/style/__pycache__/alignment.cpython-38.pyc,,
+clikit/ui/style/__pycache__/border_style.cpython-38.pyc,,
+clikit/ui/style/__pycache__/table_style.cpython-38.pyc,,
+clikit/ui/style/alignment.py,sha256=-BWCOyYJ4fiL1P8PCpUVnZarp7iMCfpOj11nQ05Z5LY,110
+clikit/ui/style/border_style.py,sha256=TSwHfFMVfpJHkWJaKW0n8PzBDOHZRP8QZ3SlRRomXp4,2540
+clikit/ui/style/table_style.py,sha256=rwLbwkBUyKAenLt2jcv5gWEsVmNZJ4QMGfasRiH3FVg,2303
+clikit/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+clikit/utils/__pycache__/__init__.cpython-38.pyc,,
+clikit/utils/__pycache__/_compat.cpython-38.pyc,,
+clikit/utils/__pycache__/command.cpython-38.pyc,,
+clikit/utils/__pycache__/string.cpython-38.pyc,,
+clikit/utils/__pycache__/terminal.cpython-38.pyc,,
+clikit/utils/__pycache__/time.cpython-38.pyc,,
+clikit/utils/_compat.py,sha256=E2hkXMnWifngCqoOgd5V3NeP3qhQFytPfTkfZwQehP0,1814
+clikit/utils/command.py,sha256=KzWMqmV5KO4Up_e9duIOT7F9AqJB1QGOxxWfwboXxlA,1296
+clikit/utils/string.py,sha256=jaoiWhqO5vRax2jgyO6YvEBgHUIDH7NIhPGcjTvaCiI,2442
+clikit/utils/terminal.py,sha256=VhnUJBuIYtuBQiQGSTgTOLSBaXJ1anepxF0uh_AoElE,3696
+clikit/utils/time.py,sha256=fJrFL3pNwn1DUPF0ML_GuL9Fw27eHKt9szwA5EnEeQY,476
diff --git a/venv/lib64/python3.8/site-packages/cryptography-35.0.0.dist-info/RECORD b/venv/lib64/python3.8/site-packages/cryptography-35.0.0.dist-info/RECORD
new file mode 100644
index 0000000..99460a6
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/cryptography-35.0.0.dist-info/RECORD
@@ -0,0 +1,184 @@
+cryptography-35.0.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+cryptography-35.0.0.dist-info/LICENSE,sha256=Q9rSzHUqtyHNmp827OcPtTq3cTVR8tPYaU2OjFoG1uI,323
+cryptography-35.0.0.dist-info/LICENSE.APACHE,sha256=qsc7MUj20dcRHbyjIJn2jSbGRMaBOuHk8F9leaomY_4,11360
+cryptography-35.0.0.dist-info/LICENSE.BSD,sha256=YCxMdILeZHndLpeTzaJ15eY9dz2s0eymiSMqtwCPtPs,1532
+cryptography-35.0.0.dist-info/LICENSE.PSF,sha256=aT7ApmKzn5laTyUrA6YiKUVHDBtvEsoCkY5O_g32S58,2415
+cryptography-35.0.0.dist-info/METADATA,sha256=zZa1iL6QuaIYXKGIUSWbpAHq7Au8WvwXNRai8NiBm_k,5411
+cryptography-35.0.0.dist-info/RECORD,,
+cryptography-35.0.0.dist-info/WHEEL,sha256=9yjAS7Go4YyoRic4z08Pd2x_haRFlnlQ7mHzG4ikAes,112
+cryptography-35.0.0.dist-info/top_level.txt,sha256=zYbdX67v4JFZPfsaNue7ZV4-mgoRqYCAhMsNgt22LqA,22
+cryptography/__about__.py,sha256=5880_FiRxxAFrYOHgHw5kq-ckSChngziy8KbwdtR6uU,417
+cryptography/__init__.py,sha256=ZkGC0RcrTYfnPlvOf9KmT-jGQ5iaA_hWG0Ei0EsIZwk,347
+cryptography/__pycache__/__about__.cpython-38.pyc,,
+cryptography/__pycache__/__init__.cpython-38.pyc,,
+cryptography/__pycache__/exceptions.cpython-38.pyc,,
+cryptography/__pycache__/fernet.cpython-38.pyc,,
+cryptography/__pycache__/utils.cpython-38.pyc,,
+cryptography/exceptions.py,sha256=TxKhSY9gEZi1P_2eFO1A2LWwzeGMvpPn8rcchIKS7fE,1209
+cryptography/fernet.py,sha256=Brm2owvVHgq73N8KgmPwKPEt9rBFzvoGD4OMb9qem-Y,6676
+cryptography/hazmat/__init__.py,sha256=OYlvgprzULzZlsf3yYTsd6VUVyQmpsbHjgJdNnsyRwE,418
+cryptography/hazmat/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/__pycache__/_oid.cpython-38.pyc,,
+cryptography/hazmat/_oid.py,sha256=VHMc8J_wmnFdIglsZO1JSROZat6FcV8PmZZJhLo45TU,14960
+cryptography/hazmat/backends/__init__.py,sha256=eSGB-hZdol_ol8otjYBi7gIoH78eiUCOTDVs2gV6IbY,699
+cryptography/hazmat/backends/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/backends/__pycache__/interfaces.cpython-38.pyc,,
+cryptography/hazmat/backends/interfaces.py,sha256=nTJiBNdciii0RCt1UCsOYtsik0hAgoWhDmNEdc9dN1c,12330
+cryptography/hazmat/backends/openssl/__init__.py,sha256=7rpz1Z3eV9vZy_d2iLrwC8Oz0vEruDFrjJlc6W2ZDXA,271
+cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-38.pyc,,
+cryptography/hazmat/backends/openssl/aead.py,sha256=zt8ZQ-JethHblWEfwAnB5-09JIL9K8qU1NXwPTjeVYA,5700
+cryptography/hazmat/backends/openssl/backend.py,sha256=fmXuIA2ZHkPNhqCQequOwW15jQdGWDkOPA6KQ0I80s8,107367
+cryptography/hazmat/backends/openssl/ciphers.py,sha256=jveXyZ9k0mTH7wp-4LUobN2HLYDGVcUb9RVumbU_kDY,10205
+cryptography/hazmat/backends/openssl/cmac.py,sha256=KXcwF1XlY0Ew6sTBqPj0I1vr62dfMwCjeV3qBosIw8s,2846
+cryptography/hazmat/backends/openssl/decode_asn1.py,sha256=FmR255NmhrIoBCccqe1rpBfZGH1lJcxiHMGWJB-fDcs,1176
+cryptography/hazmat/backends/openssl/dh.py,sha256=IbrUkIHANDPPp6jG-UaUBbCBaBcsbv-faq4L86ue5_s,11209
+cryptography/hazmat/backends/openssl/dsa.py,sha256=2xqKXe8hd3e0USiXzrdwGT38fVENy7H1dTimF0igIAE,10707
+cryptography/hazmat/backends/openssl/ec.py,sha256=LLXNW8anl1WmSNYkEdy-OlFMPCHwvkD_WV0UD2czqZA,12854
+cryptography/hazmat/backends/openssl/ed25519.py,sha256=bSlMfJedRoyzZXoJeaehj_0H_j6Ye5doQHgnib602-Q,5789
+cryptography/hazmat/backends/openssl/ed448.py,sha256=dpJf1zt_o8vfVcXYi_PD8d9H-jBbYEp-d6ZIYDKlC1s,5743
+cryptography/hazmat/backends/openssl/encode_asn1.py,sha256=1P7T7dVYDfmCm25XaMN4Tku1Iahmbn89F7RWeJT5hBo,23483
+cryptography/hazmat/backends/openssl/hashes.py,sha256=wx4SllcOscA0LHcHAZ3v6kOerLcZZO7gr7wVcIDtyKI,3098
+cryptography/hazmat/backends/openssl/hmac.py,sha256=jdiNrruBI8LG_1xrTW_pzP3V4EfmvWIGU9mV9wMtrEY,2941
+cryptography/hazmat/backends/openssl/poly1305.py,sha256=0hJDAb4pl9dJ_2xgt-XkNfyFA6U_IFXCe5jzOg7gkG0,2327
+cryptography/hazmat/backends/openssl/rsa.py,sha256=_SrvlAwnzlXo72-NWMif0FmJMySkh8oGdQom1ou77NI,21358
+cryptography/hazmat/backends/openssl/utils.py,sha256=2yO_PVh6mBQbRPC2U0ksmC2SQrAhmHSbay696SyOeLo,2342
+cryptography/hazmat/backends/openssl/x25519.py,sha256=kCnWzuchrJn1Nne4zeotKvlkMty9p3VuM8y1EWo70vQ,4622
+cryptography/hazmat/backends/openssl/x448.py,sha256=8OKYMNXDR7UlViU3sNIH5qmLMGP7J-F3OeEaRK0aots,4141
+cryptography/hazmat/backends/openssl/x509.py,sha256=VXH-yh0Onjv63Zlb774WmViExEuRV1rARz9Lm5-8Qp0,2085
+cryptography/hazmat/bindings/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
+cryptography/hazmat/bindings/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/bindings/_openssl.abi3.so,sha256=XEQzkf285jcTYevb5tHzeKfBjHHCbhJ5IGBRBZkgUtU,6589152
+cryptography/hazmat/bindings/_rust.abi3.so,sha256=dgE6e2kGvhwAcsxGbb8ukCfvYr1hBeWIhLrQ8Ie_TQo,3312240
+cryptography/hazmat/bindings/_rust/__init__.pyi,sha256=ga5QLYp8MmumQB-Rp4TGHq_NAqONcXTrLm2712TZ9Ms,103
+cryptography/hazmat/bindings/_rust/asn1.pyi,sha256=sjHGn5ZQDBG9pOHYjfm2j3WYfs_2W3tPBok_TGs1FVA,582
+cryptography/hazmat/bindings/_rust/ocsp.pyi,sha256=g8dWhhJZBciU-4hWvJS-Y5xdSbzhxHRVD60MBEpQcAc,226
+cryptography/hazmat/bindings/_rust/x509.pyi,sha256=WqkJoSvtdlh4ppjtO30xa6zPCckwRjD7Fiks3Og3X6c,863
+cryptography/hazmat/bindings/openssl/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
+cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-38.pyc,,
+cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-38.pyc,,
+cryptography/hazmat/bindings/openssl/_conditional.py,sha256=BcqYjIat6uaCJjRhkB07QNk-neiJ7TYgDbpyzOteX-4,7895
+cryptography/hazmat/bindings/openssl/binding.py,sha256=NdDV1tgUzeJj5CB5LZQ4-Ml1UrZmJ-YEuxTaJnbOack,7408
+cryptography/hazmat/primitives/__init__.py,sha256=s9oKCQ2ycFdXoERdS1imafueSkBsL9kvbyfghaauZ9Y,180
+cryptography/hazmat/primitives/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/_serialization.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/cmac.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/constant_time.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/hashes.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/hmac.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/keywrap.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/padding.cpython-38.pyc,,
+cryptography/hazmat/primitives/__pycache__/poly1305.cpython-38.pyc,,
+cryptography/hazmat/primitives/_asymmetric.py,sha256=nVJwmxkakirAXfFp410pC4kY_CinzN5FSJwhEn2IE34,485
+cryptography/hazmat/primitives/_cipheralgorithm.py,sha256=sV8-SjhhY4WtHsaLI7e2x4o2cYAAqP8YWBjhC6k1u10,1000
+cryptography/hazmat/primitives/_serialization.py,sha256=OC_uXC5cNHucoOkHuTsZbfcQ9bvZs1cq7b18TcJu4Es,1341
+cryptography/hazmat/primitives/asymmetric/__init__.py,sha256=p69vOT3TH9cC7CBRiPsJBkXWfEU10Y0V537jrbHTW0U,956
+cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-38.pyc,,
+cryptography/hazmat/primitives/asymmetric/dh.py,sha256=5G8CuY86RKBm8ZWZFbsfURNOEuFkVjUYFHwdgG1A4rU,6554
+cryptography/hazmat/primitives/asymmetric/dsa.py,sha256=Kyzjbz3Gz9PH1XdUR2zDS8s2WIK9CBmx-V8VWQg9fO0,8363
+cryptography/hazmat/primitives/asymmetric/ec.py,sha256=A_ryk10REbwC4nciF4uUDQqrdI4EPs54ZFGgfaPGlk0,15000
+cryptography/hazmat/primitives/asymmetric/ed25519.py,sha256=1qOl1UWV_-cXKHhwlFSyPBdhpx2HMDRukkI6eI5i8vM,2728
+cryptography/hazmat/primitives/asymmetric/ed448.py,sha256=oR-j4jGcWUnGxWi1GygHxVZbgkSOKHsR6y1E3Lf6wYM,2647
+cryptography/hazmat/primitives/asymmetric/padding.py,sha256=QAcY756FgQgkRTUwHUKN1TfMhjEmsu4KwS1yKwN6RKI,2145
+cryptography/hazmat/primitives/asymmetric/rsa.py,sha256=pMcXyxPHRWEoN9jCN5LYKisLcIbwJMEPIb4mIQvRFIU,12103
+cryptography/hazmat/primitives/asymmetric/types.py,sha256=cF9k9hsiQG1CT34-JNLNFC5N0uMUX5bilnT9ewFsljI,644
+cryptography/hazmat/primitives/asymmetric/utils.py,sha256=uX3yo4ngIHdp9f6P5AEYmOwiuSVpQ4mL_h8kyP_HHy8,742
+cryptography/hazmat/primitives/asymmetric/x25519.py,sha256=-nbaGlgT1sufO9Ic-urwKDql8Da0U3GL6hZJIMqHgVc,2588
+cryptography/hazmat/primitives/asymmetric/x448.py,sha256=V3lxb1VOiRTa3bzVUC3uZat2ogfExUOdktCIGUUMZ2Y,2556
+cryptography/hazmat/primitives/ciphers/__init__.py,sha256=Qp78Y3PDSRfwp7DDa3pezlLrED_QFhic_LvDw4LM9ZQ,646
+cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-38.pyc,,
+cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-38.pyc,,
+cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-38.pyc,,
+cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-38.pyc,,
+cryptography/hazmat/primitives/ciphers/aead.py,sha256=8kesdxzga3--fpfEpryq3maK8YolOwiUl_pmfSDBYkA,6863
+cryptography/hazmat/primitives/ciphers/algorithms.py,sha256=e2o7CuWULhBB-DoSb9GXUZk1RRSWE1R9kNEA7dhlu_U,4148
+cryptography/hazmat/primitives/ciphers/base.py,sha256=YmreM20iR-vmwV23zoTWaJuxmyR5h2KP4r0OsjPmU08,7007
+cryptography/hazmat/primitives/ciphers/modes.py,sha256=-1VPWPiKwcNZwKnKxhibro_qhDHpygYEQ5yCvbzrVfI,7429
+cryptography/hazmat/primitives/cmac.py,sha256=AQgoYywf-mXZCXE0KB3BiCcWcgPgaLctBOvvCx-Z_Y8,2235
+cryptography/hazmat/primitives/constant_time.py,sha256=6bkW00QjhKusdgsQbexXhMlGX0XRN59XNmxWS2W38NA,387
+cryptography/hazmat/primitives/hashes.py,sha256=IVRp8vl6jDnLEsy4vXwki_inX4l6V39dx6vIrfvIr3k,6367
+cryptography/hazmat/primitives/hmac.py,sha256=m-53Lq59EoSloUzmx9Qty4OSh2bN9akjp0ohKurYBGI,2423
+cryptography/hazmat/primitives/kdf/__init__.py,sha256=DcZhzfLG8d8IYBH771lGTVU5S87OQDpu3nrfOwZnsmA,715
+cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-38.pyc,,
+cryptography/hazmat/primitives/kdf/concatkdf.py,sha256=HrPWadThIgyktYGwrz6MKLinWXDZTz1c-kxoOmmprcM,4614
+cryptography/hazmat/primitives/kdf/hkdf.py,sha256=MZS8iwscL-FQVd2ayuqeNoEuVAwLbwd8_GlOd5lMYWY,3871
+cryptography/hazmat/primitives/kdf/kbkdf.py,sha256=SsO8RlzPLzhHuOlfG0S_zW039dZiaVsTT6M7VLr_p98,8283
+cryptography/hazmat/primitives/kdf/pbkdf2.py,sha256=pgtc2gm1RPV1O2IMRzlsD0NXjqpP2LxiRsozkSteEEY,2313
+cryptography/hazmat/primitives/kdf/scrypt.py,sha256=xG3S0sMuQufEIrzCoeIqwvv9MafvrhJEkDQ6A1NKJB4,2348
+cryptography/hazmat/primitives/kdf/x963kdf.py,sha256=KcP_PfIfz0opzbEiVYG8ECxN8aGtO_GG_mGmg7Lo1zU,2494
+cryptography/hazmat/primitives/keywrap.py,sha256=L4RqzLVFSwCDfvY1G8ZQVcn8SrPMsC88c-0U_86wmRA,6179
+cryptography/hazmat/primitives/padding.py,sha256=Kuelp5tzUgJnBpMKgn2XN7_mprC7lxscKbupAPivclM,6187
+cryptography/hazmat/primitives/poly1305.py,sha256=_Dtv6oCMn94rAhQ6pjie9mO_MiDLVL5It3Z5sdpCU3c,1711
+cryptography/hazmat/primitives/serialization/__init__.py,sha256=RALEthF7wRjlMyTvSq09XmKQey74tsSdDCCsDaD6yQU,1129
+cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-38.pyc,,
+cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-38.pyc,,
+cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-38.pyc,,
+cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-38.pyc,,
+cryptography/hazmat/primitives/serialization/base.py,sha256=WAgaOSQordQ6EBXm_JMc-5hNkxwqDfmea7Zg5fC8pZ8,1725
+cryptography/hazmat/primitives/serialization/pkcs12.py,sha256=MT_JTVam_mLAqc1ifVpzjo87mDAz43EU50sIvJ-t3rg,2367
+cryptography/hazmat/primitives/serialization/pkcs7.py,sha256=khs1nvWTTN-Ctaqfqj2QSUDrXyzzXhrp_EwC8j6YrXI,5326
+cryptography/hazmat/primitives/serialization/ssh.py,sha256=GoCJk7fDDwcBrSKhQI-37NZy_ZPtCeTWsFskleWElTg,22442
+cryptography/hazmat/primitives/twofactor/__init__.py,sha256=ZHo4zwWidFP2RWFl8luiNuYkVMZPghzx54izPNSCtD4,222
+cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-38.pyc,,
+cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-38.pyc,,
+cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-38.pyc,,
+cryptography/hazmat/primitives/twofactor/hotp.py,sha256=14sLX8Mxvjv6FSF56LrB92gEdwM8WP1pn3Mxg3dE_mY,3629
+cryptography/hazmat/primitives/twofactor/totp.py,sha256=udOohvi33C_GLqQK-PB9PGFtsv5SlcoX1BvVlIicoI0,1895
+cryptography/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+cryptography/utils.py,sha256=Ns-hs0cAZnOLE_bEeUrDgqrVi5hdPZ78GXwLByM3TyQ,5437
+cryptography/x509/__init__.py,sha256=fuXhiCA_Th9v1R1LEbF3SZvJG_oIHE_TDLEoT5QPPec,7588
+cryptography/x509/__pycache__/__init__.cpython-38.pyc,,
+cryptography/x509/__pycache__/base.cpython-38.pyc,,
+cryptography/x509/__pycache__/certificate_transparency.cpython-38.pyc,,
+cryptography/x509/__pycache__/extensions.cpython-38.pyc,,
+cryptography/x509/__pycache__/general_name.cpython-38.pyc,,
+cryptography/x509/__pycache__/name.cpython-38.pyc,,
+cryptography/x509/__pycache__/ocsp.cpython-38.pyc,,
+cryptography/x509/__pycache__/oid.cpython-38.pyc,,
+cryptography/x509/base.py,sha256=p9zkQB07005yXa2d2Xzp-oXIClDmqcrmcpQqZtpsgSk,31546
+cryptography/x509/certificate_transparency.py,sha256=Elm_-GGA6k9zrcm5KYVY5uTirDsvGc_BUuTLR7Hu-K4,1119
+cryptography/x509/extensions.py,sha256=DsV3Om5PSaz6hLIjYIRdTQdCDNF_bS2E5s4Tr4aZ64k,64465
+cryptography/x509/general_name.py,sha256=6h7QnFSllwfkYEZpwNDhqJZ5p4ng3f5UOFz-47gkY6Q,8147
+cryptography/x509/name.py,sha256=nXqeAsWG5VHD-JDrjy-rcMGLXRzwzYYUa_FIT1ofW5E,9529
+cryptography/x509/ocsp.py,sha256=1kgLbBov4pUBqTRtGhGmJb5eX_id24nkntbbiSHFmB0,14792
+cryptography/x509/oid.py,sha256=CLIlQwzE3PQXMvkKep4JbzVUaRDl_stwcX_U6-s2cNw,794
diff --git a/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__about__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__about__.cpython-38.pyc
new file mode 100644
index 0000000..8af8eec
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__about__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..609c2e3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/__pycache__/exceptions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/exceptions.cpython-38.pyc
new file mode 100644
index 0000000..5dbd9cc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/exceptions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/__pycache__/fernet.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/fernet.cpython-38.pyc
new file mode 100644
index 0000000..a8e01de
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/fernet.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/__pycache__/utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/utils.cpython-38.pyc
new file mode 100644
index 0000000..c537628
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..06a065f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-38.pyc
new file mode 100644
index 0000000..4324897
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/__pycache__/_oid.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..c036d15
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/interfaces.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/interfaces.cpython-38.pyc
new file mode 100644
index 0000000..4e4e585
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/__pycache__/interfaces.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..6c3b91f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-38.pyc
new file mode 100644
index 0000000..5607490
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/aead.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-38.pyc
new file mode 100644
index 0000000..1c34d0d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/backend.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-38.pyc
new file mode 100644
index 0000000..196bf6b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ciphers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-38.pyc
new file mode 100644
index 0000000..d1f61a7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/cmac.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-38.pyc
new file mode 100644
index 0000000..9651709
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/decode_asn1.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-38.pyc
new file mode 100644
index 0000000..e34a4b0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dh.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-38.pyc
new file mode 100644
index 0000000..96a69c0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/dsa.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-38.pyc
new file mode 100644
index 0000000..4419fd1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ec.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-38.pyc
new file mode 100644
index 0000000..cad0e3b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed25519.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-38.pyc
new file mode 100644
index 0000000..bcec59a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/ed448.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-38.pyc
new file mode 100644
index 0000000..af75b8f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/encode_asn1.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-38.pyc
new file mode 100644
index 0000000..ff5812a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hashes.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-38.pyc
new file mode 100644
index 0000000..eea07fa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/hmac.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-38.pyc
new file mode 100644
index 0000000..799cc17
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/poly1305.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-38.pyc
new file mode 100644
index 0000000..c6d3bd8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/rsa.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-38.pyc
new file mode 100644
index 0000000..f59a65f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-38.pyc
new file mode 100644
index 0000000..089c623
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x25519.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-38.pyc
new file mode 100644
index 0000000..e0e18ac
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x448.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-38.pyc
new file mode 100644
index 0000000..1cafdae
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/backends/openssl/__pycache__/x509.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..fc00c83
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..08d8ba6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-38.pyc
new file mode 100644
index 0000000..8ed4b03
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/_conditional.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-38.pyc
new file mode 100644
index 0000000..7a715db
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/bindings/openssl/__pycache__/binding.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..173e50b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-38.pyc
new file mode 100644
index 0000000..531c714
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_asymmetric.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-38.pyc
new file mode 100644
index 0000000..af66452
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_cipheralgorithm.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-38.pyc
new file mode 100644
index 0000000..a782bfe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/_serialization.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-38.pyc
new file mode 100644
index 0000000..2227b55
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/cmac.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-38.pyc
new file mode 100644
index 0000000..caa3f09
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/constant_time.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-38.pyc
new file mode 100644
index 0000000..ef7f531
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hashes.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-38.pyc
new file mode 100644
index 0000000..7f3b024
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/hmac.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-38.pyc
new file mode 100644
index 0000000..b3eec79
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/keywrap.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-38.pyc
new file mode 100644
index 0000000..bad0168
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/padding.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-38.pyc
new file mode 100644
index 0000000..afb8645
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/__pycache__/poly1305.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..9756744
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-38.pyc
new file mode 100644
index 0000000..286ede8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dh.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-38.pyc
new file mode 100644
index 0000000..bf53e4e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/dsa.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-38.pyc
new file mode 100644
index 0000000..b942597
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ec.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-38.pyc
new file mode 100644
index 0000000..c65674a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed25519.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-38.pyc
new file mode 100644
index 0000000..db0d97e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/ed448.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-38.pyc
new file mode 100644
index 0000000..7da6217
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/padding.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-38.pyc
new file mode 100644
index 0000000..402c58a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/rsa.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-38.pyc
new file mode 100644
index 0000000..567e7d2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/types.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-38.pyc
new file mode 100644
index 0000000..742e9e0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-38.pyc
new file mode 100644
index 0000000..ae0dfe1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x25519.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-38.pyc
new file mode 100644
index 0000000..7f0ce26
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/asymmetric/__pycache__/x448.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..7d98bf7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-38.pyc
new file mode 100644
index 0000000..a5f5bf3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/aead.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-38.pyc
new file mode 100644
index 0000000..1d95849
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/algorithms.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-38.pyc
new file mode 100644
index 0000000..b2ff2d2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-38.pyc
new file mode 100644
index 0000000..15d0e0b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/ciphers/__pycache__/modes.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..1dc5145
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-38.pyc
new file mode 100644
index 0000000..d43c455
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/concatkdf.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-38.pyc
new file mode 100644
index 0000000..dc779dc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/hkdf.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-38.pyc
new file mode 100644
index 0000000..4e7fe2e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/kbkdf.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-38.pyc
new file mode 100644
index 0000000..f78f422
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/pbkdf2.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-38.pyc
new file mode 100644
index 0000000..0edf9ce
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/scrypt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-38.pyc
new file mode 100644
index 0000000..6b33d1e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/kdf/__pycache__/x963kdf.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..deca47b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-38.pyc
new file mode 100644
index 0000000..887ccdb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-38.pyc
new file mode 100644
index 0000000..c503a6d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs12.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-38.pyc
new file mode 100644
index 0000000..bd7f158
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/pkcs7.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-38.pyc
new file mode 100644
index 0000000..af87f41
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/serialization/__pycache__/ssh.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..6a8bf7d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-38.pyc
new file mode 100644
index 0000000..5873690
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/hotp.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-38.pyc
new file mode 100644
index 0000000..d78ff3a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/hazmat/primitives/twofactor/__pycache__/totp.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..4a30fb5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/base.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/base.cpython-38.pyc
new file mode 100644
index 0000000..576c01b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/base.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-38.pyc
new file mode 100644
index 0000000..9c0dcfe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/certificate_transparency.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/extensions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/extensions.cpython-38.pyc
new file mode 100644
index 0000000..d742c45
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/extensions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/general_name.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/general_name.cpython-38.pyc
new file mode 100644
index 0000000..0447f34
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/general_name.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/name.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/name.cpython-38.pyc
new file mode 100644
index 0000000..9dee33d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/name.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/ocsp.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/ocsp.cpython-38.pyc
new file mode 100644
index 0000000..964d7b0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/ocsp.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/oid.cpython-38.pyc b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/oid.cpython-38.pyc
new file mode 100644
index 0000000..7aa09f2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/cryptography/x509/__pycache__/oid.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..fe6b3fb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__main__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__main__.cpython-38.pyc
new file mode 100644
index 0000000..ac3eecb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/__pycache__/_version.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/_version.cpython-38.pyc
new file mode 100644
index 0000000..cdc07d5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/__pycache__/_version.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..8c9c368
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_pydevd_packaging.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_pydevd_packaging.cpython-38.pyc
new file mode 100644
index 0000000..a51a833
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_pydevd_packaging.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_util.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_util.cpython-38.pyc
new file mode 100644
index 0000000..08e4d04
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/_util.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/force_pydevd.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/force_pydevd.cpython-38.pyc
new file mode 100644
index 0000000..ba9fa80
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/__pycache__/force_pydevd.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_app_engine_debug_startup.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_app_engine_debug_startup.cpython-38.pyc
new file mode 100644
index 0000000..73c5b69
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_app_engine_debug_startup.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_coverage.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_coverage.cpython-38.pyc
new file mode 100644
index 0000000..043d0ff
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_coverage.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_pysrc.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_pysrc.cpython-38.pyc
new file mode 100644
index 0000000..307d13f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_pysrc.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_run_in_console.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_run_in_console.cpython-38.pyc
new file mode 100644
index 0000000..4a106f7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydev_run_in_console.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevconsole.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevconsole.cpython-38.pyc
new file mode 100644
index 0000000..6d88a28
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevconsole.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd.cpython-38.pyc
new file mode 100644
index 0000000..0beeb70
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_file_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_file_utils.cpython-38.pyc
new file mode 100644
index 0000000..29ba27e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_file_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_tracing.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_tracing.cpython-38.pyc
new file mode 100644
index 0000000..3f2db5a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/pydevd_tracing.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/setup_cython.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/setup_cython.cpython-38.pyc
new file mode 100644
index 0000000..678fd83
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/__pycache__/setup_cython.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..3349abe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_calltip_util.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_calltip_util.cpython-38.pyc
new file mode 100644
index 0000000..81bdb99
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_calltip_util.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_completer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_completer.cpython-38.pyc
new file mode 100644
index 0000000..6a3dc7e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_completer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_filesystem_encoding.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_filesystem_encoding.cpython-38.pyc
new file mode 100644
index 0000000..6502558
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_filesystem_encoding.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_getopt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_getopt.cpython-38.pyc
new file mode 100644
index 0000000..f45c3e8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_getopt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_imports_tipper.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_imports_tipper.cpython-38.pyc
new file mode 100644
index 0000000..f92a0b9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_imports_tipper.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_jy_imports_tipper.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_jy_imports_tipper.cpython-38.pyc
new file mode 100644
index 0000000..4d2a714
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_jy_imports_tipper.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_log.cpython-38.pyc
new file mode 100644
index 0000000..8da8173
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_tipper_common.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_tipper_common.cpython-38.pyc
new file mode 100644
index 0000000..3354292
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/_pydev_tipper_common.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_console_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_console_utils.cpython-38.pyc
new file mode 100644
index 0000000..4155109
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_console_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_import_hook.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_import_hook.cpython-38.pyc
new file mode 100644
index 0000000..2262b48
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_import_hook.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_imports.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_imports.cpython-38.pyc
new file mode 100644
index 0000000..2b4c5a1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_imports.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console.cpython-38.pyc
new file mode 100644
index 0000000..f2f1e96
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console_011.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console_011.cpython-38.pyc
new file mode 100644
index 0000000..fb1f534
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_ipython_console_011.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_is_thread_alive.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_is_thread_alive.cpython-38.pyc
new file mode 100644
index 0000000..6225e90
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_is_thread_alive.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_localhost.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_localhost.cpython-38.pyc
new file mode 100644
index 0000000..c2bebc6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_localhost.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_log.cpython-38.pyc
new file mode 100644
index 0000000..2ef8df1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey.cpython-38.pyc
new file mode 100644
index 0000000..239e5a7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey_qt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey_qt.cpython-38.pyc
new file mode 100644
index 0000000..03756a6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_monkey_qt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_override.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_override.cpython-38.pyc
new file mode 100644
index 0000000..284f014
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_override.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_umd.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_umd.cpython-38.pyc
new file mode 100644
index 0000000..ace3603
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_umd.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_versioncheck.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_versioncheck.cpython-38.pyc
new file mode 100644
index 0000000..73f5e11
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_bundle/__pycache__/pydev_versioncheck.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..91be32e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_BaseHTTPServer.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_BaseHTTPServer.cpython-38.pyc
new file mode 100644
index 0000000..c0b5a29
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_BaseHTTPServer.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_execfile.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_execfile.cpython-38.pyc
new file mode 100644
index 0000000..d16b557
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_execfile.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_saved_modules.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_saved_modules.cpython-38.pyc
new file mode 100644
index 0000000..a9eb0db
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_saved_modules.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_sys_patch.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_sys_patch.cpython-38.pyc
new file mode 100644
index 0000000..d0e4aaa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_imps/__pycache__/_pydev_sys_patch.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..48e2116
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles.cpython-38.pyc
new file mode 100644
index 0000000..2f34377
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_coverage.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_coverage.cpython-38.pyc
new file mode 100644
index 0000000..ccadf5d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_coverage.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_nose.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_nose.cpython-38.pyc
new file mode 100644
index 0000000..38d6021
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_nose.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel.cpython-38.pyc
new file mode 100644
index 0000000..9907024
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel_client.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel_client.cpython-38.pyc
new file mode 100644
index 0000000..25934e7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_parallel_client.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_pytest2.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_pytest2.cpython-38.pyc
new file mode 100644
index 0000000..af1a7a1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_pytest2.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_unittest.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_unittest.cpython-38.pyc
new file mode 100644
index 0000000..4dae75c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_unittest.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_xml_rpc.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_xml_rpc.cpython-38.pyc
new file mode 100644
index 0000000..9d519c1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydev_runfiles/__pycache__/pydev_runfiles_xml_rpc.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..ff55eb3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info.cpython-38.pyc
new file mode 100644
index 0000000..a715aa4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info_regular.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info_regular.cpython-38.pyc
new file mode 100644
index 0000000..363b6f8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_additional_thread_info_regular.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_api.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_api.cpython-38.pyc
new file mode 100644
index 0000000..471c1e2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_api.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_breakpoints.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_breakpoints.cpython-38.pyc
new file mode 100644
index 0000000..6919bb0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_breakpoints.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_code_to_source.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_code_to_source.cpython-38.pyc
new file mode 100644
index 0000000..6f53671
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_code_to_source.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_collect_bytecode_info.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_collect_bytecode_info.cpython-38.pyc
new file mode 100644
index 0000000..417ced7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_collect_bytecode_info.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm.cpython-38.pyc
new file mode 100644
index 0000000..e5cfa3f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm_constants.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm_constants.cpython-38.pyc
new file mode 100644
index 0000000..85a3e18
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_comm_constants.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_command_line_handling.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_command_line_handling.cpython-38.pyc
new file mode 100644
index 0000000..76c613f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_command_line_handling.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_console.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_console.cpython-38.pyc
new file mode 100644
index 0000000..841c166
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_console.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_constants.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_constants.cpython-38.pyc
new file mode 100644
index 0000000..b3a4f25
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_constants.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_custom_frames.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_custom_frames.cpython-38.pyc
new file mode 100644
index 0000000..8c823a8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_custom_frames.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_cython_wrapper.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_cython_wrapper.cpython-38.pyc
new file mode 100644
index 0000000..ecd8b5b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_cython_wrapper.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_daemon_thread.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_daemon_thread.cpython-38.pyc
new file mode 100644
index 0000000..0a10c93
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_daemon_thread.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_defaults.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_defaults.cpython-38.pyc
new file mode 100644
index 0000000..b7f596c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_defaults.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace.cpython-38.pyc
new file mode 100644
index 0000000..de1e232
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace_files.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace_files.cpython-38.pyc
new file mode 100644
index 0000000..42ab65c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_dont_trace_files.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_exec2.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_exec2.cpython-38.pyc
new file mode 100644
index 0000000..4506784
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_exec2.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_api.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_api.cpython-38.pyc
new file mode 100644
index 0000000..ec03c52
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_api.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_utils.cpython-38.pyc
new file mode 100644
index 0000000..95e12d4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_extension_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_filtering.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_filtering.cpython-38.pyc
new file mode 100644
index 0000000..5fb47ad
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_filtering.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame.cpython-38.pyc
new file mode 100644
index 0000000..2f21f0f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame_utils.cpython-38.pyc
new file mode 100644
index 0000000..882014f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_frame_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_import_class.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_import_class.cpython-38.pyc
new file mode 100644
index 0000000..f9b3570
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_import_class.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_io.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_io.cpython-38.pyc
new file mode 100644
index 0000000..5445c89
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_io.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_json_debug_options.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_json_debug_options.cpython-38.pyc
new file mode 100644
index 0000000..5f8b046
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_json_debug_options.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command.cpython-38.pyc
new file mode 100644
index 0000000..c577519
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_json.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_json.cpython-38.pyc
new file mode 100644
index 0000000..a5251a1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_json.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_xml.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_xml.cpython-38.pyc
new file mode 100644
index 0000000..43e7c82
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_net_command_factory_xml.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_plugin_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_plugin_utils.cpython-38.pyc
new file mode 100644
index 0000000..e768ac8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_plugin_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command.cpython-38.pyc
new file mode 100644
index 0000000..702cb63
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command_json.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command_json.cpython-38.pyc
new file mode 100644
index 0000000..ef6375b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_process_net_command_json.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_referrers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_referrers.cpython-38.pyc
new file mode 100644
index 0000000..963fa6e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_referrers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_reload.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_reload.cpython-38.pyc
new file mode 100644
index 0000000..b89cb88
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_reload.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_resolver.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_resolver.cpython-38.pyc
new file mode 100644
index 0000000..f55b158
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_resolver.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_safe_repr.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_safe_repr.cpython-38.pyc
new file mode 100644
index 0000000..40e4440
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_safe_repr.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_save_locals.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_save_locals.cpython-38.pyc
new file mode 100644
index 0000000..779765a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_save_locals.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_signature.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_signature.cpython-38.pyc
new file mode 100644
index 0000000..5d3a23e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_signature.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_source_mapping.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_source_mapping.cpython-38.pyc
new file mode 100644
index 0000000..62bf204
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_source_mapping.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_stackless.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_stackless.cpython-38.pyc
new file mode 100644
index 0000000..e2e85fa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_stackless.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_suspended_frames.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_suspended_frames.cpython-38.pyc
new file mode 100644
index 0000000..cd85168
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_suspended_frames.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_thread_lifecycle.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_thread_lifecycle.cpython-38.pyc
new file mode 100644
index 0000000..52ad4b9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_thread_lifecycle.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_timeout.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_timeout.cpython-38.pyc
new file mode 100644
index 0000000..9fe3621
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_timeout.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_api.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_api.cpython-38.pyc
new file mode 100644
index 0000000..c3292b3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_api.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch.cpython-38.pyc
new file mode 100644
index 0000000..6c3c4e3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch_regular.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch_regular.cpython-38.pyc
new file mode 100644
index 0000000..d8da523
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_trace_dispatch_regular.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_traceproperty.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_traceproperty.cpython-38.pyc
new file mode 100644
index 0000000..d906361
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_traceproperty.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_utils.cpython-38.pyc
new file mode 100644
index 0000000..d298872
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vars.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vars.cpython-38.pyc
new file mode 100644
index 0000000..64454f7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vars.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vm_type.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vm_type.cpython-38.pyc
new file mode 100644
index 0000000..00d1e1a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_vm_type.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_xml.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_xml.cpython-38.pyc
new file mode 100644
index 0000000..73d58da
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/__pycache__/pydevd_xml.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..1119bf6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__main__pydevd_gen_debug_adapter_protocol.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__main__pydevd_gen_debug_adapter_protocol.cpython-38.pyc
new file mode 100644
index 0000000..eaf3cb4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/__main__pydevd_gen_debug_adapter_protocol.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_base_schema.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_base_schema.cpython-38.pyc
new file mode 100644
index 0000000..630f7a7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_base_schema.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema.cpython-38.pyc
new file mode 100644
index 0000000..f630e28
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema_log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema_log.cpython-38.pyc
new file mode 100644
index 0000000..5571bf4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_bundle/_debug_adapter/__pycache__/pydevd_schema_log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..ebfc8b4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_cython_wrapper.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_cython_wrapper.cpython-38.pyc
new file mode 100644
index 0000000..45cb717
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_cython_wrapper.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_main.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_main.cpython-38.pyc
new file mode 100644
index 0000000..1ea491f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_eval_main.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_tracing.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_tracing.cpython-38.pyc
new file mode 100644
index 0000000..1d5862a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_frame_tracing.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_modify_bytecode.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_modify_bytecode.cpython-38.pyc
new file mode 100644
index 0000000..f92f3ca
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/__pycache__/pydevd_modify_bytecode.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..0cb19af
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/pydevd_fix_code.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/pydevd_fix_code.cpython-38.pyc
new file mode 100644
index 0000000..f40f755
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/__pycache__/pydevd_fix_code.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..0eb91d1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/bytecode.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/bytecode.cpython-38.pyc
new file mode 100644
index 0000000..a9aa3bc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/bytecode.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/cfg.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/cfg.cpython-38.pyc
new file mode 100644
index 0000000..804f547
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/cfg.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/concrete.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/concrete.cpython-38.pyc
new file mode 100644
index 0000000..abdd758
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/concrete.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/flags.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/flags.cpython-38.pyc
new file mode 100644
index 0000000..4c6fbf0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/flags.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/instr.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/instr.cpython-38.pyc
new file mode 100644
index 0000000..69a3c2e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/instr.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/peephole_opt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/peephole_opt.cpython-38.pyc
new file mode 100644
index 0000000..960b0fe
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/__pycache__/peephole_opt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..38713b6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_bytecode.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_bytecode.cpython-38.pyc
new file mode 100644
index 0000000..67ffc39
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_bytecode.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_cfg.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_cfg.cpython-38.pyc
new file mode 100644
index 0000000..d6b5cf0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_cfg.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_code.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_code.cpython-38.pyc
new file mode 100644
index 0000000..b810ebb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_code.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_concrete.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_concrete.cpython-38.pyc
new file mode 100644
index 0000000..ad2ebfa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_concrete.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_flags.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_flags.cpython-38.pyc
new file mode 100644
index 0000000..e5da284
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_flags.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_instr.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_instr.cpython-38.pyc
new file mode 100644
index 0000000..c7eae53
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_instr.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_misc.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_misc.cpython-38.pyc
new file mode 100644
index 0000000..442b530
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_misc.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_peephole_opt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_peephole_opt.cpython-38.pyc
new file mode 100644
index 0000000..1a1522f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/_pydevd_frame_eval/vendored/bytecode/tests/__pycache__/test_peephole_opt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..842edcf
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhook.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhook.cpython-38.pyc
new file mode 100644
index 0000000..2de566f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhook.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookglut.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookglut.cpython-38.pyc
new file mode 100644
index 0000000..ba6f3c1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookglut.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk.cpython-38.pyc
new file mode 100644
index 0000000..08f49f7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk3.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk3.cpython-38.pyc
new file mode 100644
index 0000000..90ee3a7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookgtk3.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookpyglet.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookpyglet.cpython-38.pyc
new file mode 100644
index 0000000..7fd6735
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookpyglet.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt4.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt4.cpython-38.pyc
new file mode 100644
index 0000000..a0f798e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt4.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt5.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt5.cpython-38.pyc
new file mode 100644
index 0000000..d133ede
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookqt5.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhooktk.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhooktk.cpython-38.pyc
new file mode 100644
index 0000000..d427c19
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhooktk.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookwx.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookwx.cpython-38.pyc
new file mode 100644
index 0000000..d5459c5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/inputhookwx.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/matplotlibtools.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/matplotlibtools.cpython-38.pyc
new file mode 100644
index 0000000..51a89f3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/matplotlibtools.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt.cpython-38.pyc
new file mode 100644
index 0000000..e5fbb28
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_for_kernel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_for_kernel.cpython-38.pyc
new file mode 100644
index 0000000..6e6beff
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_for_kernel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_loaders.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_loaders.cpython-38.pyc
new file mode 100644
index 0000000..d39dd1a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/qt_loaders.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/version.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/version.cpython-38.pyc
new file mode 100644
index 0000000..46c3280
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_ipython/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_sitecustomize/__pycache__/sitecustomize.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_sitecustomize/__pycache__/sitecustomize.cpython-38.pyc
new file mode 100644
index 0000000..de66f19
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydev_sitecustomize/__pycache__/sitecustomize.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_always_live_program.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_always_live_program.cpython-38.pyc
new file mode 100644
index 0000000..cc234db
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_always_live_program.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process.cpython-38.pyc
new file mode 100644
index 0000000..bc803f8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process_linux.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process_linux.cpython-38.pyc
new file mode 100644
index 0000000..9b2ab2f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/_test_attach_to_process_linux.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/add_code_to_python_process.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/add_code_to_python_process.cpython-38.pyc
new file mode 100644
index 0000000..98ffdce
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/add_code_to_python_process.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_pydevd.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_pydevd.cpython-38.pyc
new file mode 100644
index 0000000..771f36b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_pydevd.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_script.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_script.cpython-38.pyc
new file mode 100644
index 0000000..4fd96af
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/__pycache__/attach_script.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/__pycache__/lldb_prepare.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/__pycache__/lldb_prepare.cpython-38.pyc
new file mode 100644
index 0000000..1c656aa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/linux_and_mac/__pycache__/lldb_prepare.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..a72732a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/breakpoint.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/breakpoint.cpython-38.pyc
new file mode 100644
index 0000000..e65c5a0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/breakpoint.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/compat.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/compat.cpython-38.pyc
new file mode 100644
index 0000000..28aa579
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/crash.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/crash.cpython-38.pyc
new file mode 100644
index 0000000..27d4dc5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/crash.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/debug.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/debug.cpython-38.pyc
new file mode 100644
index 0000000..fee14a6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/debug.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/disasm.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/disasm.cpython-38.pyc
new file mode 100644
index 0000000..8faf007
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/disasm.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/event.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/event.cpython-38.pyc
new file mode 100644
index 0000000..c697d0e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/event.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/interactive.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/interactive.cpython-38.pyc
new file mode 100644
index 0000000..8e1c76f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/interactive.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/module.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/module.cpython-38.pyc
new file mode 100644
index 0000000..d665d4a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/module.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/process.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/process.cpython-38.pyc
new file mode 100644
index 0000000..d989282
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/process.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/registry.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/registry.cpython-38.pyc
new file mode 100644
index 0000000..5c4dccd
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/registry.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/search.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/search.cpython-38.pyc
new file mode 100644
index 0000000..a467e03
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/search.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/sql.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/sql.cpython-38.pyc
new file mode 100644
index 0000000..c55fefb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/sql.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/system.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/system.cpython-38.pyc
new file mode 100644
index 0000000..a0a343d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/system.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/textio.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/textio.cpython-38.pyc
new file mode 100644
index 0000000..47cc46e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/textio.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/thread.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/thread.cpython-38.pyc
new file mode 100644
index 0000000..c9662aa
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/thread.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/util.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/util.cpython-38.pyc
new file mode 100644
index 0000000..d8b2372
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/util.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/window.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/window.cpython-38.pyc
new file mode 100644
index 0000000..6a8d3c0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/__pycache__/window.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..e73d2c9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/do_symfix.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/do_symfix.cpython-38.pyc
new file mode 100644
index 0000000..83b4e04
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/plugins/__pycache__/do_symfix.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..c73e4e1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/advapi32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/advapi32.cpython-38.pyc
new file mode 100644
index 0000000..7b034e3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/advapi32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_amd64.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_amd64.cpython-38.pyc
new file mode 100644
index 0000000..2286423
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_amd64.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_i386.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_i386.cpython-38.pyc
new file mode 100644
index 0000000..4533127
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/context_i386.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/dbghelp.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/dbghelp.cpython-38.pyc
new file mode 100644
index 0000000..067b1f5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/dbghelp.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/defines.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/defines.cpython-38.pyc
new file mode 100644
index 0000000..fc123a7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/defines.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/gdi32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/gdi32.cpython-38.pyc
new file mode 100644
index 0000000..615d281
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/gdi32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/kernel32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/kernel32.cpython-38.pyc
new file mode 100644
index 0000000..b74b068
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/kernel32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/ntdll.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/ntdll.cpython-38.pyc
new file mode 100644
index 0000000..f566cdc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/ntdll.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/peb_teb.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/peb_teb.cpython-38.pyc
new file mode 100644
index 0000000..2d5bee0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/peb_teb.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/psapi.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/psapi.cpython-38.pyc
new file mode 100644
index 0000000..f7bbfe4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/psapi.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shell32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shell32.cpython-38.pyc
new file mode 100644
index 0000000..46c4a29
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shell32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shlwapi.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shlwapi.cpython-38.pyc
new file mode 100644
index 0000000..30dad2a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/shlwapi.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/user32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/user32.cpython-38.pyc
new file mode 100644
index 0000000..149f5a3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/user32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/version.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/version.cpython-38.pyc
new file mode 100644
index 0000000..4a3396e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/version.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/wtsapi32.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/wtsapi32.cpython-38.pyc
new file mode 100644
index 0000000..9d6d86f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_attach_to_process/winappdbg/win32/__pycache__/wtsapi32.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..700fe8d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_concurrency_logger.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_concurrency_logger.cpython-38.pyc
new file mode 100644
index 0000000..a829c56
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_concurrency_logger.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_thread_wrappers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_thread_wrappers.cpython-38.pyc
new file mode 100644
index 0000000..0a673ac
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_concurrency_analyser/__pycache__/pydevd_thread_wrappers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..43643d2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/django_debug.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/django_debug.cpython-38.pyc
new file mode 100644
index 0000000..475217e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/django_debug.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/jinja2_debug.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/jinja2_debug.cpython-38.pyc
new file mode 100644
index 0000000..7aba086
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/__pycache__/jinja2_debug.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..89f117c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..e8d704c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_helpers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_helpers.cpython-38.pyc
new file mode 100644
index 0000000..955c83c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_helpers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugin_numpy_types.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugin_numpy_types.cpython-38.pyc
new file mode 100644
index 0000000..4e22e96
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugin_numpy_types.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugins_django_form_str.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugins_django_form_str.cpython-38.pyc
new file mode 100644
index 0000000..49bca91
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/_vendored/pydevd/pydevd_plugins/extensions/types/__pycache__/pydevd_plugins_django_form_str.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..9ee7a77
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__main__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__main__.cpython-38.pyc
new file mode 100644
index 0000000..37e9208
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/clients.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/clients.cpython-38.pyc
new file mode 100644
index 0000000..4917192
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/clients.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/components.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/components.cpython-38.pyc
new file mode 100644
index 0000000..62489bb
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/components.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/launchers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/launchers.cpython-38.pyc
new file mode 100644
index 0000000..95af5c7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/launchers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/servers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/servers.cpython-38.pyc
new file mode 100644
index 0000000..f924cd4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/servers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/sessions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/sessions.cpython-38.pyc
new file mode 100644
index 0000000..860e1e0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/adapter/__pycache__/sessions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..957401b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/compat.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/compat.cpython-38.pyc
new file mode 100644
index 0000000..2f2e71c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/compat.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/fmt.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/fmt.cpython-38.pyc
new file mode 100644
index 0000000..12ebfb0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/fmt.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/json.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/json.cpython-38.pyc
new file mode 100644
index 0000000..6e30351
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/json.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/log.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/log.cpython-38.pyc
new file mode 100644
index 0000000..e36f43c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/log.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/messaging.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/messaging.cpython-38.pyc
new file mode 100644
index 0000000..260d2a6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/messaging.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/modules.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/modules.cpython-38.pyc
new file mode 100644
index 0000000..5c6e6d5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/modules.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/singleton.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/singleton.cpython-38.pyc
new file mode 100644
index 0000000..fd07e46
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/singleton.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/sockets.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/sockets.cpython-38.pyc
new file mode 100644
index 0000000..4240887
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/sockets.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/stacks.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/stacks.cpython-38.pyc
new file mode 100644
index 0000000..a2c06f3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/stacks.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/timestamp.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/timestamp.cpython-38.pyc
new file mode 100644
index 0000000..511745a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/timestamp.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/util.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/util.cpython-38.pyc
new file mode 100644
index 0000000..8d9d21d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/common/__pycache__/util.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..7406e34
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__main__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__main__.cpython-38.pyc
new file mode 100644
index 0000000..f27dc46
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/debuggee.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/debuggee.cpython-38.pyc
new file mode 100644
index 0000000..49756b1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/debuggee.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/handlers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/handlers.cpython-38.pyc
new file mode 100644
index 0000000..37746fc
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/handlers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/output.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/output.cpython-38.pyc
new file mode 100644
index 0000000..3ea39d3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/output.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/winapi.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/winapi.cpython-38.pyc
new file mode 100644
index 0000000..93d0006
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/launcher/__pycache__/winapi.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..50adc8d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/api.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/api.cpython-38.pyc
new file mode 100644
index 0000000..1811369
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/api.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/attach_pid_injected.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/attach_pid_injected.cpython-38.pyc
new file mode 100644
index 0000000..6761f26
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/attach_pid_injected.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/cli.cpython-38.pyc b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/cli.cpython-38.pyc
new file mode 100644
index 0000000..baf20d8
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/debugpy/server/__pycache__/cli.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/INSTALLER b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/METADATA b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/METADATA
new file mode 100644
index 0000000..c6af761
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/METADATA
@@ -0,0 +1,16 @@
+Metadata-Version: 2.1
+Name: discord
+Version: 1.7.3
+Summary: A mirror package for discord.py. Please install that instead.
+Home-page: https://github.com/Rapptz/discord.py
+Author: Rapptz
+License: UNKNOWN
+Platform: UNKNOWN
+Description-Content-Type: text/markdown
+Requires-Dist: discord.py (>=1.7.3)
+
+### This is a mirror package!
+
+It is recommended to install `discord.py` instead.
+
+
diff --git a/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/RECORD b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/RECORD
new file mode 100644
index 0000000..b268436
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/RECORD
@@ -0,0 +1,7 @@
+discord-1.7.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+discord-1.7.3.dist-info/METADATA,sha256=n_9Ixt5dzxkh1D1fpEw-Rp6R_xpulL13WhThIskWQ8U,381
+discord-1.7.3.dist-info/RECORD,,
+discord-1.7.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+discord-1.7.3.dist-info/WHEEL,sha256=OqRkF0eY5GHssMorFjlbTIq072vpHpF60fIQA6lS9xA,92
+discord-1.7.3.dist-info/direct_url.json,sha256=odZKKWfc7LgqU3GotYGpiA5Nm3eyTu6-kUI3VXm4Qes,175
+discord-1.7.3.dist-info/top_level.txt,sha256=AbpHGcgLb-kRsJGnwFEktk7uzpZOCcBY74-YBdrKVGs,1
diff --git a/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/REQUESTED b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/direct_url.json b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/direct_url.json
new file mode 100644
index 0000000..e044fb0
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord-1.7.3.dist-info/direct_url.json
@@ -0,0 +1 @@
+{"archive_info": {}, "url": "file:///home/runner/.cache/pypoetry/artifacts/0f/cc/0e/0dd848b2518df98bf9b6e4de7030042dd09e0aa66d5bdb982bf67023fe/discord-1.7.3-py3-none-any.whl"}
\ No newline at end of file
diff --git a/venv/lib64/python3.8/site-packages/discord/__init__.py b/venv/lib64/python3.8/site-packages/discord/__init__.py
new file mode 100644
index 0000000..e2c8101
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/__init__.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+
+"""
+Discord API Wrapper
+~~~~~~~~~~~~~~~~~~~
+
+A basic wrapper for the Discord API.
+
+:copyright: (c) 2015-present Rapptz
+:license: MIT, see LICENSE for more details.
+
+"""
+
+__title__ = 'discord'
+__author__ = 'Rapptz'
+__license__ = 'MIT'
+__copyright__ = 'Copyright 2015-present Rapptz'
+__version__ = '1.7.3'
+
+__path__ = __import__('pkgutil').extend_path(__path__, __name__)
+
+from collections import namedtuple
+import logging
+
+from .client import Client
+from .appinfo import AppInfo
+from .user import User, ClientUser, Profile
+from .emoji import Emoji
+from .partial_emoji import PartialEmoji
+from .activity import *
+from .channel import *
+from .guild import Guild
+from .flags import *
+from .relationship import Relationship
+from .member import Member, VoiceState
+from .message import *
+from .asset import Asset
+from .errors import *
+from .calls import CallMessage, GroupCall
+from .permissions import Permissions, PermissionOverwrite
+from .role import Role, RoleTags
+from .file import File
+from .colour import Color, Colour
+from .integrations import Integration, IntegrationAccount
+from .invite import Invite, PartialInviteChannel, PartialInviteGuild
+from .template import Template
+from .widget import Widget, WidgetMember, WidgetChannel
+from .object import Object
+from .reaction import Reaction
+from . import utils, opus, abc
+from .enums import *
+from .embeds import Embed
+from .mentions import AllowedMentions
+from .shard import AutoShardedClient, ShardInfo
+from .player import *
+from .webhook import *
+from .voice_client import VoiceClient, VoiceProtocol
+from .audit_logs import AuditLogChanges, AuditLogEntry, AuditLogDiff
+from .raw_models import *
+from .team import *
+from .sticker import Sticker
+
+VersionInfo = namedtuple('VersionInfo', 'major minor micro releaselevel serial')
+
+version_info = VersionInfo(major=1, minor=7, micro=3, releaselevel='final', serial=0)
+
+logging.getLogger(__name__).addHandler(logging.NullHandler())
diff --git a/venv/lib64/python3.8/site-packages/discord/__main__.py b/venv/lib64/python3.8/site-packages/discord/__main__.py
new file mode 100644
index 0000000..9252835
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/__main__.py
@@ -0,0 +1,305 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import argparse
+import sys
+from pathlib import Path
+
+import discord
+import pkg_resources
+import aiohttp
+import platform
+
+def show_version():
+ entries = []
+
+ entries.append('- Python v{0.major}.{0.minor}.{0.micro}-{0.releaselevel}'.format(sys.version_info))
+ version_info = discord.version_info
+ entries.append('- discord.py v{0.major}.{0.minor}.{0.micro}-{0.releaselevel}'.format(version_info))
+ if version_info.releaselevel != 'final':
+ pkg = pkg_resources.get_distribution('discord.py')
+ if pkg:
+ entries.append(' - discord.py pkg_resources: v{0}'.format(pkg.version))
+
+ entries.append('- aiohttp v{0.__version__}'.format(aiohttp))
+ uname = platform.uname()
+ entries.append('- system info: {0.system} {0.release} {0.version}'.format(uname))
+ print('\n'.join(entries))
+
+def core(parser, args):
+ if args.version:
+ show_version()
+
+bot_template = """#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+
+from discord.ext import commands
+import discord
+import config
+
+class Bot(commands.{base}):
+ def __init__(self, **kwargs):
+ super().__init__(command_prefix=commands.when_mentioned_or('{prefix}'), **kwargs)
+ for cog in config.cogs:
+ try:
+ self.load_extension(cog)
+ except Exception as exc:
+ print('Could not load extension {{0}} due to {{1.__class__.__name__}}: {{1}}'.format(cog, exc))
+
+ async def on_ready(self):
+ print('Logged on as {{0}} (ID: {{0.id}})'.format(self.user))
+
+
+bot = Bot()
+
+# write general commands here
+
+bot.run(config.token)
+"""
+
+gitignore_template = """# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# Our configuration files
+config.py
+"""
+
+cog_template = '''# -*- coding: utf-8 -*-
+
+from discord.ext import commands
+import discord
+
+class {name}(commands.Cog{attrs}):
+ """The description for {name} goes here."""
+
+ def __init__(self, bot):
+ self.bot = bot
+{extra}
+def setup(bot):
+ bot.add_cog({name}(bot))
+'''
+
+cog_extras = '''
+ def cog_unload(self):
+ # clean up logic goes here
+ pass
+
+ async def cog_check(self, ctx):
+ # checks that apply to every command in here
+ return True
+
+ async def bot_check(self, ctx):
+ # checks that apply to every command to the bot
+ return True
+
+ async def bot_check_once(self, ctx):
+ # check that apply to every command but is guaranteed to be called only once
+ return True
+
+ async def cog_command_error(self, ctx, error):
+ # error handling to every command in here
+ pass
+
+ async def cog_before_invoke(self, ctx):
+ # called before a command is called here
+ pass
+
+ async def cog_after_invoke(self, ctx):
+ # called after a command is called here
+ pass
+
+'''
+
+
+# certain file names and directory names are forbidden
+# see: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247%28v=vs.85%29.aspx
+# although some of this doesn't apply to Linux, we might as well be consistent
+_base_table = {
+ '<': '-',
+ '>': '-',
+ ':': '-',
+ '"': '-',
+ # '/': '-', these are fine
+ # '\\': '-',
+ '|': '-',
+ '?': '-',
+ '*': '-',
+}
+
+# NUL (0) and 1-31 are disallowed
+_base_table.update((chr(i), None) for i in range(32))
+
+translation_table = str.maketrans(_base_table)
+
+def to_path(parser, name, *, replace_spaces=False):
+ if isinstance(name, Path):
+ return name
+
+ if sys.platform == 'win32':
+ forbidden = ('CON', 'PRN', 'AUX', 'NUL', 'COM1', 'COM2', 'COM3', 'COM4', 'COM5', 'COM6', 'COM7', \
+ 'COM8', 'COM9', 'LPT1', 'LPT2', 'LPT3', 'LPT4', 'LPT5', 'LPT6', 'LPT7', 'LPT8', 'LPT9')
+ if len(name) <= 4 and name.upper() in forbidden:
+ parser.error('invalid directory name given, use a different one')
+
+ name = name.translate(translation_table)
+ if replace_spaces:
+ name = name.replace(' ', '-')
+ return Path(name)
+
+def newbot(parser, args):
+ new_directory = to_path(parser, args.directory) / to_path(parser, args.name)
+
+ # as a note exist_ok for Path is a 3.5+ only feature
+ # since we already checked above that we're >3.5
+ try:
+ new_directory.mkdir(exist_ok=True, parents=True)
+ except OSError as exc:
+ parser.error('could not create our bot directory ({})'.format(exc))
+
+ cogs = new_directory / 'cogs'
+
+ try:
+ cogs.mkdir(exist_ok=True)
+ init = cogs / '__init__.py'
+ init.touch()
+ except OSError as exc:
+ print('warning: could not create cogs directory ({})'.format(exc))
+
+ try:
+ with open(str(new_directory / 'config.py'), 'w', encoding='utf-8') as fp:
+ fp.write('token = "place your token here"\ncogs = []\n')
+ except OSError as exc:
+ parser.error('could not create config file ({})'.format(exc))
+
+ try:
+ with open(str(new_directory / 'bot.py'), 'w', encoding='utf-8') as fp:
+ base = 'Bot' if not args.sharded else 'AutoShardedBot'
+ fp.write(bot_template.format(base=base, prefix=args.prefix))
+ except OSError as exc:
+ parser.error('could not create bot file ({})'.format(exc))
+
+ if not args.no_git:
+ try:
+ with open(str(new_directory / '.gitignore'), 'w', encoding='utf-8') as fp:
+ fp.write(gitignore_template)
+ except OSError as exc:
+ print('warning: could not create .gitignore file ({})'.format(exc))
+
+ print('successfully made bot at', new_directory)
+
+def newcog(parser, args):
+ cog_dir = to_path(parser, args.directory)
+ try:
+ cog_dir.mkdir(exist_ok=True)
+ except OSError as exc:
+ print('warning: could not create cogs directory ({})'.format(exc))
+
+ directory = cog_dir / to_path(parser, args.name)
+ directory = directory.with_suffix('.py')
+ try:
+ with open(str(directory), 'w', encoding='utf-8') as fp:
+ attrs = ''
+ extra = cog_extras if args.full else ''
+ if args.class_name:
+ name = args.class_name
+ else:
+ name = str(directory.stem)
+ if '-' in name or '_' in name:
+ translation = str.maketrans('-_', ' ')
+ name = name.translate(translation).title().replace(' ', '')
+ else:
+ name = name.title()
+
+ if args.display_name:
+ attrs += ', name="{}"'.format(args.display_name)
+ if args.hide_commands:
+ attrs += ', command_attrs=dict(hidden=True)'
+ fp.write(cog_template.format(name=name, extra=extra, attrs=attrs))
+ except OSError as exc:
+ parser.error('could not create cog file ({})'.format(exc))
+ else:
+ print('successfully made cog at', directory)
+
+def add_newbot_args(subparser):
+ parser = subparser.add_parser('newbot', help='creates a command bot project quickly')
+ parser.set_defaults(func=newbot)
+
+ parser.add_argument('name', help='the bot project name')
+ parser.add_argument('directory', help='the directory to place it in (default: .)', nargs='?', default=Path.cwd())
+ parser.add_argument('--prefix', help='the bot prefix (default: $)', default='$', metavar='')
+ parser.add_argument('--sharded', help='whether to use AutoShardedBot', action='store_true')
+ parser.add_argument('--no-git', help='do not create a .gitignore file', action='store_true', dest='no_git')
+
+def add_newcog_args(subparser):
+ parser = subparser.add_parser('newcog', help='creates a new cog template quickly')
+ parser.set_defaults(func=newcog)
+
+ parser.add_argument('name', help='the cog name')
+ parser.add_argument('directory', help='the directory to place it in (default: cogs)', nargs='?', default=Path('cogs'))
+ parser.add_argument('--class-name', help='the class name of the cog (default: )', dest='class_name')
+ parser.add_argument('--display-name', help='the cog name (default: )')
+ parser.add_argument('--hide-commands', help='whether to hide all commands in the cog', action='store_true')
+ parser.add_argument('--full', help='add all special methods as well', action='store_true')
+
+def parse_args():
+ parser = argparse.ArgumentParser(prog='discord', description='Tools for helping with discord.py')
+ parser.add_argument('-v', '--version', action='store_true', help='shows the library version')
+ parser.set_defaults(func=core)
+
+ subparser = parser.add_subparsers(dest='subcommand', title='subcommands')
+ add_newbot_args(subparser)
+ add_newcog_args(subparser)
+ return parser, parser.parse_args()
+
+def main():
+ parser, args = parse_args()
+ args.func(parser, args)
+
+if __name__ == '__main__':
+ main()
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..ecfafb3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/__main__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/__main__.cpython-38.pyc
new file mode 100644
index 0000000..0aacd77
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/__main__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/abc.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/abc.cpython-38.pyc
new file mode 100644
index 0000000..f2d245e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/abc.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/activity.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/activity.cpython-38.pyc
new file mode 100644
index 0000000..b7e4ba5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/activity.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/appinfo.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/appinfo.cpython-38.pyc
new file mode 100644
index 0000000..d83c3ad
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/appinfo.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/asset.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/asset.cpython-38.pyc
new file mode 100644
index 0000000..27833e2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/asset.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/audit_logs.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/audit_logs.cpython-38.pyc
new file mode 100644
index 0000000..dbdacc9
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/audit_logs.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/backoff.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/backoff.cpython-38.pyc
new file mode 100644
index 0000000..9c431e3
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/backoff.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/calls.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/calls.cpython-38.pyc
new file mode 100644
index 0000000..895b6dd
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/calls.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/channel.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/channel.cpython-38.pyc
new file mode 100644
index 0000000..4c49223
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/channel.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/client.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/client.cpython-38.pyc
new file mode 100644
index 0000000..fd2e20e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/client.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/colour.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/colour.cpython-38.pyc
new file mode 100644
index 0000000..5f211db
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/colour.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/context_managers.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/context_managers.cpython-38.pyc
new file mode 100644
index 0000000..6624b0d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/context_managers.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/embeds.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/embeds.cpython-38.pyc
new file mode 100644
index 0000000..5265e1e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/embeds.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/emoji.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/emoji.cpython-38.pyc
new file mode 100644
index 0000000..39f670d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/emoji.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/enums.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/enums.cpython-38.pyc
new file mode 100644
index 0000000..5d1851a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/enums.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/errors.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/errors.cpython-38.pyc
new file mode 100644
index 0000000..b6f51d1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/errors.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/file.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/file.cpython-38.pyc
new file mode 100644
index 0000000..3308bcf
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/file.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/flags.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/flags.cpython-38.pyc
new file mode 100644
index 0000000..df6cf4c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/flags.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/gateway.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/gateway.cpython-38.pyc
new file mode 100644
index 0000000..d221d8d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/gateway.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/guild.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/guild.cpython-38.pyc
new file mode 100644
index 0000000..11fdd76
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/guild.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/http.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/http.cpython-38.pyc
new file mode 100644
index 0000000..b75c506
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/http.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/integrations.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/integrations.cpython-38.pyc
new file mode 100644
index 0000000..a61fad0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/integrations.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/invite.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/invite.cpython-38.pyc
new file mode 100644
index 0000000..3e0a650
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/invite.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/iterators.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/iterators.cpython-38.pyc
new file mode 100644
index 0000000..8e7f2a4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/iterators.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/member.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/member.cpython-38.pyc
new file mode 100644
index 0000000..1f38f44
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/member.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/mentions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/mentions.cpython-38.pyc
new file mode 100644
index 0000000..4c75b1e
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/mentions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/message.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/message.cpython-38.pyc
new file mode 100644
index 0000000..4aa48ce
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/message.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/mixins.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/mixins.cpython-38.pyc
new file mode 100644
index 0000000..44759d4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/mixins.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/object.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/object.cpython-38.pyc
new file mode 100644
index 0000000..5815b12
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/object.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/oggparse.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/oggparse.cpython-38.pyc
new file mode 100644
index 0000000..95b8614
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/oggparse.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/opus.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/opus.cpython-38.pyc
new file mode 100644
index 0000000..115ddee
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/opus.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/partial_emoji.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/partial_emoji.cpython-38.pyc
new file mode 100644
index 0000000..9fcf5ff
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/partial_emoji.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/permissions.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/permissions.cpython-38.pyc
new file mode 100644
index 0000000..157ef44
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/permissions.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/player.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/player.cpython-38.pyc
new file mode 100644
index 0000000..cfc18c4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/player.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/raw_models.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/raw_models.cpython-38.pyc
new file mode 100644
index 0000000..f8d5a81
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/raw_models.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/reaction.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/reaction.cpython-38.pyc
new file mode 100644
index 0000000..0ff1e89
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/reaction.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/relationship.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/relationship.cpython-38.pyc
new file mode 100644
index 0000000..c9fa5d0
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/relationship.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/role.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/role.cpython-38.pyc
new file mode 100644
index 0000000..1f00d26
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/role.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/shard.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/shard.cpython-38.pyc
new file mode 100644
index 0000000..4c1611c
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/shard.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/state.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/state.cpython-38.pyc
new file mode 100644
index 0000000..c7be6a5
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/state.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/sticker.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/sticker.cpython-38.pyc
new file mode 100644
index 0000000..218c2f4
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/sticker.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/team.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/team.cpython-38.pyc
new file mode 100644
index 0000000..ea79aac
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/team.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/template.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/template.cpython-38.pyc
new file mode 100644
index 0000000..71cbf43
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/template.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/user.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/user.cpython-38.pyc
new file mode 100644
index 0000000..16076b7
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/user.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/utils.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/utils.cpython-38.pyc
new file mode 100644
index 0000000..e07c3a6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/utils.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/voice_client.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/voice_client.cpython-38.pyc
new file mode 100644
index 0000000..833e49f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/voice_client.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/webhook.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/webhook.cpython-38.pyc
new file mode 100644
index 0000000..f71e35f
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/webhook.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/__pycache__/widget.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/__pycache__/widget.cpython-38.pyc
new file mode 100644
index 0000000..3593626
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/__pycache__/widget.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/abc.py b/venv/lib64/python3.8/site-packages/discord/abc.py
new file mode 100644
index 0000000..0e48a2f
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/abc.py
@@ -0,0 +1,1294 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import abc
+import sys
+import copy
+import asyncio
+
+from .iterators import HistoryIterator
+from .context_managers import Typing
+from .enums import ChannelType
+from .errors import InvalidArgument, ClientException
+from .mentions import AllowedMentions
+from .permissions import PermissionOverwrite, Permissions
+from .role import Role
+from .invite import Invite
+from .file import File
+from .voice_client import VoiceClient, VoiceProtocol
+from . import utils
+
+class _Undefined:
+ def __repr__(self):
+ return 'see-below'
+
+_undefined = _Undefined()
+
+class Snowflake(metaclass=abc.ABCMeta):
+ """An ABC that details the common operations on a Discord model.
+
+ Almost all :ref:`Discord models ` meet this
+ abstract base class.
+
+ If you want to create a snowflake on your own, consider using
+ :class:`.Object`.
+
+ Attributes
+ -----------
+ id: :class:`int`
+ The model's unique ID.
+ """
+ __slots__ = ()
+
+ @property
+ @abc.abstractmethod
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the model's creation time as a naive datetime in UTC."""
+ raise NotImplementedError
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is Snowflake:
+ mro = C.__mro__
+ for attr in ('created_at', 'id'):
+ for base in mro:
+ if attr in base.__dict__:
+ break
+ else:
+ return NotImplemented
+ return True
+ return NotImplemented
+
+class User(metaclass=abc.ABCMeta):
+ """An ABC that details the common operations on a Discord user.
+
+ The following implement this ABC:
+
+ - :class:`~discord.User`
+ - :class:`~discord.ClientUser`
+ - :class:`~discord.Member`
+
+ This ABC must also implement :class:`~discord.abc.Snowflake`.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The user's username.
+ discriminator: :class:`str`
+ The user's discriminator.
+ avatar: Optional[:class:`str`]
+ The avatar hash the user has.
+ bot: :class:`bool`
+ If the user is a bot account.
+ """
+ __slots__ = ()
+
+ @property
+ @abc.abstractmethod
+ def display_name(self):
+ """:class:`str`: Returns the user's display name."""
+ raise NotImplementedError
+
+ @property
+ @abc.abstractmethod
+ def mention(self):
+ """:class:`str`: Returns a string that allows you to mention the given user."""
+ raise NotImplementedError
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is User:
+ if Snowflake.__subclasshook__(C) is NotImplemented:
+ return NotImplemented
+
+ mro = C.__mro__
+ for attr in ('display_name', 'mention', 'name', 'avatar', 'discriminator', 'bot'):
+ for base in mro:
+ if attr in base.__dict__:
+ break
+ else:
+ return NotImplemented
+ return True
+ return NotImplemented
+
+class PrivateChannel(metaclass=abc.ABCMeta):
+ """An ABC that details the common operations on a private Discord channel.
+
+ The following implement this ABC:
+
+ - :class:`~discord.DMChannel`
+ - :class:`~discord.GroupChannel`
+
+ This ABC must also implement :class:`~discord.abc.Snowflake`.
+
+ Attributes
+ -----------
+ me: :class:`~discord.ClientUser`
+ The user presenting yourself.
+ """
+ __slots__ = ()
+
+ @classmethod
+ def __subclasshook__(cls, C):
+ if cls is PrivateChannel:
+ if Snowflake.__subclasshook__(C) is NotImplemented:
+ return NotImplemented
+
+ mro = C.__mro__
+ for base in mro:
+ if 'me' in base.__dict__:
+ return True
+ return NotImplemented
+ return NotImplemented
+
+class _Overwrites:
+ __slots__ = ('id', 'allow', 'deny', 'type')
+
+ def __init__(self, **kwargs):
+ self.id = kwargs.pop('id')
+ self.allow = int(kwargs.pop('allow_new', 0))
+ self.deny = int(kwargs.pop('deny_new', 0))
+ self.type = sys.intern(kwargs.pop('type'))
+
+ def _asdict(self):
+ return {
+ 'id': self.id,
+ 'allow': str(self.allow),
+ 'deny': str(self.deny),
+ 'type': self.type,
+ }
+
+class GuildChannel:
+ """An ABC that details the common operations on a Discord guild channel.
+
+ The following implement this ABC:
+
+ - :class:`~discord.TextChannel`
+ - :class:`~discord.VoiceChannel`
+ - :class:`~discord.CategoryChannel`
+ - :class:`~discord.StageChannel`
+
+ This ABC must also implement :class:`~discord.abc.Snowflake`.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The channel name.
+ guild: :class:`~discord.Guild`
+ The guild the channel belongs to.
+ position: :class:`int`
+ The position in the channel list. This is a number that starts at 0.
+ e.g. the top channel is position 0.
+ """
+ __slots__ = ()
+
+ def __str__(self):
+ return self.name
+
+ @property
+ def _sorting_bucket(self):
+ raise NotImplementedError
+
+ async def _move(self, position, parent_id=None, lock_permissions=False, *, reason):
+ if position < 0:
+ raise InvalidArgument('Channel position cannot be less than 0.')
+
+ http = self._state.http
+ bucket = self._sorting_bucket
+ channels = [c for c in self.guild.channels if c._sorting_bucket == bucket]
+
+ channels.sort(key=lambda c: c.position)
+
+ try:
+ # remove ourselves from the channel list
+ channels.remove(self)
+ except ValueError:
+ # not there somehow lol
+ return
+ else:
+ index = next((i for i, c in enumerate(channels) if c.position >= position), len(channels))
+ # add ourselves at our designated position
+ channels.insert(index, self)
+
+ payload = []
+ for index, c in enumerate(channels):
+ d = {'id': c.id, 'position': index}
+ if parent_id is not _undefined and c.id == self.id:
+ d.update(parent_id=parent_id, lock_permissions=lock_permissions)
+ payload.append(d)
+
+ await http.bulk_channel_update(self.guild.id, payload, reason=reason)
+ self.position = position
+ if parent_id is not _undefined:
+ self.category_id = int(parent_id) if parent_id else None
+
+ async def _edit(self, options, reason):
+ try:
+ parent = options.pop('category')
+ except KeyError:
+ parent_id = _undefined
+ else:
+ parent_id = parent and parent.id
+
+ try:
+ options['rate_limit_per_user'] = options.pop('slowmode_delay')
+ except KeyError:
+ pass
+
+ try:
+ rtc_region = options.pop('rtc_region')
+ except KeyError:
+ pass
+ else:
+ options['rtc_region'] = None if rtc_region is None else str(rtc_region)
+
+ lock_permissions = options.pop('sync_permissions', False)
+
+ try:
+ position = options.pop('position')
+ except KeyError:
+ if parent_id is not _undefined:
+ if lock_permissions:
+ category = self.guild.get_channel(parent_id)
+ options['permission_overwrites'] = [c._asdict() for c in category._overwrites]
+ options['parent_id'] = parent_id
+ elif lock_permissions and self.category_id is not None:
+ # if we're syncing permissions on a pre-existing channel category without changing it
+ # we need to update the permissions to point to the pre-existing category
+ category = self.guild.get_channel(self.category_id)
+ options['permission_overwrites'] = [c._asdict() for c in category._overwrites]
+ else:
+ await self._move(position, parent_id=parent_id, lock_permissions=lock_permissions, reason=reason)
+
+ overwrites = options.get('overwrites', None)
+ if overwrites is not None:
+ perms = []
+ for target, perm in overwrites.items():
+ if not isinstance(perm, PermissionOverwrite):
+ raise InvalidArgument('Expected PermissionOverwrite received {0.__name__}'.format(type(perm)))
+
+ allow, deny = perm.pair()
+ payload = {
+ 'allow': allow.value,
+ 'deny': deny.value,
+ 'id': target.id
+ }
+
+ if isinstance(target, Role):
+ payload['type'] = 'role'
+ else:
+ payload['type'] = 'member'
+
+ perms.append(payload)
+ options['permission_overwrites'] = perms
+
+ try:
+ ch_type = options['type']
+ except KeyError:
+ pass
+ else:
+ if not isinstance(ch_type, ChannelType):
+ raise InvalidArgument('type field must be of type ChannelType')
+ options['type'] = ch_type.value
+
+ if options:
+ data = await self._state.http.edit_channel(self.id, reason=reason, **options)
+ self._update(self.guild, data)
+
+ def _fill_overwrites(self, data):
+ self._overwrites = []
+ everyone_index = 0
+ everyone_id = self.guild.id
+
+ for index, overridden in enumerate(data.get('permission_overwrites', [])):
+ overridden_id = int(overridden.pop('id'))
+ self._overwrites.append(_Overwrites(id=overridden_id, **overridden))
+
+ if overridden['type'] == 'member':
+ continue
+
+ if overridden_id == everyone_id:
+ # the @everyone role is not guaranteed to be the first one
+ # in the list of permission overwrites, however the permission
+ # resolution code kind of requires that it is the first one in
+ # the list since it is special. So we need the index so we can
+ # swap it to be the first one.
+ everyone_index = index
+
+ # do the swap
+ tmp = self._overwrites
+ if tmp:
+ tmp[everyone_index], tmp[0] = tmp[0], tmp[everyone_index]
+
+ @property
+ def changed_roles(self):
+ """List[:class:`~discord.Role`]: Returns a list of roles that have been overridden from
+ their default values in the :attr:`~discord.Guild.roles` attribute."""
+ ret = []
+ g = self.guild
+ for overwrite in filter(lambda o: o.type == 'role', self._overwrites):
+ role = g.get_role(overwrite.id)
+ if role is None:
+ continue
+
+ role = copy.copy(role)
+ role.permissions.handle_overwrite(overwrite.allow, overwrite.deny)
+ ret.append(role)
+ return ret
+
+ @property
+ def mention(self):
+ """:class:`str`: The string that allows you to mention the channel."""
+ return '<#%s>' % self.id
+
+ @property
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the channel's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ def overwrites_for(self, obj):
+ """Returns the channel-specific overwrites for a member or a role.
+
+ Parameters
+ -----------
+ obj: Union[:class:`~discord.Role`, :class:`~discord.abc.User`]
+ The role or user denoting
+ whose overwrite to get.
+
+ Returns
+ ---------
+ :class:`~discord.PermissionOverwrite`
+ The permission overwrites for this object.
+ """
+
+ if isinstance(obj, User):
+ predicate = lambda p: p.type == 'member'
+ elif isinstance(obj, Role):
+ predicate = lambda p: p.type == 'role'
+ else:
+ predicate = lambda p: True
+
+ for overwrite in filter(predicate, self._overwrites):
+ if overwrite.id == obj.id:
+ allow = Permissions(overwrite.allow)
+ deny = Permissions(overwrite.deny)
+ return PermissionOverwrite.from_pair(allow, deny)
+
+ return PermissionOverwrite()
+
+ @property
+ def overwrites(self):
+ """Returns all of the channel's overwrites.
+
+ This is returned as a dictionary where the key contains the target which
+ can be either a :class:`~discord.Role` or a :class:`~discord.Member` and the value is the
+ overwrite as a :class:`~discord.PermissionOverwrite`.
+
+ Returns
+ --------
+ Mapping[Union[:class:`~discord.Role`, :class:`~discord.Member`], :class:`~discord.PermissionOverwrite`]
+ The channel's permission overwrites.
+ """
+ ret = {}
+ for ow in self._overwrites:
+ allow = Permissions(ow.allow)
+ deny = Permissions(ow.deny)
+ overwrite = PermissionOverwrite.from_pair(allow, deny)
+
+ if ow.type == 'role':
+ target = self.guild.get_role(ow.id)
+ elif ow.type == 'member':
+ target = self.guild.get_member(ow.id)
+
+ # TODO: There is potential data loss here in the non-chunked
+ # case, i.e. target is None because get_member returned nothing.
+ # This can be fixed with a slight breaking change to the return type,
+ # i.e. adding discord.Object to the list of it
+ # However, for now this is an acceptable compromise.
+ if target is not None:
+ ret[target] = overwrite
+ return ret
+
+ @property
+ def category(self):
+ """Optional[:class:`~discord.CategoryChannel`]: The category this channel belongs to.
+
+ If there is no category then this is ``None``.
+ """
+ return self.guild.get_channel(self.category_id)
+
+ @property
+ def permissions_synced(self):
+ """:class:`bool`: Whether or not the permissions for this channel are synced with the
+ category it belongs to.
+
+ If there is no category then this is ``False``.
+
+ .. versionadded:: 1.3
+ """
+ category = self.guild.get_channel(self.category_id)
+ return bool(category and category.overwrites == self.overwrites)
+
+ def permissions_for(self, member):
+ """Handles permission resolution for the current :class:`~discord.Member`.
+
+ This function takes into consideration the following cases:
+
+ - Guild owner
+ - Guild roles
+ - Channel overrides
+ - Member overrides
+
+ Parameters
+ ----------
+ member: :class:`~discord.Member`
+ The member to resolve permissions for.
+
+ Returns
+ -------
+ :class:`~discord.Permissions`
+ The resolved permissions for the member.
+ """
+
+ # The current cases can be explained as:
+ # Guild owner get all permissions -- no questions asked. Otherwise...
+ # The @everyone role gets the first application.
+ # After that, the applied roles that the user has in the channel
+ # (or otherwise) are then OR'd together.
+ # After the role permissions are resolved, the member permissions
+ # have to take into effect.
+ # After all that is done.. you have to do the following:
+
+ # If manage permissions is True, then all permissions are set to True.
+
+ # The operation first takes into consideration the denied
+ # and then the allowed.
+
+ if self.guild.owner_id == member.id:
+ return Permissions.all()
+
+ default = self.guild.default_role
+ base = Permissions(default.permissions.value)
+ roles = member._roles
+ get_role = self.guild.get_role
+
+ # Apply guild roles that the member has.
+ for role_id in roles:
+ role = get_role(role_id)
+ if role is not None:
+ base.value |= role._permissions
+
+ # Guild-wide Administrator -> True for everything
+ # Bypass all channel-specific overrides
+ if base.administrator:
+ return Permissions.all()
+
+ # Apply @everyone allow/deny first since it's special
+ try:
+ maybe_everyone = self._overwrites[0]
+ if maybe_everyone.id == self.guild.id:
+ base.handle_overwrite(allow=maybe_everyone.allow, deny=maybe_everyone.deny)
+ remaining_overwrites = self._overwrites[1:]
+ else:
+ remaining_overwrites = self._overwrites
+ except IndexError:
+ remaining_overwrites = self._overwrites
+
+ denies = 0
+ allows = 0
+
+ # Apply channel specific role permission overwrites
+ for overwrite in remaining_overwrites:
+ if overwrite.type == 'role' and roles.has(overwrite.id):
+ denies |= overwrite.deny
+ allows |= overwrite.allow
+
+ base.handle_overwrite(allow=allows, deny=denies)
+
+ # Apply member specific permission overwrites
+ for overwrite in remaining_overwrites:
+ if overwrite.type == 'member' and overwrite.id == member.id:
+ base.handle_overwrite(allow=overwrite.allow, deny=overwrite.deny)
+ break
+
+ # if you can't send a message in a channel then you can't have certain
+ # permissions as well
+ if not base.send_messages:
+ base.send_tts_messages = False
+ base.mention_everyone = False
+ base.embed_links = False
+ base.attach_files = False
+
+ # if you can't read a channel then you have no permissions there
+ if not base.read_messages:
+ denied = Permissions.all_channel()
+ base.value &= ~denied.value
+
+ return base
+
+ async def delete(self, *, reason=None):
+ """|coro|
+
+ Deletes the channel.
+
+ You must have :attr:`~Permissions.manage_channels` permission to use this.
+
+ Parameters
+ -----------
+ reason: Optional[:class:`str`]
+ The reason for deleting this channel.
+ Shows up on the audit log.
+
+ Raises
+ -------
+ ~discord.Forbidden
+ You do not have proper permissions to delete the channel.
+ ~discord.NotFound
+ The channel was not found or was already deleted.
+ ~discord.HTTPException
+ Deleting the channel failed.
+ """
+ await self._state.http.delete_channel(self.id, reason=reason)
+
+ async def set_permissions(self, target, *, overwrite=_undefined, reason=None, **permissions):
+ r"""|coro|
+
+ Sets the channel specific permission overwrites for a target in the
+ channel.
+
+ The ``target`` parameter should either be a :class:`~discord.Member` or a
+ :class:`~discord.Role` that belongs to guild.
+
+ The ``overwrite`` parameter, if given, must either be ``None`` or
+ :class:`~discord.PermissionOverwrite`. For convenience, you can pass in
+ keyword arguments denoting :class:`~discord.Permissions` attributes. If this is
+ done, then you cannot mix the keyword arguments with the ``overwrite``
+ parameter.
+
+ If the ``overwrite`` parameter is ``None``, then the permission
+ overwrites are deleted.
+
+ You must have the :attr:`~Permissions.manage_roles` permission to use this.
+
+ Examples
+ ----------
+
+ Setting allow and deny: ::
+
+ await message.channel.set_permissions(message.author, read_messages=True,
+ send_messages=False)
+
+ Deleting overwrites ::
+
+ await channel.set_permissions(member, overwrite=None)
+
+ Using :class:`~discord.PermissionOverwrite` ::
+
+ overwrite = discord.PermissionOverwrite()
+ overwrite.send_messages = False
+ overwrite.read_messages = True
+ await channel.set_permissions(member, overwrite=overwrite)
+
+ Parameters
+ -----------
+ target: Union[:class:`~discord.Member`, :class:`~discord.Role`]
+ The member or role to overwrite permissions for.
+ overwrite: Optional[:class:`~discord.PermissionOverwrite`]
+ The permissions to allow and deny to the target, or ``None`` to
+ delete the overwrite.
+ \*\*permissions
+ A keyword argument list of permissions to set for ease of use.
+ Cannot be mixed with ``overwrite``.
+ reason: Optional[:class:`str`]
+ The reason for doing this action. Shows up on the audit log.
+
+ Raises
+ -------
+ ~discord.Forbidden
+ You do not have permissions to edit channel specific permissions.
+ ~discord.HTTPException
+ Editing channel specific permissions failed.
+ ~discord.NotFound
+ The role or member being edited is not part of the guild.
+ ~discord.InvalidArgument
+ The overwrite parameter invalid or the target type was not
+ :class:`~discord.Role` or :class:`~discord.Member`.
+ """
+
+ http = self._state.http
+
+ if isinstance(target, User):
+ perm_type = 'member'
+ elif isinstance(target, Role):
+ perm_type = 'role'
+ else:
+ raise InvalidArgument('target parameter must be either Member or Role')
+
+ if isinstance(overwrite, _Undefined):
+ if len(permissions) == 0:
+ raise InvalidArgument('No overwrite provided.')
+ try:
+ overwrite = PermissionOverwrite(**permissions)
+ except (ValueError, TypeError):
+ raise InvalidArgument('Invalid permissions given to keyword arguments.')
+ else:
+ if len(permissions) > 0:
+ raise InvalidArgument('Cannot mix overwrite and keyword arguments.')
+
+ # TODO: wait for event
+
+ if overwrite is None:
+ await http.delete_channel_permissions(self.id, target.id, reason=reason)
+ elif isinstance(overwrite, PermissionOverwrite):
+ (allow, deny) = overwrite.pair()
+ await http.edit_channel_permissions(self.id, target.id, allow.value, deny.value, perm_type, reason=reason)
+ else:
+ raise InvalidArgument('Invalid overwrite type provided.')
+
+ async def _clone_impl(self, base_attrs, *, name=None, reason=None):
+ base_attrs['permission_overwrites'] = [
+ x._asdict() for x in self._overwrites
+ ]
+ base_attrs['parent_id'] = self.category_id
+ base_attrs['name'] = name or self.name
+ guild_id = self.guild.id
+ cls = self.__class__
+ data = await self._state.http.create_channel(guild_id, self.type.value, reason=reason, **base_attrs)
+ obj = cls(state=self._state, guild=self.guild, data=data)
+
+ # temporarily add it to the cache
+ self.guild._channels[obj.id] = obj
+ return obj
+
+ async def clone(self, *, name=None, reason=None):
+ """|coro|
+
+ Clones this channel. This creates a channel with the same properties
+ as this channel.
+
+ You must have the :attr:`~discord.Permissions.manage_channels` permission to
+ do this.
+
+ .. versionadded:: 1.1
+
+ Parameters
+ ------------
+ name: Optional[:class:`str`]
+ The name of the new channel. If not provided, defaults to this
+ channel name.
+ reason: Optional[:class:`str`]
+ The reason for cloning this channel. Shows up on the audit log.
+
+ Raises
+ -------
+ ~discord.Forbidden
+ You do not have the proper permissions to create this channel.
+ ~discord.HTTPException
+ Creating the channel failed.
+
+ Returns
+ --------
+ :class:`.abc.GuildChannel`
+ The channel that was created.
+ """
+ raise NotImplementedError
+
+ async def move(self, **kwargs):
+ """|coro|
+
+ A rich interface to help move a channel relative to other channels.
+
+ If exact position movement is required, :meth:`edit` should be used instead.
+
+ You must have the :attr:`~discord.Permissions.manage_channels` permission to
+ do this.
+
+ .. note::
+
+ Voice channels will always be sorted below text channels.
+ This is a Discord limitation.
+
+ .. versionadded:: 1.7
+
+ Parameters
+ ------------
+ beginning: :class:`bool`
+ Whether to move the channel to the beginning of the
+ channel list (or category if given).
+ This is mutually exclusive with ``end``, ``before``, and ``after``.
+ end: :class:`bool`
+ Whether to move the channel to the end of the
+ channel list (or category if given).
+ This is mutually exclusive with ``beginning``, ``before``, and ``after``.
+ before: :class:`~discord.abc.Snowflake`
+ The channel that should be before our current channel.
+ This is mutually exclusive with ``beginning``, ``end``, and ``after``.
+ after: :class:`~discord.abc.Snowflake`
+ The channel that should be after our current channel.
+ This is mutually exclusive with ``beginning``, ``end``, and ``before``.
+ offset: :class:`int`
+ The number of channels to offset the move by. For example,
+ an offset of ``2`` with ``beginning=True`` would move
+ it 2 after the beginning. A positive number moves it below
+ while a negative number moves it above. Note that this
+ number is relative and computed after the ``beginning``,
+ ``end``, ``before``, and ``after`` parameters.
+ category: Optional[:class:`~discord.abc.Snowflake`]
+ The category to move this channel under.
+ If ``None`` is given then it moves it out of the category.
+ This parameter is ignored if moving a category channel.
+ sync_permissions: :class:`bool`
+ Whether to sync the permissions with the category (if given).
+ reason: :class:`str`
+ The reason for the move.
+
+ Raises
+ -------
+ InvalidArgument
+ An invalid position was given or a bad mix of arguments were passed.
+ Forbidden
+ You do not have permissions to move the channel.
+ HTTPException
+ Moving the channel failed.
+ """
+
+ if not kwargs:
+ return
+
+ beginning, end = kwargs.get('beginning'), kwargs.get('end')
+ before, after = kwargs.get('before'), kwargs.get('after')
+ offset = kwargs.get('offset', 0)
+ if sum(bool(a) for a in (beginning, end, before, after)) > 1:
+ raise InvalidArgument('Only one of [before, after, end, beginning] can be used.')
+
+ bucket = self._sorting_bucket
+ parent_id = kwargs.get('category', ...)
+ if parent_id not in (..., None):
+ parent_id = parent_id.id
+ channels = [
+ ch
+ for ch in self.guild.channels
+ if ch._sorting_bucket == bucket
+ and ch.category_id == parent_id
+ ]
+ else:
+ channels = [
+ ch
+ for ch in self.guild.channels
+ if ch._sorting_bucket == bucket
+ and ch.category_id == self.category_id
+ ]
+
+ channels.sort(key=lambda c: (c.position, c.id))
+
+ try:
+ # Try to remove ourselves from the channel list
+ channels.remove(self)
+ except ValueError:
+ # If we're not there then it's probably due to not being in the category
+ pass
+
+ index = None
+ if beginning:
+ index = 0
+ elif end:
+ index = len(channels)
+ elif before:
+ index = next((i for i, c in enumerate(channels) if c.id == before.id), None)
+ elif after:
+ index = next((i + 1 for i, c in enumerate(channels) if c.id == after.id), None)
+
+ if index is None:
+ raise InvalidArgument('Could not resolve appropriate move position')
+
+ channels.insert(max((index + offset), 0), self)
+ payload = []
+ lock_permissions = kwargs.get('sync_permissions', False)
+ reason = kwargs.get('reason')
+ for index, channel in enumerate(channels):
+ d = { 'id': channel.id, 'position': index }
+ if parent_id is not ... and channel.id == self.id:
+ d.update(parent_id=parent_id, lock_permissions=lock_permissions)
+ payload.append(d)
+
+ await self._state.http.bulk_channel_update(self.guild.id, payload, reason=reason)
+
+
+ async def create_invite(self, *, reason=None, **fields):
+ """|coro|
+
+ Creates an instant invite from a text or voice channel.
+
+ You must have the :attr:`~Permissions.create_instant_invite` permission to
+ do this.
+
+ Parameters
+ ------------
+ max_age: :class:`int`
+ How long the invite should last in seconds. If it's 0 then the invite
+ doesn't expire. Defaults to ``0``.
+ max_uses: :class:`int`
+ How many uses the invite could be used for. If it's 0 then there
+ are unlimited uses. Defaults to ``0``.
+ temporary: :class:`bool`
+ Denotes that the invite grants temporary membership
+ (i.e. they get kicked after they disconnect). Defaults to ``False``.
+ unique: :class:`bool`
+ Indicates if a unique invite URL should be created. Defaults to True.
+ If this is set to ``False`` then it will return a previously created
+ invite.
+ reason: Optional[:class:`str`]
+ The reason for creating this invite. Shows up on the audit log.
+
+ Raises
+ -------
+ ~discord.HTTPException
+ Invite creation failed.
+
+ ~discord.NotFound
+ The channel that was passed is a category or an invalid channel.
+
+ Returns
+ --------
+ :class:`~discord.Invite`
+ The invite that was created.
+ """
+
+ data = await self._state.http.create_invite(self.id, reason=reason, **fields)
+ return Invite.from_incomplete(data=data, state=self._state)
+
+ async def invites(self):
+ """|coro|
+
+ Returns a list of all active instant invites from this channel.
+
+ You must have :attr:`~Permissions.manage_channels` to get this information.
+
+ Raises
+ -------
+ ~discord.Forbidden
+ You do not have proper permissions to get the information.
+ ~discord.HTTPException
+ An error occurred while fetching the information.
+
+ Returns
+ -------
+ List[:class:`~discord.Invite`]
+ The list of invites that are currently active.
+ """
+
+ state = self._state
+ data = await state.http.invites_from_channel(self.id)
+ result = []
+
+ for invite in data:
+ invite['channel'] = self
+ invite['guild'] = self.guild
+ result.append(Invite(state=state, data=invite))
+
+ return result
+
+class Messageable(metaclass=abc.ABCMeta):
+ """An ABC that details the common operations on a model that can send messages.
+
+ The following implement this ABC:
+
+ - :class:`~discord.TextChannel`
+ - :class:`~discord.DMChannel`
+ - :class:`~discord.GroupChannel`
+ - :class:`~discord.User`
+ - :class:`~discord.Member`
+ - :class:`~discord.ext.commands.Context`
+ """
+
+ __slots__ = ()
+
+ @abc.abstractmethod
+ async def _get_channel(self):
+ raise NotImplementedError
+
+ async def send(self, content=None, *, tts=False, embed=None, file=None,
+ files=None, delete_after=None, nonce=None,
+ allowed_mentions=None, reference=None,
+ mention_author=None):
+ """|coro|
+
+ Sends a message to the destination with the content given.
+
+ The content must be a type that can convert to a string through ``str(content)``.
+ If the content is set to ``None`` (the default), then the ``embed`` parameter must
+ be provided.
+
+ To upload a single file, the ``file`` parameter should be used with a
+ single :class:`~discord.File` object. To upload multiple files, the ``files``
+ parameter should be used with a :class:`list` of :class:`~discord.File` objects.
+ **Specifying both parameters will lead to an exception**.
+
+ If the ``embed`` parameter is provided, it must be of type :class:`~discord.Embed` and
+ it must be a rich embed type.
+
+ Parameters
+ ------------
+ content: :class:`str`
+ The content of the message to send.
+ tts: :class:`bool`
+ Indicates if the message should be sent using text-to-speech.
+ embed: :class:`~discord.Embed`
+ The rich embed for the content.
+ file: :class:`~discord.File`
+ The file to upload.
+ files: List[:class:`~discord.File`]
+ A list of files to upload. Must be a maximum of 10.
+ nonce: :class:`int`
+ The nonce to use for sending this message. If the message was successfully sent,
+ then the message will have a nonce with this value.
+ delete_after: :class:`float`
+ If provided, the number of seconds to wait in the background
+ before deleting the message we just sent. If the deletion fails,
+ then it is silently ignored.
+ allowed_mentions: :class:`~discord.AllowedMentions`
+ Controls the mentions being processed in this message. If this is
+ passed, then the object is merged with :attr:`~discord.Client.allowed_mentions`.
+ The merging behaviour only overrides attributes that have been explicitly passed
+ to the object, otherwise it uses the attributes set in :attr:`~discord.Client.allowed_mentions`.
+ If no object is passed at all then the defaults given by :attr:`~discord.Client.allowed_mentions`
+ are used instead.
+
+ .. versionadded:: 1.4
+
+ reference: Union[:class:`~discord.Message`, :class:`~discord.MessageReference`]
+ A reference to the :class:`~discord.Message` to which you are replying, this can be created using
+ :meth:`~discord.Message.to_reference` or passed directly as a :class:`~discord.Message`. You can control
+ whether this mentions the author of the referenced message using the :attr:`~discord.AllowedMentions.replied_user`
+ attribute of ``allowed_mentions`` or by setting ``mention_author``.
+
+ .. versionadded:: 1.6
+
+ mention_author: Optional[:class:`bool`]
+ If set, overrides the :attr:`~discord.AllowedMentions.replied_user` attribute of ``allowed_mentions``.
+
+ .. versionadded:: 1.6
+
+ Raises
+ --------
+ ~discord.HTTPException
+ Sending the message failed.
+ ~discord.Forbidden
+ You do not have the proper permissions to send the message.
+ ~discord.InvalidArgument
+ The ``files`` list is not of the appropriate size,
+ you specified both ``file`` and ``files``,
+ or the ``reference`` object is not a :class:`~discord.Message`
+ or :class:`~discord.MessageReference`.
+
+ Returns
+ ---------
+ :class:`~discord.Message`
+ The message that was sent.
+ """
+
+ channel = await self._get_channel()
+ state = self._state
+ content = str(content) if content is not None else None
+ if embed is not None:
+ embed = embed.to_dict()
+
+ if allowed_mentions is not None:
+ if state.allowed_mentions is not None:
+ allowed_mentions = state.allowed_mentions.merge(allowed_mentions).to_dict()
+ else:
+ allowed_mentions = allowed_mentions.to_dict()
+ else:
+ allowed_mentions = state.allowed_mentions and state.allowed_mentions.to_dict()
+
+ if mention_author is not None:
+ allowed_mentions = allowed_mentions or AllowedMentions().to_dict()
+ allowed_mentions['replied_user'] = bool(mention_author)
+
+ if reference is not None:
+ try:
+ reference = reference.to_message_reference_dict()
+ except AttributeError:
+ raise InvalidArgument('reference parameter must be Message or MessageReference') from None
+
+ if file is not None and files is not None:
+ raise InvalidArgument('cannot pass both file and files parameter to send()')
+
+ if file is not None:
+ if not isinstance(file, File):
+ raise InvalidArgument('file parameter must be File')
+
+ try:
+ data = await state.http.send_files(channel.id, files=[file], allowed_mentions=allowed_mentions,
+ content=content, tts=tts, embed=embed, nonce=nonce,
+ message_reference=reference)
+ finally:
+ file.close()
+
+ elif files is not None:
+ if len(files) > 10:
+ raise InvalidArgument('files parameter must be a list of up to 10 elements')
+ elif not all(isinstance(file, File) for file in files):
+ raise InvalidArgument('files parameter must be a list of File')
+
+ try:
+ data = await state.http.send_files(channel.id, files=files, content=content, tts=tts,
+ embed=embed, nonce=nonce, allowed_mentions=allowed_mentions,
+ message_reference=reference)
+ finally:
+ for f in files:
+ f.close()
+ else:
+ data = await state.http.send_message(channel.id, content, tts=tts, embed=embed,
+ nonce=nonce, allowed_mentions=allowed_mentions,
+ message_reference=reference)
+
+ ret = state.create_message(channel=channel, data=data)
+ if delete_after is not None:
+ await ret.delete(delay=delete_after)
+ return ret
+
+ async def trigger_typing(self):
+ """|coro|
+
+ Triggers a *typing* indicator to the destination.
+
+ *Typing* indicator will go away after 10 seconds, or after a message is sent.
+ """
+
+ channel = await self._get_channel()
+ await self._state.http.send_typing(channel.id)
+
+ def typing(self):
+ """Returns a context manager that allows you to type for an indefinite period of time.
+
+ This is useful for denoting long computations in your bot.
+
+ .. note::
+
+ This is both a regular context manager and an async context manager.
+ This means that both ``with`` and ``async with`` work with this.
+
+ Example Usage: ::
+
+ async with channel.typing():
+ # do expensive stuff here
+ await channel.send('done!')
+
+ """
+ return Typing(self)
+
+ async def fetch_message(self, id):
+ """|coro|
+
+ Retrieves a single :class:`~discord.Message` from the destination.
+
+ This can only be used by bot accounts.
+
+ Parameters
+ ------------
+ id: :class:`int`
+ The message ID to look for.
+
+ Raises
+ --------
+ ~discord.NotFound
+ The specified message was not found.
+ ~discord.Forbidden
+ You do not have the permissions required to get a message.
+ ~discord.HTTPException
+ Retrieving the message failed.
+
+ Returns
+ --------
+ :class:`~discord.Message`
+ The message asked for.
+ """
+
+ channel = await self._get_channel()
+ data = await self._state.http.get_message(channel.id, id)
+ return self._state.create_message(channel=channel, data=data)
+
+ async def pins(self):
+ """|coro|
+
+ Retrieves all messages that are currently pinned in the channel.
+
+ .. note::
+
+ Due to a limitation with the Discord API, the :class:`.Message`
+ objects returned by this method do not contain complete
+ :attr:`.Message.reactions` data.
+
+ Raises
+ -------
+ ~discord.HTTPException
+ Retrieving the pinned messages failed.
+
+ Returns
+ --------
+ List[:class:`~discord.Message`]
+ The messages that are currently pinned.
+ """
+
+ channel = await self._get_channel()
+ state = self._state
+ data = await state.http.pins_from(channel.id)
+ return [state.create_message(channel=channel, data=m) for m in data]
+
+ def history(self, *, limit=100, before=None, after=None, around=None, oldest_first=None):
+ """Returns an :class:`~discord.AsyncIterator` that enables receiving the destination's message history.
+
+ You must have :attr:`~Permissions.read_message_history` permissions to use this.
+
+ Examples
+ ---------
+
+ Usage ::
+
+ counter = 0
+ async for message in channel.history(limit=200):
+ if message.author == client.user:
+ counter += 1
+
+ Flattening into a list: ::
+
+ messages = await channel.history(limit=123).flatten()
+ # messages is now a list of Message...
+
+ All parameters are optional.
+
+ Parameters
+ -----------
+ limit: Optional[:class:`int`]
+ The number of messages to retrieve.
+ If ``None``, retrieves every message in the channel. Note, however,
+ that this would make it a slow operation.
+ before: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]]
+ Retrieve messages before this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ after: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]]
+ Retrieve messages after this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ around: Optional[Union[:class:`~discord.abc.Snowflake`, :class:`datetime.datetime`]]
+ Retrieve messages around this date or message.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ When using this argument, the maximum limit is 101. Note that if the limit is an
+ even number then this will return at most limit + 1 messages.
+ oldest_first: Optional[:class:`bool`]
+ If set to ``True``, return messages in oldest->newest order. Defaults to ``True`` if
+ ``after`` is specified, otherwise ``False``.
+
+ Raises
+ ------
+ ~discord.Forbidden
+ You do not have permissions to get channel message history.
+ ~discord.HTTPException
+ The request to get message history failed.
+
+ Yields
+ -------
+ :class:`~discord.Message`
+ The message with the message data parsed.
+ """
+ return HistoryIterator(self, limit=limit, before=before, after=after, around=around, oldest_first=oldest_first)
+
+class Connectable(metaclass=abc.ABCMeta):
+ """An ABC that details the common operations on a channel that can
+ connect to a voice server.
+
+ The following implement this ABC:
+
+ - :class:`~discord.VoiceChannel`
+ """
+ __slots__ = ()
+
+ @abc.abstractmethod
+ def _get_voice_client_key(self):
+ raise NotImplementedError
+
+ @abc.abstractmethod
+ def _get_voice_state_pair(self):
+ raise NotImplementedError
+
+ async def connect(self, *, timeout=60.0, reconnect=True, cls=VoiceClient):
+ """|coro|
+
+ Connects to voice and creates a :class:`VoiceClient` to establish
+ your connection to the voice server.
+
+ Parameters
+ -----------
+ timeout: :class:`float`
+ The timeout in seconds to wait for the voice endpoint.
+ reconnect: :class:`bool`
+ Whether the bot should automatically attempt
+ a reconnect if a part of the handshake fails
+ or the gateway goes down.
+ cls: Type[:class:`VoiceProtocol`]
+ A type that subclasses :class:`~discord.VoiceProtocol` to connect with.
+ Defaults to :class:`~discord.VoiceClient`.
+
+ Raises
+ -------
+ asyncio.TimeoutError
+ Could not connect to the voice channel in time.
+ ~discord.ClientException
+ You are already connected to a voice channel.
+ ~discord.opus.OpusNotLoaded
+ The opus library has not been loaded.
+
+ Returns
+ --------
+ :class:`~discord.VoiceProtocol`
+ A voice client that is fully connected to the voice server.
+ """
+
+ key_id, _ = self._get_voice_client_key()
+ state = self._state
+
+ if state._get_voice_client(key_id):
+ raise ClientException('Already connected to a voice channel.')
+
+ client = state._get_client()
+ voice = cls(client, self)
+
+ if not isinstance(voice, VoiceProtocol):
+ raise TypeError('Type must meet VoiceProtocol abstract base class.')
+
+ state._add_voice_client(key_id, voice)
+
+ try:
+ await voice.connect(timeout=timeout, reconnect=reconnect)
+ except asyncio.TimeoutError:
+ try:
+ await voice.disconnect(force=True)
+ except Exception:
+ # we don't care if disconnect failed because connection failed
+ pass
+ raise # re-raise
+
+ return voice
diff --git a/venv/lib64/python3.8/site-packages/discord/activity.py b/venv/lib64/python3.8/site-packages/discord/activity.py
new file mode 100644
index 0000000..cf5192a
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/activity.py
@@ -0,0 +1,773 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import datetime
+
+from .asset import Asset
+from .enums import ActivityType, try_enum
+from .colour import Colour
+from .partial_emoji import PartialEmoji
+from .utils import _get_as_snowflake
+
+__all__ = (
+ 'BaseActivity',
+ 'Activity',
+ 'Streaming',
+ 'Game',
+ 'Spotify',
+ 'CustomActivity',
+)
+
+"""If curious, this is the current schema for an activity.
+
+It's fairly long so I will document it here:
+
+All keys are optional.
+
+state: str (max: 128),
+details: str (max: 128)
+timestamps: dict
+ start: int (min: 1)
+ end: int (min: 1)
+assets: dict
+ large_image: str (max: 32)
+ large_text: str (max: 128)
+ small_image: str (max: 32)
+ small_text: str (max: 128)
+party: dict
+ id: str (max: 128),
+ size: List[int] (max-length: 2)
+ elem: int (min: 1)
+secrets: dict
+ match: str (max: 128)
+ join: str (max: 128)
+ spectate: str (max: 128)
+instance: bool
+application_id: str
+name: str (max: 128)
+url: str
+type: int
+sync_id: str
+session_id: str
+flags: int
+
+There are also activity flags which are mostly uninteresting for the library atm.
+
+t.ActivityFlags = {
+ INSTANCE: 1,
+ JOIN: 2,
+ SPECTATE: 4,
+ JOIN_REQUEST: 8,
+ SYNC: 16,
+ PLAY: 32
+}
+"""
+
+class BaseActivity:
+ """The base activity that all user-settable activities inherit from.
+ A user-settable activity is one that can be used in :meth:`Client.change_presence`.
+
+ The following types currently count as user-settable:
+
+ - :class:`Activity`
+ - :class:`Game`
+ - :class:`Streaming`
+ - :class:`CustomActivity`
+
+ Note that although these types are considered user-settable by the library,
+ Discord typically ignores certain combinations of activity depending on
+ what is currently set. This behaviour may change in the future so there are
+ no guarantees on whether Discord will actually let you set these types.
+
+ .. versionadded:: 1.3
+ """
+ __slots__ = ('_created_at',)
+
+ def __init__(self, **kwargs):
+ self._created_at = kwargs.pop('created_at', None)
+
+ @property
+ def created_at(self):
+ """Optional[:class:`datetime.datetime`]: When the user started doing this activity in UTC.
+
+ .. versionadded:: 1.3
+ """
+ if self._created_at is not None:
+ return datetime.datetime.utcfromtimestamp(self._created_at / 1000)
+
+class Activity(BaseActivity):
+ """Represents an activity in Discord.
+
+ This could be an activity such as streaming, playing, listening
+ or watching.
+
+ For memory optimisation purposes, some activities are offered in slimmed
+ down versions:
+
+ - :class:`Game`
+ - :class:`Streaming`
+
+ Attributes
+ ------------
+ application_id: :class:`int`
+ The application ID of the game.
+ name: :class:`str`
+ The name of the activity.
+ url: :class:`str`
+ A stream URL that the activity could be doing.
+ type: :class:`ActivityType`
+ The type of activity currently being done.
+ state: :class:`str`
+ The user's current state. For example, "In Game".
+ details: :class:`str`
+ The detail of the user's current activity.
+ timestamps: :class:`dict`
+ A dictionary of timestamps. It contains the following optional keys:
+
+ - ``start``: Corresponds to when the user started doing the
+ activity in milliseconds since Unix epoch.
+ - ``end``: Corresponds to when the user will finish doing the
+ activity in milliseconds since Unix epoch.
+
+ assets: :class:`dict`
+ A dictionary representing the images and their hover text of an activity.
+ It contains the following optional keys:
+
+ - ``large_image``: A string representing the ID for the large image asset.
+ - ``large_text``: A string representing the text when hovering over the large image asset.
+ - ``small_image``: A string representing the ID for the small image asset.
+ - ``small_text``: A string representing the text when hovering over the small image asset.
+
+ party: :class:`dict`
+ A dictionary representing the activity party. It contains the following optional keys:
+
+ - ``id``: A string representing the party ID.
+ - ``size``: A list of up to two integer elements denoting (current_size, maximum_size).
+ emoji: Optional[:class:`PartialEmoji`]
+ The emoji that belongs to this activity.
+ """
+
+ __slots__ = ('state', 'details', '_created_at', 'timestamps', 'assets', 'party',
+ 'flags', 'sync_id', 'session_id', 'type', 'name', 'url',
+ 'application_id', 'emoji')
+
+ def __init__(self, **kwargs):
+ super().__init__(**kwargs)
+ self.state = kwargs.pop('state', None)
+ self.details = kwargs.pop('details', None)
+ self.timestamps = kwargs.pop('timestamps', {})
+ self.assets = kwargs.pop('assets', {})
+ self.party = kwargs.pop('party', {})
+ self.application_id = _get_as_snowflake(kwargs, 'application_id')
+ self.name = kwargs.pop('name', None)
+ self.url = kwargs.pop('url', None)
+ self.flags = kwargs.pop('flags', 0)
+ self.sync_id = kwargs.pop('sync_id', None)
+ self.session_id = kwargs.pop('session_id', None)
+ self.type = try_enum(ActivityType, kwargs.pop('type', -1))
+ emoji = kwargs.pop('emoji', None)
+ if emoji is not None:
+ self.emoji = PartialEmoji.from_dict(emoji)
+ else:
+ self.emoji = None
+
+ def __repr__(self):
+ attrs = (
+ 'type',
+ 'name',
+ 'url',
+ 'details',
+ 'application_id',
+ 'session_id',
+ 'emoji',
+ )
+ mapped = ' '.join('%s=%r' % (attr, getattr(self, attr)) for attr in attrs)
+ return '' % mapped
+
+ def to_dict(self):
+ ret = {}
+ for attr in self.__slots__:
+ value = getattr(self, attr, None)
+ if value is None:
+ continue
+
+ if isinstance(value, dict) and len(value) == 0:
+ continue
+
+ ret[attr] = value
+ ret['type'] = int(self.type)
+ if self.emoji:
+ ret['emoji'] = self.emoji.to_dict()
+ return ret
+
+ @property
+ def start(self):
+ """Optional[:class:`datetime.datetime`]: When the user started doing this activity in UTC, if applicable."""
+ try:
+ return datetime.datetime.utcfromtimestamp(self.timestamps['start'] / 1000)
+ except KeyError:
+ return None
+
+ @property
+ def end(self):
+ """Optional[:class:`datetime.datetime`]: When the user will stop doing this activity in UTC, if applicable."""
+ try:
+ return datetime.datetime.utcfromtimestamp(self.timestamps['end'] / 1000)
+ except KeyError:
+ return None
+
+ @property
+ def large_image_url(self):
+ """Optional[:class:`str`]: Returns a URL pointing to the large image asset of this activity if applicable."""
+ if self.application_id is None:
+ return None
+
+ try:
+ large_image = self.assets['large_image']
+ except KeyError:
+ return None
+ else:
+ return Asset.BASE + '/app-assets/{0}/{1}.png'.format(self.application_id, large_image)
+
+ @property
+ def small_image_url(self):
+ """Optional[:class:`str`]: Returns a URL pointing to the small image asset of this activity if applicable."""
+ if self.application_id is None:
+ return None
+
+ try:
+ small_image = self.assets['small_image']
+ except KeyError:
+ return None
+ else:
+ return Asset.BASE + '/app-assets/{0}/{1}.png'.format(self.application_id, small_image)
+ @property
+ def large_image_text(self):
+ """Optional[:class:`str`]: Returns the large image asset hover text of this activity if applicable."""
+ return self.assets.get('large_text', None)
+
+ @property
+ def small_image_text(self):
+ """Optional[:class:`str`]: Returns the small image asset hover text of this activity if applicable."""
+ return self.assets.get('small_text', None)
+
+
+class Game(BaseActivity):
+ """A slimmed down version of :class:`Activity` that represents a Discord game.
+
+ This is typically displayed via **Playing** on the official Discord client.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two games are equal.
+
+ .. describe:: x != y
+
+ Checks if two games are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the game's hash.
+
+ .. describe:: str(x)
+
+ Returns the game's name.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The game's name.
+ start: Optional[:class:`datetime.datetime`]
+ A naive UTC timestamp representing when the game started. Keyword-only parameter. Ignored for bots.
+ end: Optional[:class:`datetime.datetime`]
+ A naive UTC timestamp representing when the game ends. Keyword-only parameter. Ignored for bots.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The game's name.
+ """
+
+ __slots__ = ('name', '_end', '_start')
+
+ def __init__(self, name, **extra):
+ super().__init__(**extra)
+ self.name = name
+
+ try:
+ timestamps = extra['timestamps']
+ except KeyError:
+ self._extract_timestamp(extra, 'start')
+ self._extract_timestamp(extra, 'end')
+ else:
+ self._start = timestamps.get('start', 0)
+ self._end = timestamps.get('end', 0)
+
+ def _extract_timestamp(self, data, key):
+ try:
+ dt = data[key]
+ except KeyError:
+ setattr(self, '_' + key, 0)
+ else:
+ setattr(self, '_' + key, dt.timestamp() * 1000.0)
+
+ @property
+ def type(self):
+ """:class:`ActivityType`: Returns the game's type. This is for compatibility with :class:`Activity`.
+
+ It always returns :attr:`ActivityType.playing`.
+ """
+ return ActivityType.playing
+
+ @property
+ def start(self):
+ """Optional[:class:`datetime.datetime`]: When the user started playing this game in UTC, if applicable."""
+ if self._start:
+ return datetime.datetime.utcfromtimestamp(self._start / 1000)
+ return None
+
+ @property
+ def end(self):
+ """Optional[:class:`datetime.datetime`]: When the user will stop playing this game in UTC, if applicable."""
+ if self._end:
+ return datetime.datetime.utcfromtimestamp(self._end / 1000)
+ return None
+
+ def __str__(self):
+ return str(self.name)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def to_dict(self):
+ timestamps = {}
+ if self._start:
+ timestamps['start'] = self._start
+
+ if self._end:
+ timestamps['end'] = self._end
+
+ return {
+ 'type': ActivityType.playing.value,
+ 'name': str(self.name),
+ 'timestamps': timestamps
+ }
+
+ def __eq__(self, other):
+ return isinstance(other, Game) and other.name == self.name
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self.name)
+
+class Streaming(BaseActivity):
+ """A slimmed down version of :class:`Activity` that represents a Discord streaming status.
+
+ This is typically displayed via **Streaming** on the official Discord client.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two streams are equal.
+
+ .. describe:: x != y
+
+ Checks if two streams are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the stream's hash.
+
+ .. describe:: str(x)
+
+ Returns the stream's name.
+
+ Attributes
+ -----------
+ platform: :class:`str`
+ Where the user is streaming from (ie. YouTube, Twitch).
+
+ .. versionadded:: 1.3
+
+ name: Optional[:class:`str`]
+ The stream's name.
+ details: Optional[:class:`str`]
+ An alias for :attr:`name`
+ game: Optional[:class:`str`]
+ The game being streamed.
+
+ .. versionadded:: 1.3
+
+ url: :class:`str`
+ The stream's URL.
+ assets: :class:`dict`
+ A dictionary comprising of similar keys than those in :attr:`Activity.assets`.
+ """
+
+ __slots__ = ('platform', 'name', 'game', 'url', 'details', 'assets')
+
+ def __init__(self, *, name, url, **extra):
+ super().__init__(**extra)
+ self.platform = name
+ self.name = extra.pop('details', name)
+ self.game = extra.pop('state', None)
+ self.url = url
+ self.details = extra.pop('details', self.name) # compatibility
+ self.assets = extra.pop('assets', {})
+
+ @property
+ def type(self):
+ """:class:`ActivityType`: Returns the game's type. This is for compatibility with :class:`Activity`.
+
+ It always returns :attr:`ActivityType.streaming`.
+ """
+ return ActivityType.streaming
+
+ def __str__(self):
+ return str(self.name)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ @property
+ def twitch_name(self):
+ """Optional[:class:`str`]: If provided, the twitch name of the user streaming.
+
+ This corresponds to the ``large_image`` key of the :attr:`Streaming.assets`
+ dictionary if it starts with ``twitch:``. Typically set by the Discord client.
+ """
+
+ try:
+ name = self.assets['large_image']
+ except KeyError:
+ return None
+ else:
+ return name[7:] if name[:7] == 'twitch:' else None
+
+ def to_dict(self):
+ ret = {
+ 'type': ActivityType.streaming.value,
+ 'name': str(self.name),
+ 'url': str(self.url),
+ 'assets': self.assets
+ }
+ if self.details:
+ ret['details'] = self.details
+ return ret
+
+ def __eq__(self, other):
+ return isinstance(other, Streaming) and other.name == self.name and other.url == self.url
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self.name)
+
+class Spotify:
+ """Represents a Spotify listening activity from Discord. This is a special case of
+ :class:`Activity` that makes it easier to work with the Spotify integration.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two activities are equal.
+
+ .. describe:: x != y
+
+ Checks if two activities are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the activity's hash.
+
+ .. describe:: str(x)
+
+ Returns the string 'Spotify'.
+ """
+
+ __slots__ = ('_state', '_details', '_timestamps', '_assets', '_party', '_sync_id', '_session_id',
+ '_created_at')
+
+ def __init__(self, **data):
+ self._state = data.pop('state', None)
+ self._details = data.pop('details', None)
+ self._timestamps = data.pop('timestamps', {})
+ self._assets = data.pop('assets', {})
+ self._party = data.pop('party', {})
+ self._sync_id = data.pop('sync_id')
+ self._session_id = data.pop('session_id')
+ self._created_at = data.pop('created_at', None)
+
+ @property
+ def type(self):
+ """:class:`ActivityType`: Returns the activity's type. This is for compatibility with :class:`Activity`.
+
+ It always returns :attr:`ActivityType.listening`.
+ """
+ return ActivityType.listening
+
+ @property
+ def created_at(self):
+ """Optional[:class:`datetime.datetime`]: When the user started listening in UTC.
+
+ .. versionadded:: 1.3
+ """
+ if self._created_at is not None:
+ return datetime.datetime.utcfromtimestamp(self._created_at / 1000)
+
+ @property
+ def colour(self):
+ """:class:`Colour`: Returns the Spotify integration colour, as a :class:`Colour`.
+
+ There is an alias for this named :attr:`color`"""
+ return Colour(0x1db954)
+
+ @property
+ def color(self):
+ """:class:`Colour`: Returns the Spotify integration colour, as a :class:`Colour`.
+
+ There is an alias for this named :attr:`colour`"""
+ return self.colour
+
+ def to_dict(self):
+ return {
+ 'flags': 48, # SYNC | PLAY
+ 'name': 'Spotify',
+ 'assets': self._assets,
+ 'party': self._party,
+ 'sync_id': self._sync_id,
+ 'session_id': self._session_id,
+ 'timestamps': self._timestamps,
+ 'details': self._details,
+ 'state': self._state
+ }
+
+ @property
+ def name(self):
+ """:class:`str`: The activity's name. This will always return "Spotify"."""
+ return 'Spotify'
+
+ def __eq__(self, other):
+ return (isinstance(other, Spotify) and other._session_id == self._session_id
+ and other._sync_id == self._sync_id and other.start == self.start)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self._session_id)
+
+ def __str__(self):
+ return 'Spotify'
+
+ def __repr__(self):
+ return ''.format(self)
+
+ @property
+ def title(self):
+ """:class:`str`: The title of the song being played."""
+ return self._details
+
+ @property
+ def artists(self):
+ """List[:class:`str`]: The artists of the song being played."""
+ return self._state.split('; ')
+
+ @property
+ def artist(self):
+ """:class:`str`: The artist of the song being played.
+
+ This does not attempt to split the artist information into
+ multiple artists. Useful if there's only a single artist.
+ """
+ return self._state
+
+ @property
+ def album(self):
+ """:class:`str`: The album that the song being played belongs to."""
+ return self._assets.get('large_text', '')
+
+ @property
+ def album_cover_url(self):
+ """:class:`str`: The album cover image URL from Spotify's CDN."""
+ large_image = self._assets.get('large_image', '')
+ if large_image[:8] != 'spotify:':
+ return ''
+ album_image_id = large_image[8:]
+ return 'https://i.scdn.co/image/' + album_image_id
+
+ @property
+ def track_id(self):
+ """:class:`str`: The track ID used by Spotify to identify this song."""
+ return self._sync_id
+
+ @property
+ def start(self):
+ """:class:`datetime.datetime`: When the user started playing this song in UTC."""
+ return datetime.datetime.utcfromtimestamp(self._timestamps['start'] / 1000)
+
+ @property
+ def end(self):
+ """:class:`datetime.datetime`: When the user will stop playing this song in UTC."""
+ return datetime.datetime.utcfromtimestamp(self._timestamps['end'] / 1000)
+
+ @property
+ def duration(self):
+ """:class:`datetime.timedelta`: The duration of the song being played."""
+ return self.end - self.start
+
+ @property
+ def party_id(self):
+ """:class:`str`: The party ID of the listening party."""
+ return self._party.get('id', '')
+
+class CustomActivity(BaseActivity):
+ """Represents a Custom activity from Discord.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two activities are equal.
+
+ .. describe:: x != y
+
+ Checks if two activities are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the activity's hash.
+
+ .. describe:: str(x)
+
+ Returns the custom status text.
+
+ .. versionadded:: 1.3
+
+ Attributes
+ -----------
+ name: Optional[:class:`str`]
+ The custom activity's name.
+ emoji: Optional[:class:`PartialEmoji`]
+ The emoji to pass to the activity, if any.
+ """
+
+ __slots__ = ('name', 'emoji', 'state')
+
+ def __init__(self, name, *, emoji=None, **extra):
+ super().__init__(**extra)
+ self.name = name
+ self.state = extra.pop('state', None)
+ if self.name == 'Custom Status':
+ self.name = self.state
+
+ if emoji is None:
+ self.emoji = emoji
+ elif isinstance(emoji, dict):
+ self.emoji = PartialEmoji.from_dict(emoji)
+ elif isinstance(emoji, str):
+ self.emoji = PartialEmoji(name=emoji)
+ elif isinstance(emoji, PartialEmoji):
+ self.emoji = emoji
+ else:
+ raise TypeError('Expected str, PartialEmoji, or None, received {0!r} instead.'.format(type(emoji)))
+
+ @property
+ def type(self):
+ """:class:`ActivityType`: Returns the activity's type. This is for compatibility with :class:`Activity`.
+
+ It always returns :attr:`ActivityType.custom`.
+ """
+ return ActivityType.custom
+
+ def to_dict(self):
+ if self.name == self.state:
+ o = {
+ 'type': ActivityType.custom.value,
+ 'state': self.name,
+ 'name': 'Custom Status',
+ }
+ else:
+ o = {
+ 'type': ActivityType.custom.value,
+ 'name': self.name,
+ }
+
+ if self.emoji:
+ o['emoji'] = self.emoji.to_dict()
+ return o
+
+ def __eq__(self, other):
+ return (isinstance(other, CustomActivity) and other.name == self.name and other.emoji == self.emoji)
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash((self.name, str(self.emoji)))
+
+ def __str__(self):
+ if self.emoji:
+ if self.name:
+ return '%s %s' % (self.emoji, self.name)
+ return str(self.emoji)
+ else:
+ return str(self.name)
+
+ def __repr__(self):
+ return ''.format(self)
+
+
+def create_activity(data):
+ if not data:
+ return None
+
+ game_type = try_enum(ActivityType, data.get('type', -1))
+ if game_type is ActivityType.playing:
+ if 'application_id' in data or 'session_id' in data:
+ return Activity(**data)
+ return Game(**data)
+ elif game_type is ActivityType.custom:
+ try:
+ name = data.pop('name')
+ except KeyError:
+ return Activity(**data)
+ else:
+ return CustomActivity(name=name, **data)
+ elif game_type is ActivityType.streaming:
+ if 'url' in data:
+ return Streaming(**data)
+ return Activity(**data)
+ elif game_type is ActivityType.listening and 'sync_id' in data and 'session_id' in data:
+ return Spotify(**data)
+ return Activity(**data)
diff --git a/venv/lib64/python3.8/site-packages/discord/appinfo.py b/venv/lib64/python3.8/site-packages/discord/appinfo.py
new file mode 100644
index 0000000..cbc0056
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/appinfo.py
@@ -0,0 +1,217 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+from . import utils
+from .user import User
+from .asset import Asset
+from .team import Team
+
+
+class AppInfo:
+ """Represents the application info for the bot provided by Discord.
+
+
+ Attributes
+ -------------
+ id: :class:`int`
+ The application ID.
+ name: :class:`str`
+ The application name.
+ owner: :class:`User`
+ The application owner.
+ team: Optional[:class:`Team`]
+ The application's team.
+
+ .. versionadded:: 1.3
+
+ icon: Optional[:class:`str`]
+ The icon hash, if it exists.
+ description: Optional[:class:`str`]
+ The application description.
+ bot_public: :class:`bool`
+ Whether the bot can be invited by anyone or if it is locked
+ to the application owner.
+ bot_require_code_grant: :class:`bool`
+ Whether the bot requires the completion of the full oauth2 code
+ grant flow to join.
+ rpc_origins: Optional[List[:class:`str`]]
+ A list of RPC origin URLs, if RPC is enabled.
+ summary: :class:`str`
+ If this application is a game sold on Discord,
+ this field will be the summary field for the store page of its primary SKU.
+
+ .. versionadded:: 1.3
+
+ verify_key: :class:`str`
+ The hex encoded key for verification in interactions and the
+ GameSDK's `GetTicket `_.
+
+ .. versionadded:: 1.3
+
+ guild_id: Optional[:class:`int`]
+ If this application is a game sold on Discord,
+ this field will be the guild to which it has been linked to.
+
+ .. versionadded:: 1.3
+
+ primary_sku_id: Optional[:class:`int`]
+ If this application is a game sold on Discord,
+ this field will be the id of the "Game SKU" that is created,
+ if it exists.
+
+ .. versionadded:: 1.3
+
+ slug: Optional[:class:`str`]
+ If this application is a game sold on Discord,
+ this field will be the URL slug that links to the store page.
+
+ .. versionadded:: 1.3
+
+ cover_image: Optional[:class:`str`]
+ If this application is a game sold on Discord,
+ this field will be the hash of the image on store embeds
+
+ .. versionadded:: 1.3
+ """
+ __slots__ = ('_state', 'description', 'id', 'name', 'rpc_origins',
+ 'bot_public', 'bot_require_code_grant', 'owner', 'icon',
+ 'summary', 'verify_key', 'team', 'guild_id', 'primary_sku_id',
+ 'slug', 'cover_image')
+
+ def __init__(self, state, data):
+ self._state = state
+
+ self.id = int(data['id'])
+ self.name = data['name']
+ self.description = data['description']
+ self.icon = data['icon']
+ self.rpc_origins = data['rpc_origins']
+ self.bot_public = data['bot_public']
+ self.bot_require_code_grant = data['bot_require_code_grant']
+ self.owner = User(state=self._state, data=data['owner'])
+
+ team = data.get('team')
+ self.team = Team(state, team) if team else None
+
+ self.summary = data['summary']
+ self.verify_key = data['verify_key']
+
+ self.guild_id = utils._get_as_snowflake(data, 'guild_id')
+
+ self.primary_sku_id = utils._get_as_snowflake(data, 'primary_sku_id')
+ self.slug = data.get('slug')
+ self.cover_image = data.get('cover_image')
+
+ def __repr__(self):
+ return '<{0.__class__.__name__} id={0.id} name={0.name!r} description={0.description!r} public={0.bot_public} ' \
+ 'owner={0.owner!r}>'.format(self)
+
+ @property
+ def icon_url(self):
+ """:class:`.Asset`: Retrieves the application's icon asset.
+
+ This is equivalent to calling :meth:`icon_url_as` with
+ the default parameters ('webp' format and a size of 1024).
+
+ .. versionadded:: 1.3
+ """
+ return self.icon_url_as()
+
+ def icon_url_as(self, *, format='webp', size=1024):
+ """Returns an :class:`Asset` for the icon the application has.
+
+ The format must be one of 'webp', 'jpeg', 'jpg' or 'png'.
+ The size must be a power of 2 between 16 and 4096.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ -----------
+ format: :class:`str`
+ The format to attempt to convert the icon to. Defaults to 'webp'.
+ size: :class:`int`
+ The size of the image to display.
+
+ Raises
+ ------
+ InvalidArgument
+ Bad image format passed to ``format`` or invalid ``size``.
+
+ Returns
+ --------
+ :class:`Asset`
+ The resulting CDN asset.
+ """
+ return Asset._from_icon(self._state, self, 'app', format=format, size=size)
+
+
+ @property
+ def cover_image_url(self):
+ """:class:`.Asset`: Retrieves the cover image on a store embed.
+
+ This is equivalent to calling :meth:`cover_image_url_as` with
+ the default parameters ('webp' format and a size of 1024).
+
+ .. versionadded:: 1.3
+ """
+ return self.cover_image_url_as()
+
+ def cover_image_url_as(self, *, format='webp', size=1024):
+ """Returns an :class:`Asset` for the image on store embeds
+ if this application is a game sold on Discord.
+
+ The format must be one of 'webp', 'jpeg', 'jpg' or 'png'.
+ The size must be a power of 2 between 16 and 4096.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ -----------
+ format: :class:`str`
+ The format to attempt to convert the image to. Defaults to 'webp'.
+ size: :class:`int`
+ The size of the image to display.
+
+ Raises
+ ------
+ InvalidArgument
+ Bad image format passed to ``format`` or invalid ``size``.
+
+ Returns
+ --------
+ :class:`Asset`
+ The resulting CDN asset.
+ """
+ return Asset._from_cover_image(self._state, self, format=format, size=size)
+
+ @property
+ def guild(self):
+ """Optional[:class:`Guild`]: If this application is a game sold on Discord,
+ this field will be the guild to which it has been linked
+
+ .. versionadded:: 1.3
+ """
+ return self._state._get_guild(int(self.guild_id))
diff --git a/venv/lib64/python3.8/site-packages/discord/asset.py b/venv/lib64/python3.8/site-packages/discord/asset.py
new file mode 100644
index 0000000..ea45729
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/asset.py
@@ -0,0 +1,262 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import io
+from .errors import DiscordException
+from .errors import InvalidArgument
+from . import utils
+
+VALID_STATIC_FORMATS = frozenset({"jpeg", "jpg", "webp", "png"})
+VALID_AVATAR_FORMATS = VALID_STATIC_FORMATS | {"gif"}
+
+class Asset:
+ """Represents a CDN asset on Discord.
+
+ .. container:: operations
+
+ .. describe:: str(x)
+
+ Returns the URL of the CDN asset.
+
+ .. describe:: len(x)
+
+ Returns the length of the CDN asset's URL.
+
+ .. describe:: bool(x)
+
+ Checks if the Asset has a URL.
+
+ .. describe:: x == y
+
+ Checks if the asset is equal to another asset.
+
+ .. describe:: x != y
+
+ Checks if the asset is not equal to another asset.
+
+ .. describe:: hash(x)
+
+ Returns the hash of the asset.
+ """
+ __slots__ = ('_state', '_url')
+
+ BASE = 'https://cdn.discordapp.com'
+
+ def __init__(self, state, url=None):
+ self._state = state
+ self._url = url
+
+ @classmethod
+ def _from_avatar(cls, state, user, *, format=None, static_format='webp', size=1024):
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+ if format is not None and format not in VALID_AVATAR_FORMATS:
+ raise InvalidArgument("format must be None or one of {}".format(VALID_AVATAR_FORMATS))
+ if format == "gif" and not user.is_avatar_animated():
+ raise InvalidArgument("non animated avatars do not support gif format")
+ if static_format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("static_format must be one of {}".format(VALID_STATIC_FORMATS))
+
+ if user.avatar is None:
+ return user.default_avatar_url
+
+ if format is None:
+ format = 'gif' if user.is_avatar_animated() else static_format
+
+ return cls(state, '/avatars/{0.id}/{0.avatar}.{1}?size={2}'.format(user, format, size))
+
+ @classmethod
+ def _from_icon(cls, state, object, path, *, format='webp', size=1024):
+ if object.icon is None:
+ return cls(state)
+
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+ if format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("format must be None or one of {}".format(VALID_STATIC_FORMATS))
+
+ url = '/{0}-icons/{1.id}/{1.icon}.{2}?size={3}'.format(path, object, format, size)
+ return cls(state, url)
+
+ @classmethod
+ def _from_cover_image(cls, state, obj, *, format='webp', size=1024):
+ if obj.cover_image is None:
+ return cls(state)
+
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+ if format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("format must be None or one of {}".format(VALID_STATIC_FORMATS))
+
+ url = '/app-assets/{0.id}/store/{0.cover_image}.{1}?size={2}'.format(obj, format, size)
+ return cls(state, url)
+
+ @classmethod
+ def _from_guild_image(cls, state, id, hash, key, *, format='webp', size=1024):
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+ if format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("format must be one of {}".format(VALID_STATIC_FORMATS))
+
+ if hash is None:
+ return cls(state)
+
+ url = '/{key}/{0}/{1}.{2}?size={3}'
+ return cls(state, url.format(id, hash, format, size, key=key))
+
+ @classmethod
+ def _from_guild_icon(cls, state, guild, *, format=None, static_format='webp', size=1024):
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+ if format is not None and format not in VALID_AVATAR_FORMATS:
+ raise InvalidArgument("format must be one of {}".format(VALID_AVATAR_FORMATS))
+ if format == "gif" and not guild.is_icon_animated():
+ raise InvalidArgument("non animated guild icons do not support gif format")
+ if static_format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("static_format must be one of {}".format(VALID_STATIC_FORMATS))
+
+ if guild.icon is None:
+ return cls(state)
+
+ if format is None:
+ format = 'gif' if guild.is_icon_animated() else static_format
+
+ return cls(state, '/icons/{0.id}/{0.icon}.{1}?size={2}'.format(guild, format, size))
+
+ @classmethod
+ def _from_sticker_url(cls, state, sticker, *, size=1024):
+ if not utils.valid_icon_size(size):
+ raise InvalidArgument("size must be a power of 2 between 16 and 4096")
+
+ return cls(state, '/stickers/{0.id}/{0.image}.png?size={2}'.format(sticker, format, size))
+
+ @classmethod
+ def _from_emoji(cls, state, emoji, *, format=None, static_format='png'):
+ if format is not None and format not in VALID_AVATAR_FORMATS:
+ raise InvalidArgument("format must be None or one of {}".format(VALID_AVATAR_FORMATS))
+ if format == "gif" and not emoji.animated:
+ raise InvalidArgument("non animated emoji's do not support gif format")
+ if static_format not in VALID_STATIC_FORMATS:
+ raise InvalidArgument("static_format must be one of {}".format(VALID_STATIC_FORMATS))
+ if format is None:
+ format = 'gif' if emoji.animated else static_format
+
+ return cls(state, '/emojis/{0.id}.{1}'.format(emoji, format))
+
+ def __str__(self):
+ return self.BASE + self._url if self._url is not None else ''
+
+ def __len__(self):
+ if self._url:
+ return len(self.BASE + self._url)
+ return 0
+
+ def __bool__(self):
+ return self._url is not None
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def __eq__(self, other):
+ return isinstance(other, Asset) and self._url == other._url
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return hash(self._url)
+
+ async def read(self):
+ """|coro|
+
+ Retrieves the content of this asset as a :class:`bytes` object.
+
+ .. warning::
+
+ :class:`PartialEmoji` won't have a connection state if user created,
+ and a URL won't be present if a custom image isn't associated with
+ the asset, e.g. a guild with no custom icon.
+
+ .. versionadded:: 1.1
+
+ Raises
+ ------
+ DiscordException
+ There was no valid URL or internal connection state.
+ HTTPException
+ Downloading the asset failed.
+ NotFound
+ The asset was deleted.
+
+ Returns
+ -------
+ :class:`bytes`
+ The content of the asset.
+ """
+ if not self._url:
+ raise DiscordException('Invalid asset (no URL provided)')
+
+ if self._state is None:
+ raise DiscordException('Invalid state (no ConnectionState provided)')
+
+ return await self._state.http.get_from_cdn(self.BASE + self._url)
+
+ async def save(self, fp, *, seek_begin=True):
+ """|coro|
+
+ Saves this asset into a file-like object.
+
+ Parameters
+ ----------
+ fp: Union[BinaryIO, :class:`os.PathLike`]
+ Same as in :meth:`Attachment.save`.
+ seek_begin: :class:`bool`
+ Same as in :meth:`Attachment.save`.
+
+ Raises
+ ------
+ DiscordException
+ There was no valid URL or internal connection state.
+ HTTPException
+ Downloading the asset failed.
+ NotFound
+ The asset was deleted.
+
+ Returns
+ --------
+ :class:`int`
+ The number of bytes written.
+ """
+
+ data = await self.read()
+ if isinstance(fp, io.IOBase) and fp.writable():
+ written = fp.write(data)
+ if seek_begin:
+ fp.seek(0)
+ return written
+ else:
+ with open(fp, 'wb') as f:
+ return f.write(data)
diff --git a/venv/lib64/python3.8/site-packages/discord/audit_logs.py b/venv/lib64/python3.8/site-packages/discord/audit_logs.py
new file mode 100644
index 0000000..7d70a93
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/audit_logs.py
@@ -0,0 +1,382 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+from . import utils, enums
+from .object import Object
+from .permissions import PermissionOverwrite, Permissions
+from .colour import Colour
+from .invite import Invite
+from .mixins import Hashable
+
+def _transform_verification_level(entry, data):
+ return enums.try_enum(enums.VerificationLevel, data)
+
+def _transform_default_notifications(entry, data):
+ return enums.try_enum(enums.NotificationLevel, data)
+
+def _transform_explicit_content_filter(entry, data):
+ return enums.try_enum(enums.ContentFilter, data)
+
+def _transform_permissions(entry, data):
+ return Permissions(data)
+
+def _transform_color(entry, data):
+ return Colour(data)
+
+def _transform_snowflake(entry, data):
+ return int(data)
+
+def _transform_channel(entry, data):
+ if data is None:
+ return None
+ return entry.guild.get_channel(int(data)) or Object(id=data)
+
+def _transform_owner_id(entry, data):
+ if data is None:
+ return None
+ return entry._get_member(int(data))
+
+def _transform_inviter_id(entry, data):
+ if data is None:
+ return None
+ return entry._get_member(int(data))
+
+def _transform_overwrites(entry, data):
+ overwrites = []
+ for elem in data:
+ allow = Permissions(elem['allow'])
+ deny = Permissions(elem['deny'])
+ ow = PermissionOverwrite.from_pair(allow, deny)
+
+ ow_type = elem['type']
+ ow_id = int(elem['id'])
+ if ow_type == 'role':
+ target = entry.guild.get_role(ow_id)
+ else:
+ target = entry._get_member(ow_id)
+
+ if target is None:
+ target = Object(id=ow_id)
+
+ overwrites.append((target, ow))
+
+ return overwrites
+
+class AuditLogDiff:
+ def __len__(self):
+ return len(self.__dict__)
+
+ def __iter__(self):
+ return iter(self.__dict__.items())
+
+ def __repr__(self):
+ values = ' '.join('%s=%r' % item for item in self.__dict__.items())
+ return '' % values
+
+class AuditLogChanges:
+ TRANSFORMERS = {
+ 'verification_level': (None, _transform_verification_level),
+ 'explicit_content_filter': (None, _transform_explicit_content_filter),
+ 'allow': (None, _transform_permissions),
+ 'deny': (None, _transform_permissions),
+ 'permissions': (None, _transform_permissions),
+ 'id': (None, _transform_snowflake),
+ 'color': ('colour', _transform_color),
+ 'owner_id': ('owner', _transform_owner_id),
+ 'inviter_id': ('inviter', _transform_inviter_id),
+ 'channel_id': ('channel', _transform_channel),
+ 'afk_channel_id': ('afk_channel', _transform_channel),
+ 'system_channel_id': ('system_channel', _transform_channel),
+ 'widget_channel_id': ('widget_channel', _transform_channel),
+ 'permission_overwrites': ('overwrites', _transform_overwrites),
+ 'splash_hash': ('splash', None),
+ 'icon_hash': ('icon', None),
+ 'avatar_hash': ('avatar', None),
+ 'rate_limit_per_user': ('slowmode_delay', None),
+ 'default_message_notifications': ('default_notifications', _transform_default_notifications),
+ }
+
+ def __init__(self, entry, data):
+ self.before = AuditLogDiff()
+ self.after = AuditLogDiff()
+
+ for elem in data:
+ attr = elem['key']
+
+ # special cases for role add/remove
+ if attr == '$add':
+ self._handle_role(self.before, self.after, entry, elem['new_value'])
+ continue
+ elif attr == '$remove':
+ self._handle_role(self.after, self.before, entry, elem['new_value'])
+ continue
+
+ transformer = self.TRANSFORMERS.get(attr)
+ if transformer:
+ key, transformer = transformer
+ if key:
+ attr = key
+
+ try:
+ before = elem['old_value']
+ except KeyError:
+ before = None
+ else:
+ if transformer:
+ before = transformer(entry, before)
+
+ setattr(self.before, attr, before)
+
+ try:
+ after = elem['new_value']
+ except KeyError:
+ after = None
+ else:
+ if transformer:
+ after = transformer(entry, after)
+
+ setattr(self.after, attr, after)
+
+ # add an alias
+ if hasattr(self.after, 'colour'):
+ self.after.color = self.after.colour
+ self.before.color = self.before.colour
+
+ def __repr__(self):
+ return '' % (self.before, self.after)
+
+ def _handle_role(self, first, second, entry, elem):
+ if not hasattr(first, 'roles'):
+ setattr(first, 'roles', [])
+
+ data = []
+ g = entry.guild
+
+ for e in elem:
+ role_id = int(e['id'])
+ role = g.get_role(role_id)
+
+ if role is None:
+ role = Object(id=role_id)
+ role.name = e['name']
+
+ data.append(role)
+
+ setattr(second, 'roles', data)
+
+class AuditLogEntry(Hashable):
+ r"""Represents an Audit Log entry.
+
+ You retrieve these via :meth:`Guild.audit_logs`.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two entries are equal.
+
+ .. describe:: x != y
+
+ Checks if two entries are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the entry's hash.
+
+ .. versionchanged:: 1.7
+ Audit log entries are now comparable and hashable.
+
+ Attributes
+ -----------
+ action: :class:`AuditLogAction`
+ The action that was done.
+ user: :class:`abc.User`
+ The user who initiated this action. Usually a :class:`Member`\, unless gone
+ then it's a :class:`User`.
+ id: :class:`int`
+ The entry ID.
+ target: Any
+ The target that got changed. The exact type of this depends on
+ the action being done.
+ reason: Optional[:class:`str`]
+ The reason this action was done.
+ extra: Any
+ Extra information that this entry has that might be useful.
+ For most actions, this is ``None``. However in some cases it
+ contains extra information. See :class:`AuditLogAction` for
+ which actions have this field filled out.
+ """
+
+ def __init__(self, *, users, data, guild):
+ self._state = guild._state
+ self.guild = guild
+ self._users = users
+ self._from_data(data)
+
+ def _from_data(self, data):
+ self.action = enums.try_enum(enums.AuditLogAction, data['action_type'])
+ self.id = int(data['id'])
+
+ # this key is technically not usually present
+ self.reason = data.get('reason')
+ self.extra = data.get('options')
+
+ if isinstance(self.action, enums.AuditLogAction) and self.extra:
+ if self.action is enums.AuditLogAction.member_prune:
+ # member prune has two keys with useful information
+ self.extra = type('_AuditLogProxy', (), {k: int(v) for k, v in self.extra.items()})()
+ elif self.action is enums.AuditLogAction.member_move or self.action is enums.AuditLogAction.message_delete:
+ channel_id = int(self.extra['channel_id'])
+ elems = {
+ 'count': int(self.extra['count']),
+ 'channel': self.guild.get_channel(channel_id) or Object(id=channel_id)
+ }
+ self.extra = type('_AuditLogProxy', (), elems)()
+ elif self.action is enums.AuditLogAction.member_disconnect:
+ # The member disconnect action has a dict with some information
+ elems = {
+ 'count': int(self.extra['count']),
+ }
+ self.extra = type('_AuditLogProxy', (), elems)()
+ elif self.action.name.endswith('pin'):
+ # the pin actions have a dict with some information
+ channel_id = int(self.extra['channel_id'])
+ message_id = int(self.extra['message_id'])
+ elems = {
+ 'channel': self.guild.get_channel(channel_id) or Object(id=channel_id),
+ 'message_id': message_id
+ }
+ self.extra = type('_AuditLogProxy', (), elems)()
+ elif self.action.name.startswith('overwrite_'):
+ # the overwrite_ actions have a dict with some information
+ instance_id = int(self.extra['id'])
+ the_type = self.extra.get('type')
+ if the_type == 'member':
+ self.extra = self._get_member(instance_id)
+ else:
+ role = self.guild.get_role(instance_id)
+ if role is None:
+ role = Object(id=instance_id)
+ role.name = self.extra.get('role_name')
+ self.extra = role
+
+ # this key is not present when the above is present, typically.
+ # It's a list of { new_value: a, old_value: b, key: c }
+ # where new_value and old_value are not guaranteed to be there depending
+ # on the action type, so let's just fetch it for now and only turn it
+ # into meaningful data when requested
+ self._changes = data.get('changes', [])
+
+ self.user = self._get_member(utils._get_as_snowflake(data, 'user_id'))
+ self._target_id = utils._get_as_snowflake(data, 'target_id')
+
+ def _get_member(self, user_id):
+ return self.guild.get_member(user_id) or self._users.get(user_id)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ @utils.cached_property
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the entry's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ @utils.cached_property
+ def target(self):
+ try:
+ converter = getattr(self, '_convert_target_' + self.action.target_type)
+ except AttributeError:
+ return Object(id=self._target_id)
+ else:
+ return converter(self._target_id)
+
+ @utils.cached_property
+ def category(self):
+ """Optional[:class:`AuditLogActionCategory`]: The category of the action, if applicable."""
+ return self.action.category
+
+ @utils.cached_property
+ def changes(self):
+ """:class:`AuditLogChanges`: The list of changes this entry has."""
+ obj = AuditLogChanges(self, self._changes)
+ del self._changes
+ return obj
+
+ @utils.cached_property
+ def before(self):
+ """:class:`AuditLogDiff`: The target's prior state."""
+ return self.changes.before
+
+ @utils.cached_property
+ def after(self):
+ """:class:`AuditLogDiff`: The target's subsequent state."""
+ return self.changes.after
+
+ def _convert_target_guild(self, target_id):
+ return self.guild
+
+ def _convert_target_channel(self, target_id):
+ ch = self.guild.get_channel(target_id)
+ if ch is None:
+ return Object(id=target_id)
+ return ch
+
+ def _convert_target_user(self, target_id):
+ return self._get_member(target_id)
+
+ def _convert_target_role(self, target_id):
+ role = self.guild.get_role(target_id)
+ if role is None:
+ return Object(id=target_id)
+ return role
+
+ def _convert_target_invite(self, target_id):
+ # invites have target_id set to null
+ # so figure out which change has the full invite data
+ changeset = self.before if self.action is enums.AuditLogAction.invite_delete else self.after
+
+ fake_payload = {
+ 'max_age': changeset.max_age,
+ 'max_uses': changeset.max_uses,
+ 'code': changeset.code,
+ 'temporary': changeset.temporary,
+ 'channel': changeset.channel,
+ 'uses': changeset.uses,
+ 'guild': self.guild,
+ }
+
+ obj = Invite(state=self._state, data=fake_payload)
+ try:
+ obj.inviter = changeset.inviter
+ except AttributeError:
+ pass
+ return obj
+
+ def _convert_target_emoji(self, target_id):
+ return self._state.get_emoji(target_id) or Object(id=target_id)
+
+ def _convert_target_message(self, target_id):
+ return self._get_member(target_id)
diff --git a/venv/lib64/python3.8/site-packages/discord/backoff.py b/venv/lib64/python3.8/site-packages/discord/backoff.py
new file mode 100644
index 0000000..0f49d15
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/backoff.py
@@ -0,0 +1,85 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import time
+import random
+
+class ExponentialBackoff:
+ """An implementation of the exponential backoff algorithm
+
+ Provides a convenient interface to implement an exponential backoff
+ for reconnecting or retrying transmissions in a distributed network.
+
+ Once instantiated, the delay method will return the next interval to
+ wait for when retrying a connection or transmission. The maximum
+ delay increases exponentially with each retry up to a maximum of
+ 2^10 * base, and is reset if no more attempts are needed in a period
+ of 2^11 * base seconds.
+
+ Parameters
+ ----------
+ base: :class:`int`
+ The base delay in seconds. The first retry-delay will be up to
+ this many seconds.
+ integral: :class:`bool`
+ Set to ``True`` if whole periods of base is desirable, otherwise any
+ number in between may be returned.
+ """
+
+ def __init__(self, base=1, *, integral=False):
+ self._base = base
+
+ self._exp = 0
+ self._max = 10
+ self._reset_time = base * 2 ** 11
+ self._last_invocation = time.monotonic()
+
+ # Use our own random instance to avoid messing with global one
+ rand = random.Random()
+ rand.seed()
+
+ self._randfunc = rand.randrange if integral else rand.uniform
+
+ def delay(self):
+ """Compute the next delay
+
+ Returns the next delay to wait according to the exponential
+ backoff algorithm. This is a value between 0 and base * 2^exp
+ where exponent starts off at 1 and is incremented at every
+ invocation of this method up to a maximum of 10.
+
+ If a period of more than base * 2^11 has passed since the last
+ retry, the exponent is reset to 1.
+ """
+ invocation = time.monotonic()
+ interval = invocation - self._last_invocation
+ self._last_invocation = invocation
+
+ if interval > self._reset_time:
+ self._exp = 0
+
+ self._exp = min(self._exp + 1, self._max)
+ return self._randfunc(0, self._base * 2 ** self._exp)
diff --git a/venv/lib64/python3.8/site-packages/discord/calls.py b/venv/lib64/python3.8/site-packages/discord/calls.py
new file mode 100644
index 0000000..2006b30
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/calls.py
@@ -0,0 +1,176 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import datetime
+
+from . import utils
+from .enums import VoiceRegion, try_enum
+from .member import VoiceState
+
+class CallMessage:
+ """Represents a group call message from Discord.
+
+ This is only received in cases where the message type is equivalent to
+ :attr:`MessageType.call`.
+
+ .. deprecated:: 1.7
+
+ Attributes
+ -----------
+ ended_timestamp: Optional[:class:`datetime.datetime`]
+ A naive UTC datetime object that represents the time that the call has ended.
+ participants: List[:class:`User`]
+ The list of users that are participating in this call.
+ message: :class:`Message`
+ The message associated with this call message.
+ """
+
+ def __init__(self, message, **kwargs):
+ self.message = message
+ self.ended_timestamp = utils.parse_time(kwargs.get('ended_timestamp'))
+ self.participants = kwargs.get('participants')
+
+ @property
+ def call_ended(self):
+ """:class:`bool`: Indicates if the call has ended.
+
+ .. deprecated:: 1.7
+ """
+ return self.ended_timestamp is not None
+
+ @property
+ def channel(self):
+ r""":class:`GroupChannel`\: The private channel associated with this message.
+
+ .. deprecated:: 1.7
+ """
+ return self.message.channel
+
+ @property
+ def duration(self):
+ """Queries the duration of the call.
+
+ If the call has not ended then the current duration will
+ be returned.
+
+ .. deprecated:: 1.7
+
+ Returns
+ ---------
+ :class:`datetime.timedelta`
+ The timedelta object representing the duration.
+ """
+ if self.ended_timestamp is None:
+ return datetime.datetime.utcnow() - self.message.created_at
+ else:
+ return self.ended_timestamp - self.message.created_at
+
+class GroupCall:
+ """Represents the actual group call from Discord.
+
+ This is accompanied with a :class:`CallMessage` denoting the information.
+
+ .. deprecated:: 1.7
+
+ Attributes
+ -----------
+ call: :class:`CallMessage`
+ The call message associated with this group call.
+ unavailable: :class:`bool`
+ Denotes if this group call is unavailable.
+ ringing: List[:class:`User`]
+ A list of users that are currently being rung to join the call.
+ region: :class:`VoiceRegion`
+ The guild region the group call is being hosted on.
+ """
+
+ def __init__(self, **kwargs):
+ self.call = kwargs.get('call')
+ self.unavailable = kwargs.get('unavailable')
+ self._voice_states = {}
+
+ for state in kwargs.get('voice_states', []):
+ self._update_voice_state(state)
+
+ self._update(**kwargs)
+
+ def _update(self, **kwargs):
+ self.region = try_enum(VoiceRegion, kwargs.get('region'))
+ lookup = {u.id: u for u in self.call.channel.recipients}
+ me = self.call.channel.me
+ lookup[me.id] = me
+ self.ringing = list(filter(None, map(lookup.get, kwargs.get('ringing', []))))
+
+ def _update_voice_state(self, data):
+ user_id = int(data['user_id'])
+ # left the voice channel?
+ if data['channel_id'] is None:
+ self._voice_states.pop(user_id, None)
+ else:
+ self._voice_states[user_id] = VoiceState(data=data, channel=self.channel)
+
+ @property
+ def connected(self):
+ """List[:class:`User`]: A property that returns all users that are currently in this call.
+
+ .. deprecated:: 1.7
+ """
+ ret = [u for u in self.channel.recipients if self.voice_state_for(u) is not None]
+ me = self.channel.me
+ if self.voice_state_for(me) is not None:
+ ret.append(me)
+
+ return ret
+
+ @property
+ def channel(self):
+ r""":class:`GroupChannel`\: Returns the channel the group call is in.
+
+ .. deprecated:: 1.7
+ """
+ return self.call.channel
+
+ @utils.deprecated()
+ def voice_state_for(self, user):
+ """Retrieves the :class:`VoiceState` for a specified :class:`User`.
+
+ If the :class:`User` has no voice state then this function returns
+ ``None``.
+
+ .. deprecated:: 1.7
+
+ Parameters
+ ------------
+ user: :class:`User`
+ The user to retrieve the voice state for.
+
+ Returns
+ --------
+ Optional[:class:`VoiceState`]
+ The voice state associated with this user.
+ """
+
+ return self._voice_states.get(user.id)
diff --git a/venv/lib64/python3.8/site-packages/discord/channel.py b/venv/lib64/python3.8/site-packages/discord/channel.py
new file mode 100644
index 0000000..3510b80
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/channel.py
@@ -0,0 +1,1569 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import time
+import asyncio
+
+import discord.abc
+from .permissions import Permissions
+from .enums import ChannelType, try_enum, VoiceRegion
+from .mixins import Hashable
+from . import utils
+from .asset import Asset
+from .errors import ClientException, NoMoreItems, InvalidArgument
+
+__all__ = (
+ 'TextChannel',
+ 'VoiceChannel',
+ 'StageChannel',
+ 'DMChannel',
+ 'CategoryChannel',
+ 'StoreChannel',
+ 'GroupChannel',
+ '_channel_factory',
+)
+
+async def _single_delete_strategy(messages):
+ for m in messages:
+ await m.delete()
+
+class TextChannel(discord.abc.Messageable, discord.abc.GuildChannel, Hashable):
+ """Represents a Discord guild text channel.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns the channel's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The channel name.
+ guild: :class:`Guild`
+ The guild the channel belongs to.
+ id: :class:`int`
+ The channel ID.
+ category_id: Optional[:class:`int`]
+ The category channel ID this channel belongs to, if applicable.
+ topic: Optional[:class:`str`]
+ The channel's topic. ``None`` if it doesn't exist.
+ position: :class:`int`
+ The position in the channel list. This is a number that starts at 0. e.g. the
+ top channel is position 0.
+ last_message_id: Optional[:class:`int`]
+ The last message ID of the message sent to this channel. It may
+ *not* point to an existing or valid message.
+ slowmode_delay: :class:`int`
+ The number of seconds a member must wait between sending messages
+ in this channel. A value of `0` denotes that it is disabled.
+ Bots and users with :attr:`~Permissions.manage_channels` or
+ :attr:`~Permissions.manage_messages` bypass slowmode.
+ """
+
+ __slots__ = ('name', 'id', 'guild', 'topic', '_state', 'nsfw',
+ 'category_id', 'position', 'slowmode_delay', '_overwrites',
+ '_type', 'last_message_id')
+
+ def __init__(self, *, state, guild, data):
+ self._state = state
+ self.id = int(data['id'])
+ self._type = data['type']
+ self._update(guild, data)
+
+ def __repr__(self):
+ attrs = [
+ ('id', self.id),
+ ('name', self.name),
+ ('position', self.position),
+ ('nsfw', self.nsfw),
+ ('news', self.is_news()),
+ ('category_id', self.category_id)
+ ]
+ return '<%s %s>' % (self.__class__.__name__, ' '.join('%s=%r' % t for t in attrs))
+
+ def _update(self, guild, data):
+ self.guild = guild
+ self.name = data['name']
+ self.category_id = utils._get_as_snowflake(data, 'parent_id')
+ self.topic = data.get('topic')
+ self.position = data['position']
+ self.nsfw = data.get('nsfw', False)
+ # Does this need coercion into `int`? No idea yet.
+ self.slowmode_delay = data.get('rate_limit_per_user', 0)
+ self._type = data.get('type', self._type)
+ self.last_message_id = utils._get_as_snowflake(data, 'last_message_id')
+ self._fill_overwrites(data)
+
+ async def _get_channel(self):
+ return self
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return try_enum(ChannelType, self._type)
+
+ @property
+ def _sorting_bucket(self):
+ return ChannelType.text.value
+
+ @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
+ def permissions_for(self, member):
+ base = super().permissions_for(member)
+
+ # text channels do not have voice related permissions
+ denied = Permissions.voice()
+ base.value &= ~denied.value
+ return base
+
+ @property
+ def members(self):
+ """List[:class:`Member`]: Returns all members that can see this channel."""
+ return [m for m in self.guild.members if self.permissions_for(m).read_messages]
+
+ def is_nsfw(self):
+ """:class:`bool`: Checks if the channel is NSFW."""
+ return self.nsfw
+
+ def is_news(self):
+ """:class:`bool`: Checks if the channel is a news channel."""
+ return self._type == ChannelType.news.value
+
+ @property
+ def last_message(self):
+ """Fetches the last message from this channel in cache.
+
+ The message might not be valid or point to an existing message.
+
+ .. admonition:: Reliable Fetching
+ :class: helpful
+
+ For a slightly more reliable method of fetching the
+ last message, consider using either :meth:`history`
+ or :meth:`fetch_message` with the :attr:`last_message_id`
+ attribute.
+
+ Returns
+ ---------
+ Optional[:class:`Message`]
+ The last message in this channel or ``None`` if not found.
+ """
+ return self._state._get_message(self.last_message_id) if self.last_message_id else None
+
+ async def edit(self, *, reason=None, **options):
+ """|coro|
+
+ Edits the channel.
+
+ You must have the :attr:`~Permissions.manage_channels` permission to
+ use this.
+
+ .. versionchanged:: 1.3
+ The ``overwrites`` keyword-only parameter was added.
+
+ .. versionchanged:: 1.4
+ The ``type`` keyword-only parameter was added.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The new channel name.
+ topic: :class:`str`
+ The new channel's topic.
+ position: :class:`int`
+ The new channel's position.
+ nsfw: :class:`bool`
+ To mark the channel as NSFW or not.
+ sync_permissions: :class:`bool`
+ Whether to sync permissions with the channel's new or pre-existing
+ category. Defaults to ``False``.
+ category: Optional[:class:`CategoryChannel`]
+ The new category for this channel. Can be ``None`` to remove the
+ category.
+ slowmode_delay: :class:`int`
+ Specifies the slowmode rate limit for user in this channel, in seconds.
+ A value of `0` disables slowmode. The maximum value possible is `21600`.
+ type: :class:`ChannelType`
+ Change the type of this text channel. Currently, only conversion between
+ :attr:`ChannelType.text` and :attr:`ChannelType.news` is supported. This
+ is only available to guilds that contain ``NEWS`` in :attr:`Guild.features`.
+ reason: Optional[:class:`str`]
+ The reason for editing this channel. Shows up on the audit log.
+ overwrites: :class:`dict`
+ A :class:`dict` of target (either a role or a member) to
+ :class:`PermissionOverwrite` to apply to the channel.
+
+ Raises
+ ------
+ InvalidArgument
+ If position is less than 0 or greater than the number of channels, or if
+ the permission overwrite information is not in proper form.
+ Forbidden
+ You do not have permissions to edit the channel.
+ HTTPException
+ Editing the channel failed.
+ """
+ await self._edit(options, reason=reason)
+
+ @utils.copy_doc(discord.abc.GuildChannel.clone)
+ async def clone(self, *, name=None, reason=None):
+ return await self._clone_impl({
+ 'topic': self.topic,
+ 'nsfw': self.nsfw,
+ 'rate_limit_per_user': self.slowmode_delay
+ }, name=name, reason=reason)
+
+ async def delete_messages(self, messages):
+ """|coro|
+
+ Deletes a list of messages. This is similar to :meth:`Message.delete`
+ except it bulk deletes multiple messages.
+
+ As a special case, if the number of messages is 0, then nothing
+ is done. If the number of messages is 1 then single message
+ delete is done. If it's more than two, then bulk delete is used.
+
+ You cannot bulk delete more than 100 messages or messages that
+ are older than 14 days old.
+
+ You must have the :attr:`~Permissions.manage_messages` permission to
+ use this.
+
+ Usable only by bot accounts.
+
+ Parameters
+ -----------
+ messages: Iterable[:class:`abc.Snowflake`]
+ An iterable of messages denoting which ones to bulk delete.
+
+ Raises
+ ------
+ ClientException
+ The number of messages to delete was more than 100.
+ Forbidden
+ You do not have proper permissions to delete the messages or
+ you're not using a bot account.
+ NotFound
+ If single delete, then the message was already deleted.
+ HTTPException
+ Deleting the messages failed.
+ """
+ if not isinstance(messages, (list, tuple)):
+ messages = list(messages)
+
+ if len(messages) == 0:
+ return # do nothing
+
+ if len(messages) == 1:
+ message_id = messages[0].id
+ await self._state.http.delete_message(self.id, message_id)
+ return
+
+ if len(messages) > 100:
+ raise ClientException('Can only bulk delete messages up to 100 messages')
+
+ message_ids = [m.id for m in messages]
+ await self._state.http.delete_messages(self.id, message_ids)
+
+ async def purge(self, *, limit=100, check=None, before=None, after=None, around=None, oldest_first=False, bulk=True):
+ """|coro|
+
+ Purges a list of messages that meet the criteria given by the predicate
+ ``check``. If a ``check`` is not provided then all messages are deleted
+ without discrimination.
+
+ You must have the :attr:`~Permissions.manage_messages` permission to
+ delete messages even if they are your own (unless you are a user
+ account). The :attr:`~Permissions.read_message_history` permission is
+ also needed to retrieve message history.
+
+ Internally, this employs a different number of strategies depending
+ on the conditions met such as if a bulk delete is possible or if
+ the account is a user bot or not.
+
+ Examples
+ ---------
+
+ Deleting bot's messages ::
+
+ def is_me(m):
+ return m.author == client.user
+
+ deleted = await channel.purge(limit=100, check=is_me)
+ await channel.send('Deleted {} message(s)'.format(len(deleted)))
+
+ Parameters
+ -----------
+ limit: Optional[:class:`int`]
+ The number of messages to search through. This is not the number
+ of messages that will be deleted, though it can be.
+ check: Callable[[:class:`Message`], :class:`bool`]
+ The function used to check if a message should be deleted.
+ It must take a :class:`Message` as its sole parameter.
+ before: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]]
+ Same as ``before`` in :meth:`history`.
+ after: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]]
+ Same as ``after`` in :meth:`history`.
+ around: Optional[Union[:class:`abc.Snowflake`, :class:`datetime.datetime`]]
+ Same as ``around`` in :meth:`history`.
+ oldest_first: Optional[:class:`bool`]
+ Same as ``oldest_first`` in :meth:`history`.
+ bulk: :class:`bool`
+ If ``True``, use bulk delete. Setting this to ``False`` is useful for mass-deleting
+ a bot's own messages without :attr:`Permissions.manage_messages`. When ``True``, will
+ fall back to single delete if current account is a user bot (now deprecated), or if messages are
+ older than two weeks.
+
+ Raises
+ -------
+ Forbidden
+ You do not have proper permissions to do the actions required.
+ HTTPException
+ Purging the messages failed.
+
+ Returns
+ --------
+ List[:class:`.Message`]
+ The list of messages that were deleted.
+ """
+
+ if check is None:
+ check = lambda m: True
+
+ iterator = self.history(limit=limit, before=before, after=after, oldest_first=oldest_first, around=around)
+ ret = []
+ count = 0
+
+ minimum_time = int((time.time() - 14 * 24 * 60 * 60) * 1000.0 - 1420070400000) << 22
+ strategy = self.delete_messages if self._state.is_bot and bulk else _single_delete_strategy
+
+ while True:
+ try:
+ msg = await iterator.next()
+ except NoMoreItems:
+ # no more messages to poll
+ if count >= 2:
+ # more than 2 messages -> bulk delete
+ to_delete = ret[-count:]
+ await strategy(to_delete)
+ elif count == 1:
+ # delete a single message
+ await ret[-1].delete()
+
+ return ret
+ else:
+ if count == 100:
+ # we've reached a full 'queue'
+ to_delete = ret[-100:]
+ await strategy(to_delete)
+ count = 0
+ await asyncio.sleep(1)
+
+ if check(msg):
+ if msg.id < minimum_time:
+ # older than 14 days old
+ if count == 1:
+ await ret[-1].delete()
+ elif count >= 2:
+ to_delete = ret[-count:]
+ await strategy(to_delete)
+
+ count = 0
+ strategy = _single_delete_strategy
+
+ count += 1
+ ret.append(msg)
+
+ async def webhooks(self):
+ """|coro|
+
+ Gets the list of webhooks from this channel.
+
+ Requires :attr:`~.Permissions.manage_webhooks` permissions.
+
+ Raises
+ -------
+ Forbidden
+ You don't have permissions to get the webhooks.
+
+ Returns
+ --------
+ List[:class:`Webhook`]
+ The webhooks for this channel.
+ """
+
+ from .webhook import Webhook
+ data = await self._state.http.channel_webhooks(self.id)
+ return [Webhook.from_state(d, state=self._state) for d in data]
+
+ async def create_webhook(self, *, name, avatar=None, reason=None):
+ """|coro|
+
+ Creates a webhook for this channel.
+
+ Requires :attr:`~.Permissions.manage_webhooks` permissions.
+
+ .. versionchanged:: 1.1
+ Added the ``reason`` keyword-only parameter.
+
+ Parameters
+ -------------
+ name: :class:`str`
+ The webhook's name.
+ avatar: Optional[:class:`bytes`]
+ A :term:`py:bytes-like object` representing the webhook's default avatar.
+ This operates similarly to :meth:`~ClientUser.edit`.
+ reason: Optional[:class:`str`]
+ The reason for creating this webhook. Shows up in the audit logs.
+
+ Raises
+ -------
+ HTTPException
+ Creating the webhook failed.
+ Forbidden
+ You do not have permissions to create a webhook.
+
+ Returns
+ --------
+ :class:`Webhook`
+ The created webhook.
+ """
+
+ from .webhook import Webhook
+ if avatar is not None:
+ avatar = utils._bytes_to_base64_data(avatar)
+
+ data = await self._state.http.create_webhook(self.id, name=str(name), avatar=avatar, reason=reason)
+ return Webhook.from_state(data, state=self._state)
+
+ async def follow(self, *, destination, reason=None):
+ """
+ Follows a channel using a webhook.
+
+ Only news channels can be followed.
+
+ .. note::
+
+ The webhook returned will not provide a token to do webhook
+ actions, as Discord does not provide it.
+
+ .. versionadded:: 1.3
+
+ Parameters
+ -----------
+ destination: :class:`TextChannel`
+ The channel you would like to follow from.
+ reason: Optional[:class:`str`]
+ The reason for following the channel. Shows up on the destination guild's audit log.
+
+ .. versionadded:: 1.4
+
+ Raises
+ -------
+ HTTPException
+ Following the channel failed.
+ Forbidden
+ You do not have the permissions to create a webhook.
+
+ Returns
+ --------
+ :class:`Webhook`
+ The created webhook.
+ """
+
+ if not self.is_news():
+ raise ClientException('The channel must be a news channel.')
+
+ if not isinstance(destination, TextChannel):
+ raise InvalidArgument('Expected TextChannel received {0.__name__}'.format(type(destination)))
+
+ from .webhook import Webhook
+ data = await self._state.http.follow_webhook(self.id, webhook_channel_id=destination.id, reason=reason)
+ return Webhook._as_follower(data, channel=destination, user=self._state.user)
+
+ def get_partial_message(self, message_id):
+ """Creates a :class:`PartialMessage` from the message ID.
+
+ This is useful if you want to work with a message and only have its ID without
+ doing an unnecessary API call.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ ------------
+ message_id: :class:`int`
+ The message ID to create a partial message for.
+
+ Returns
+ ---------
+ :class:`PartialMessage`
+ The partial message.
+ """
+
+ from .message import PartialMessage
+ return PartialMessage(channel=self, id=message_id)
+
+class VocalGuildChannel(discord.abc.Connectable, discord.abc.GuildChannel, Hashable):
+ __slots__ = ('name', 'id', 'guild', 'bitrate', 'user_limit',
+ '_state', 'position', '_overwrites', 'category_id',
+ 'rtc_region')
+
+ def __init__(self, *, state, guild, data):
+ self._state = state
+ self.id = int(data['id'])
+ self._update(guild, data)
+
+ def _get_voice_client_key(self):
+ return self.guild.id, 'guild_id'
+
+ def _get_voice_state_pair(self):
+ return self.guild.id, self.id
+
+ def _update(self, guild, data):
+ self.guild = guild
+ self.name = data['name']
+ self.rtc_region = data.get('rtc_region')
+ if self.rtc_region:
+ self.rtc_region = try_enum(VoiceRegion, self.rtc_region)
+ self.category_id = utils._get_as_snowflake(data, 'parent_id')
+ self.position = data['position']
+ self.bitrate = data.get('bitrate')
+ self.user_limit = data.get('user_limit')
+ self._fill_overwrites(data)
+
+ @property
+ def _sorting_bucket(self):
+ return ChannelType.voice.value
+
+ @property
+ def members(self):
+ """List[:class:`Member`]: Returns all members that are currently inside this voice channel."""
+ ret = []
+ for user_id, state in self.guild._voice_states.items():
+ if state.channel and state.channel.id == self.id:
+ member = self.guild.get_member(user_id)
+ if member is not None:
+ ret.append(member)
+ return ret
+
+ @property
+ def voice_states(self):
+ """Returns a mapping of member IDs who have voice states in this channel.
+
+ .. versionadded:: 1.3
+
+ .. note::
+
+ This function is intentionally low level to replace :attr:`members`
+ when the member cache is unavailable.
+
+ Returns
+ --------
+ Mapping[:class:`int`, :class:`VoiceState`]
+ The mapping of member ID to a voice state.
+ """
+ return {key: value for key, value in self.guild._voice_states.items() if value.channel.id == self.id}
+
+ @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
+ def permissions_for(self, member):
+ base = super().permissions_for(member)
+
+ # voice channels cannot be edited by people who can't connect to them
+ # It also implicitly denies all other voice perms
+ if not base.connect:
+ denied = Permissions.voice()
+ denied.update(manage_channels=True, manage_roles=True)
+ base.value &= ~denied.value
+ return base
+
+class VoiceChannel(VocalGuildChannel):
+ """Represents a Discord guild voice channel.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns the channel's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The channel name.
+ guild: :class:`Guild`
+ The guild the channel belongs to.
+ id: :class:`int`
+ The channel ID.
+ category_id: Optional[:class:`int`]
+ The category channel ID this channel belongs to, if applicable.
+ position: :class:`int`
+ The position in the channel list. This is a number that starts at 0. e.g. the
+ top channel is position 0.
+ bitrate: :class:`int`
+ The channel's preferred audio bitrate in bits per second.
+ user_limit: :class:`int`
+ The channel's limit for number of members that can be in a voice channel.
+ rtc_region: Optional[:class:`VoiceRegion`]
+ The region for the voice channel's voice communication.
+ A value of ``None`` indicates automatic voice region detection.
+
+ .. versionadded:: 1.7
+ """
+
+ __slots__ = ()
+
+ def __repr__(self):
+ attrs = [
+ ('id', self.id),
+ ('name', self.name),
+ ('rtc_region', self.rtc_region),
+ ('position', self.position),
+ ('bitrate', self.bitrate),
+ ('user_limit', self.user_limit),
+ ('category_id', self.category_id)
+ ]
+ return '<%s %s>' % (self.__class__.__name__, ' '.join('%s=%r' % t for t in attrs))
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.voice
+
+ @utils.copy_doc(discord.abc.GuildChannel.clone)
+ async def clone(self, *, name=None, reason=None):
+ return await self._clone_impl({
+ 'bitrate': self.bitrate,
+ 'user_limit': self.user_limit
+ }, name=name, reason=reason)
+
+ async def edit(self, *, reason=None, **options):
+ """|coro|
+
+ Edits the channel.
+
+ You must have the :attr:`~Permissions.manage_channels` permission to
+ use this.
+
+ .. versionchanged:: 1.3
+ The ``overwrites`` keyword-only parameter was added.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The new channel's name.
+ bitrate: :class:`int`
+ The new channel's bitrate.
+ user_limit: :class:`int`
+ The new channel's user limit.
+ position: :class:`int`
+ The new channel's position.
+ sync_permissions: :class:`bool`
+ Whether to sync permissions with the channel's new or pre-existing
+ category. Defaults to ``False``.
+ category: Optional[:class:`CategoryChannel`]
+ The new category for this channel. Can be ``None`` to remove the
+ category.
+ reason: Optional[:class:`str`]
+ The reason for editing this channel. Shows up on the audit log.
+ overwrites: :class:`dict`
+ A :class:`dict` of target (either a role or a member) to
+ :class:`PermissionOverwrite` to apply to the channel.
+ rtc_region: Optional[:class:`VoiceRegion`]
+ The new region for the voice channel's voice communication.
+ A value of ``None`` indicates automatic voice region detection.
+
+ .. versionadded:: 1.7
+
+ Raises
+ ------
+ InvalidArgument
+ If the permission overwrite information is not in proper form.
+ Forbidden
+ You do not have permissions to edit the channel.
+ HTTPException
+ Editing the channel failed.
+ """
+
+ await self._edit(options, reason=reason)
+
+class StageChannel(VocalGuildChannel):
+ """Represents a Discord guild stage channel.
+
+ .. versionadded:: 1.7
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns the channel's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The channel name.
+ guild: :class:`Guild`
+ The guild the channel belongs to.
+ id: :class:`int`
+ The channel ID.
+ topic: Optional[:class:`str`]
+ The channel's topic. ``None`` if it isn't set.
+ category_id: Optional[:class:`int`]
+ The category channel ID this channel belongs to, if applicable.
+ position: :class:`int`
+ The position in the channel list. This is a number that starts at 0. e.g. the
+ top channel is position 0.
+ bitrate: :class:`int`
+ The channel's preferred audio bitrate in bits per second.
+ user_limit: :class:`int`
+ The channel's limit for number of members that can be in a stage channel.
+ rtc_region: Optional[:class:`VoiceRegion`]
+ The region for the stage channel's voice communication.
+ A value of ``None`` indicates automatic voice region detection.
+ """
+ __slots__ = ('topic',)
+
+ def __repr__(self):
+ attrs = [
+ ('id', self.id),
+ ('name', self.name),
+ ('topic', self.topic),
+ ('rtc_region', self.rtc_region),
+ ('position', self.position),
+ ('bitrate', self.bitrate),
+ ('user_limit', self.user_limit),
+ ('category_id', self.category_id)
+ ]
+ return '<%s %s>' % (self.__class__.__name__, ' '.join('%s=%r' % t for t in attrs))
+
+ def _update(self, guild, data):
+ super()._update(guild, data)
+ self.topic = data.get('topic')
+
+ @property
+ def requesting_to_speak(self):
+ """List[:class:`Member`]: A list of members who are requesting to speak in the stage channel."""
+ return [member for member in self.members if member.voice.requested_to_speak_at is not None]
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.stage_voice
+
+ @utils.copy_doc(discord.abc.GuildChannel.clone)
+ async def clone(self, *, name=None, reason=None):
+ return await self._clone_impl({
+ 'topic': self.topic,
+ }, name=name, reason=reason)
+
+ async def edit(self, *, reason=None, **options):
+ """|coro|
+
+ Edits the channel.
+
+ You must have the :attr:`~Permissions.manage_channels` permission to
+ use this.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The new channel's name.
+ topic: :class:`str`
+ The new channel's topic.
+ position: :class:`int`
+ The new channel's position.
+ sync_permissions: :class:`bool`
+ Whether to sync permissions with the channel's new or pre-existing
+ category. Defaults to ``False``.
+ category: Optional[:class:`CategoryChannel`]
+ The new category for this channel. Can be ``None`` to remove the
+ category.
+ reason: Optional[:class:`str`]
+ The reason for editing this channel. Shows up on the audit log.
+ overwrites: :class:`dict`
+ A :class:`dict` of target (either a role or a member) to
+ :class:`PermissionOverwrite` to apply to the channel.
+ rtc_region: Optional[:class:`VoiceRegion`]
+ The new region for the stage channel's voice communication.
+ A value of ``None`` indicates automatic voice region detection.
+
+ Raises
+ ------
+ InvalidArgument
+ If the permission overwrite information is not in proper form.
+ Forbidden
+ You do not have permissions to edit the channel.
+ HTTPException
+ Editing the channel failed.
+ """
+
+ await self._edit(options, reason=reason)
+
+class CategoryChannel(discord.abc.GuildChannel, Hashable):
+ """Represents a Discord channel category.
+
+ These are useful to group channels to logical compartments.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the category's hash.
+
+ .. describe:: str(x)
+
+ Returns the category's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The category name.
+ guild: :class:`Guild`
+ The guild the category belongs to.
+ id: :class:`int`
+ The category channel ID.
+ position: :class:`int`
+ The position in the category list. This is a number that starts at 0. e.g. the
+ top category is position 0.
+ """
+
+ __slots__ = ('name', 'id', 'guild', 'nsfw', '_state', 'position', '_overwrites', 'category_id')
+
+ def __init__(self, *, state, guild, data):
+ self._state = state
+ self.id = int(data['id'])
+ self._update(guild, data)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def _update(self, guild, data):
+ self.guild = guild
+ self.name = data['name']
+ self.category_id = utils._get_as_snowflake(data, 'parent_id')
+ self.nsfw = data.get('nsfw', False)
+ self.position = data['position']
+ self._fill_overwrites(data)
+
+ @property
+ def _sorting_bucket(self):
+ return ChannelType.category.value
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.category
+
+ def is_nsfw(self):
+ """:class:`bool`: Checks if the category is NSFW."""
+ return self.nsfw
+
+ @utils.copy_doc(discord.abc.GuildChannel.clone)
+ async def clone(self, *, name=None, reason=None):
+ return await self._clone_impl({
+ 'nsfw': self.nsfw
+ }, name=name, reason=reason)
+
+ async def edit(self, *, reason=None, **options):
+ """|coro|
+
+ Edits the channel.
+
+ You must have the :attr:`~Permissions.manage_channels` permission to
+ use this.
+
+ .. versionchanged:: 1.3
+ The ``overwrites`` keyword-only parameter was added.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The new category's name.
+ position: :class:`int`
+ The new category's position.
+ nsfw: :class:`bool`
+ To mark the category as NSFW or not.
+ reason: Optional[:class:`str`]
+ The reason for editing this category. Shows up on the audit log.
+ overwrites: :class:`dict`
+ A :class:`dict` of target (either a role or a member) to
+ :class:`PermissionOverwrite` to apply to the channel.
+
+ Raises
+ ------
+ InvalidArgument
+ If position is less than 0 or greater than the number of categories.
+ Forbidden
+ You do not have permissions to edit the category.
+ HTTPException
+ Editing the category failed.
+ """
+
+ await self._edit(options=options, reason=reason)
+
+ @utils.copy_doc(discord.abc.GuildChannel.move)
+ async def move(self, **kwargs):
+ kwargs.pop('category', None)
+ await super().move(**kwargs)
+
+ @property
+ def channels(self):
+ """List[:class:`abc.GuildChannel`]: Returns the channels that are under this category.
+
+ These are sorted by the official Discord UI, which places voice channels below the text channels.
+ """
+ def comparator(channel):
+ return (not isinstance(channel, TextChannel), channel.position)
+
+ ret = [c for c in self.guild.channels if c.category_id == self.id]
+ ret.sort(key=comparator)
+ return ret
+
+ @property
+ def text_channels(self):
+ """List[:class:`TextChannel`]: Returns the text channels that are under this category."""
+ ret = [c for c in self.guild.channels
+ if c.category_id == self.id
+ and isinstance(c, TextChannel)]
+ ret.sort(key=lambda c: (c.position, c.id))
+ return ret
+
+ @property
+ def voice_channels(self):
+ """List[:class:`VoiceChannel`]: Returns the voice channels that are under this category."""
+ ret = [c for c in self.guild.channels
+ if c.category_id == self.id
+ and isinstance(c, VoiceChannel)]
+ ret.sort(key=lambda c: (c.position, c.id))
+ return ret
+
+ @property
+ def stage_channels(self):
+ """List[:class:`StageChannel`]: Returns the voice channels that are under this category.
+
+ .. versionadded:: 1.7
+ """
+ ret = [c for c in self.guild.channels
+ if c.category_id == self.id
+ and isinstance(c, StageChannel)]
+ ret.sort(key=lambda c: (c.position, c.id))
+ return ret
+
+ async def create_text_channel(self, name, *, overwrites=None, reason=None, **options):
+ """|coro|
+
+ A shortcut method to :meth:`Guild.create_text_channel` to create a :class:`TextChannel` in the category.
+
+ Returns
+ -------
+ :class:`TextChannel`
+ The channel that was just created.
+ """
+ return await self.guild.create_text_channel(name, overwrites=overwrites, category=self, reason=reason, **options)
+
+ async def create_voice_channel(self, name, *, overwrites=None, reason=None, **options):
+ """|coro|
+
+ A shortcut method to :meth:`Guild.create_voice_channel` to create a :class:`VoiceChannel` in the category.
+
+ Returns
+ -------
+ :class:`VoiceChannel`
+ The channel that was just created.
+ """
+ return await self.guild.create_voice_channel(name, overwrites=overwrites, category=self, reason=reason, **options)
+
+ async def create_stage_channel(self, name, *, overwrites=None, reason=None, **options):
+ """|coro|
+
+ A shortcut method to :meth:`Guild.create_stage_channel` to create a :class:`StageChannel` in the category.
+
+ .. versionadded:: 1.7
+
+ Returns
+ -------
+ :class:`StageChannel`
+ The channel that was just created.
+ """
+ return await self.guild.create_stage_channel(name, overwrites=overwrites, category=self, reason=reason, **options)
+
+class StoreChannel(discord.abc.GuildChannel, Hashable):
+ """Represents a Discord guild store channel.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns the channel's name.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The channel name.
+ guild: :class:`Guild`
+ The guild the channel belongs to.
+ id: :class:`int`
+ The channel ID.
+ category_id: :class:`int`
+ The category channel ID this channel belongs to.
+ position: :class:`int`
+ The position in the channel list. This is a number that starts at 0. e.g. the
+ top channel is position 0.
+ """
+ __slots__ = ('name', 'id', 'guild', '_state', 'nsfw',
+ 'category_id', 'position', '_overwrites',)
+
+ def __init__(self, *, state, guild, data):
+ self._state = state
+ self.id = int(data['id'])
+ self._update(guild, data)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def _update(self, guild, data):
+ self.guild = guild
+ self.name = data['name']
+ self.category_id = utils._get_as_snowflake(data, 'parent_id')
+ self.position = data['position']
+ self.nsfw = data.get('nsfw', False)
+ self._fill_overwrites(data)
+
+ @property
+ def _sorting_bucket(self):
+ return ChannelType.text.value
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.store
+
+ @utils.copy_doc(discord.abc.GuildChannel.permissions_for)
+ def permissions_for(self, member):
+ base = super().permissions_for(member)
+
+ # store channels do not have voice related permissions
+ denied = Permissions.voice()
+ base.value &= ~denied.value
+ return base
+
+ def is_nsfw(self):
+ """:class:`bool`: Checks if the channel is NSFW."""
+ return self.nsfw
+
+ @utils.copy_doc(discord.abc.GuildChannel.clone)
+ async def clone(self, *, name=None, reason=None):
+ return await self._clone_impl({
+ 'nsfw': self.nsfw
+ }, name=name, reason=reason)
+
+ async def edit(self, *, reason=None, **options):
+ """|coro|
+
+ Edits the channel.
+
+ You must have the :attr:`~Permissions.manage_channels` permission to
+ use this.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The new channel name.
+ position: :class:`int`
+ The new channel's position.
+ nsfw: :class:`bool`
+ To mark the channel as NSFW or not.
+ sync_permissions: :class:`bool`
+ Whether to sync permissions with the channel's new or pre-existing
+ category. Defaults to ``False``.
+ category: Optional[:class:`CategoryChannel`]
+ The new category for this channel. Can be ``None`` to remove the
+ category.
+ reason: Optional[:class:`str`]
+ The reason for editing this channel. Shows up on the audit log.
+ overwrites: :class:`dict`
+ A :class:`dict` of target (either a role or a member) to
+ :class:`PermissionOverwrite` to apply to the channel.
+
+ .. versionadded:: 1.3
+
+ Raises
+ ------
+ InvalidArgument
+ If position is less than 0 or greater than the number of channels, or if
+ the permission overwrite information is not in proper form.
+ Forbidden
+ You do not have permissions to edit the channel.
+ HTTPException
+ Editing the channel failed.
+ """
+ await self._edit(options, reason=reason)
+
+class DMChannel(discord.abc.Messageable, Hashable):
+ """Represents a Discord direct message channel.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns a string representation of the channel
+
+ Attributes
+ ----------
+ recipient: :class:`User`
+ The user you are participating with in the direct message channel.
+ me: :class:`ClientUser`
+ The user presenting yourself.
+ id: :class:`int`
+ The direct message channel ID.
+ """
+
+ __slots__ = ('id', 'recipient', 'me', '_state')
+
+ def __init__(self, *, me, state, data):
+ self._state = state
+ self.recipient = state.store_user(data['recipients'][0])
+ self.me = me
+ self.id = int(data['id'])
+
+ async def _get_channel(self):
+ return self
+
+ def __str__(self):
+ return 'Direct Message with %s' % self.recipient
+
+ def __repr__(self):
+ return ''.format(self)
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.private
+
+ @property
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the direct message channel's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ def permissions_for(self, user=None):
+ """Handles permission resolution for a :class:`User`.
+
+ This function is there for compatibility with other channel types.
+
+ Actual direct messages do not really have the concept of permissions.
+
+ This returns all the Text related permissions set to ``True`` except:
+
+ - :attr:`~Permissions.send_tts_messages`: You cannot send TTS messages in a DM.
+ - :attr:`~Permissions.manage_messages`: You cannot delete others messages in a DM.
+
+ Parameters
+ -----------
+ user: :class:`User`
+ The user to check permissions for. This parameter is ignored
+ but kept for compatibility.
+
+ Returns
+ --------
+ :class:`Permissions`
+ The resolved permissions.
+ """
+
+ base = Permissions.text()
+ base.read_messages = True
+ base.send_tts_messages = False
+ base.manage_messages = False
+ return base
+
+ def get_partial_message(self, message_id):
+ """Creates a :class:`PartialMessage` from the message ID.
+
+ This is useful if you want to work with a message and only have its ID without
+ doing an unnecessary API call.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ ------------
+ message_id: :class:`int`
+ The message ID to create a partial message for.
+
+ Returns
+ ---------
+ :class:`PartialMessage`
+ The partial message.
+ """
+
+ from .message import PartialMessage
+ return PartialMessage(channel=self, id=message_id)
+
+class GroupChannel(discord.abc.Messageable, Hashable):
+ """Represents a Discord group channel.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two channels are equal.
+
+ .. describe:: x != y
+
+ Checks if two channels are not equal.
+
+ .. describe:: hash(x)
+
+ Returns the channel's hash.
+
+ .. describe:: str(x)
+
+ Returns a string representation of the channel
+
+ Attributes
+ ----------
+ recipients: List[:class:`User`]
+ The users you are participating with in the group channel.
+ me: :class:`ClientUser`
+ The user presenting yourself.
+ id: :class:`int`
+ The group channel ID.
+ owner: :class:`User`
+ The user that owns the group channel.
+ icon: Optional[:class:`str`]
+ The group channel's icon hash if provided.
+ name: Optional[:class:`str`]
+ The group channel's name if provided.
+ """
+
+ __slots__ = ('id', 'recipients', 'owner', 'icon', 'name', 'me', '_state')
+
+ def __init__(self, *, me, state, data):
+ self._state = state
+ self.id = int(data['id'])
+ self.me = me
+ self._update_group(data)
+
+ def _update_group(self, data):
+ owner_id = utils._get_as_snowflake(data, 'owner_id')
+ self.icon = data.get('icon')
+ self.name = data.get('name')
+
+ try:
+ self.recipients = [self._state.store_user(u) for u in data['recipients']]
+ except KeyError:
+ pass
+
+ if owner_id == self.me.id:
+ self.owner = self.me
+ else:
+ self.owner = utils.find(lambda u: u.id == owner_id, self.recipients)
+
+ async def _get_channel(self):
+ return self
+
+ def __str__(self):
+ if self.name:
+ return self.name
+
+ if len(self.recipients) == 0:
+ return 'Unnamed'
+
+ return ', '.join(map(lambda x: x.name, self.recipients))
+
+ def __repr__(self):
+ return ''.format(self)
+
+ @property
+ def type(self):
+ """:class:`ChannelType`: The channel's Discord type."""
+ return ChannelType.group
+
+ @property
+ def icon_url(self):
+ """:class:`Asset`: Returns the channel's icon asset if available.
+
+ This is equivalent to calling :meth:`icon_url_as` with
+ the default parameters ('webp' format and a size of 1024).
+ """
+ return self.icon_url_as()
+
+ def icon_url_as(self, *, format='webp', size=1024):
+ """Returns an :class:`Asset` for the icon the channel has.
+
+ The format must be one of 'webp', 'jpeg', 'jpg' or 'png'.
+ The size must be a power of 2 between 16 and 4096.
+
+ .. versionadded:: 2.0
+
+ Parameters
+ -----------
+ format: :class:`str`
+ The format to attempt to convert the icon to. Defaults to 'webp'.
+ size: :class:`int`
+ The size of the image to display.
+
+ Raises
+ ------
+ InvalidArgument
+ Bad image format passed to ``format`` or invalid ``size``.
+
+ Returns
+ --------
+ :class:`Asset`
+ The resulting CDN asset.
+ """
+ return Asset._from_icon(self._state, self, 'channel', format=format, size=size)
+
+ @property
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the channel's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ def permissions_for(self, user):
+ """Handles permission resolution for a :class:`User`.
+
+ This function is there for compatibility with other channel types.
+
+ Actual direct messages do not really have the concept of permissions.
+
+ This returns all the Text related permissions set to ``True`` except:
+
+ - :attr:`~Permissions.send_tts_messages`: You cannot send TTS messages in a DM.
+ - :attr:`~Permissions.manage_messages`: You cannot delete others messages in a DM.
+
+ This also checks the kick_members permission if the user is the owner.
+
+ Parameters
+ -----------
+ user: :class:`User`
+ The user to check permissions for.
+
+ Returns
+ --------
+ :class:`Permissions`
+ The resolved permissions for the user.
+ """
+
+ base = Permissions.text()
+ base.read_messages = True
+ base.send_tts_messages = False
+ base.manage_messages = False
+ base.mention_everyone = True
+
+ if user.id == self.owner.id:
+ base.kick_members = True
+
+ return base
+
+ @utils.deprecated()
+ async def add_recipients(self, *recipients):
+ r"""|coro|
+
+ Adds recipients to this group.
+
+ A group can only have a maximum of 10 members.
+ Attempting to add more ends up in an exception. To
+ add a recipient to the group, you must have a relationship
+ with the user of type :attr:`RelationshipType.friend`.
+
+ .. deprecated:: 1.7
+
+ Parameters
+ -----------
+ \*recipients: :class:`User`
+ An argument list of users to add to this group.
+
+ Raises
+ -------
+ HTTPException
+ Adding a recipient to this group failed.
+ """
+
+ # TODO: wait for the corresponding WS event
+
+ req = self._state.http.add_group_recipient
+ for recipient in recipients:
+ await req(self.id, recipient.id)
+
+ @utils.deprecated()
+ async def remove_recipients(self, *recipients):
+ r"""|coro|
+
+ Removes recipients from this group.
+
+ .. deprecated:: 1.7
+
+ Parameters
+ -----------
+ \*recipients: :class:`User`
+ An argument list of users to remove from this group.
+
+ Raises
+ -------
+ HTTPException
+ Removing a recipient from this group failed.
+ """
+
+ # TODO: wait for the corresponding WS event
+
+ req = self._state.http.remove_group_recipient
+ for recipient in recipients:
+ await req(self.id, recipient.id)
+
+ @utils.deprecated()
+ async def edit(self, **fields):
+ """|coro|
+
+ Edits the group.
+
+ .. deprecated:: 1.7
+
+ Parameters
+ -----------
+ name: Optional[:class:`str`]
+ The new name to change the group to.
+ Could be ``None`` to remove the name.
+ icon: Optional[:class:`bytes`]
+ A :term:`py:bytes-like object` representing the new icon.
+ Could be ``None`` to remove the icon.
+
+ Raises
+ -------
+ HTTPException
+ Editing the group failed.
+ """
+
+ try:
+ icon_bytes = fields['icon']
+ except KeyError:
+ pass
+ else:
+ if icon_bytes is not None:
+ fields['icon'] = utils._bytes_to_base64_data(icon_bytes)
+
+ data = await self._state.http.edit_group(self.id, **fields)
+ self._update_group(data)
+
+ async def leave(self):
+ """|coro|
+
+ Leave the group.
+
+ If you are the only one in the group, this deletes it as well.
+
+ Raises
+ -------
+ HTTPException
+ Leaving the group failed.
+ """
+
+ await self._state.http.leave_group(self.id)
+
+def _channel_factory(channel_type):
+ value = try_enum(ChannelType, channel_type)
+ if value is ChannelType.text:
+ return TextChannel, value
+ elif value is ChannelType.voice:
+ return VoiceChannel, value
+ elif value is ChannelType.private:
+ return DMChannel, value
+ elif value is ChannelType.category:
+ return CategoryChannel, value
+ elif value is ChannelType.group:
+ return GroupChannel, value
+ elif value is ChannelType.news:
+ return TextChannel, value
+ elif value is ChannelType.store:
+ return StoreChannel, value
+ elif value is ChannelType.stage_voice:
+ return StageChannel, value
+ else:
+ return None, value
diff --git a/venv/lib64/python3.8/site-packages/discord/client.py b/venv/lib64/python3.8/site-packages/discord/client.py
new file mode 100644
index 0000000..1c35fdd
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/client.py
@@ -0,0 +1,1494 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import asyncio
+import logging
+import signal
+import sys
+import traceback
+
+import aiohttp
+
+from .user import User, Profile
+from .invite import Invite
+from .template import Template
+from .widget import Widget
+from .guild import Guild
+from .channel import _channel_factory
+from .enums import ChannelType
+from .mentions import AllowedMentions
+from .errors import *
+from .enums import Status, VoiceRegion
+from .gateway import *
+from .activity import BaseActivity, create_activity
+from .voice_client import VoiceClient
+from .http import HTTPClient
+from .state import ConnectionState
+from . import utils
+from .object import Object
+from .backoff import ExponentialBackoff
+from .webhook import Webhook
+from .iterators import GuildIterator
+from .appinfo import AppInfo
+
+log = logging.getLogger(__name__)
+
+def _cancel_tasks(loop):
+ try:
+ task_retriever = asyncio.Task.all_tasks
+ except AttributeError:
+ # future proofing for 3.9 I guess
+ task_retriever = asyncio.all_tasks
+
+ tasks = {t for t in task_retriever(loop=loop) if not t.done()}
+
+ if not tasks:
+ return
+
+ log.info('Cleaning up after %d tasks.', len(tasks))
+ for task in tasks:
+ task.cancel()
+
+ loop.run_until_complete(asyncio.gather(*tasks, return_exceptions=True))
+ log.info('All tasks finished cancelling.')
+
+ for task in tasks:
+ if task.cancelled():
+ continue
+ if task.exception() is not None:
+ loop.call_exception_handler({
+ 'message': 'Unhandled exception during Client.run shutdown.',
+ 'exception': task.exception(),
+ 'task': task
+ })
+
+def _cleanup_loop(loop):
+ try:
+ _cancel_tasks(loop)
+ if sys.version_info >= (3, 6):
+ loop.run_until_complete(loop.shutdown_asyncgens())
+ finally:
+ log.info('Closing the event loop.')
+ loop.close()
+
+class _ClientEventTask(asyncio.Task):
+ def __init__(self, original_coro, event_name, coro, *, loop):
+ super().__init__(coro, loop=loop)
+ self.__event_name = event_name
+ self.__original_coro = original_coro
+
+ def __repr__(self):
+ info = [
+ ('state', self._state.lower()),
+ ('event', self.__event_name),
+ ('coro', repr(self.__original_coro)),
+ ]
+ if self._exception is not None:
+ info.append(('exception', repr(self._exception)))
+ return ''.format(' '.join('%s=%s' % t for t in info))
+
+class Client:
+ r"""Represents a client connection that connects to Discord.
+ This class is used to interact with the Discord WebSocket and API.
+
+ A number of options can be passed to the :class:`Client`.
+
+ Parameters
+ -----------
+ max_messages: Optional[:class:`int`]
+ The maximum number of messages to store in the internal message cache.
+ This defaults to ``1000``. Passing in ``None`` disables the message cache.
+
+ .. versionchanged:: 1.3
+ Allow disabling the message cache and change the default size to ``1000``.
+ loop: Optional[:class:`asyncio.AbstractEventLoop`]
+ The :class:`asyncio.AbstractEventLoop` to use for asynchronous operations.
+ Defaults to ``None``, in which case the default event loop is used via
+ :func:`asyncio.get_event_loop()`.
+ connector: :class:`aiohttp.BaseConnector`
+ The connector to use for connection pooling.
+ proxy: Optional[:class:`str`]
+ Proxy URL.
+ proxy_auth: Optional[:class:`aiohttp.BasicAuth`]
+ An object that represents proxy HTTP Basic Authorization.
+ shard_id: Optional[:class:`int`]
+ Integer starting at ``0`` and less than :attr:`.shard_count`.
+ shard_count: Optional[:class:`int`]
+ The total number of shards.
+ intents: :class:`Intents`
+ The intents that you want to enable for the session. This is a way of
+ disabling and enabling certain gateway events from triggering and being sent.
+ If not given, defaults to a regularly constructed :class:`Intents` class.
+
+ .. versionadded:: 1.5
+ member_cache_flags: :class:`MemberCacheFlags`
+ Allows for finer control over how the library caches members.
+ If not given, defaults to cache as much as possible with the
+ currently selected intents.
+
+ .. versionadded:: 1.5
+ fetch_offline_members: :class:`bool`
+ A deprecated alias of ``chunk_guilds_at_startup``.
+ chunk_guilds_at_startup: :class:`bool`
+ Indicates if :func:`.on_ready` should be delayed to chunk all guilds
+ at start-up if necessary. This operation is incredibly slow for large
+ amounts of guilds. The default is ``True`` if :attr:`Intents.members`
+ is ``True``.
+
+ .. versionadded:: 1.5
+ status: Optional[:class:`.Status`]
+ A status to start your presence with upon logging on to Discord.
+ activity: Optional[:class:`.BaseActivity`]
+ An activity to start your presence with upon logging on to Discord.
+ allowed_mentions: Optional[:class:`AllowedMentions`]
+ Control how the client handles mentions by default on every message sent.
+
+ .. versionadded:: 1.4
+ heartbeat_timeout: :class:`float`
+ The maximum numbers of seconds before timing out and restarting the
+ WebSocket in the case of not receiving a HEARTBEAT_ACK. Useful if
+ processing the initial packets take too long to the point of disconnecting
+ you. The default timeout is 60 seconds.
+ guild_ready_timeout: :class:`float`
+ The maximum number of seconds to wait for the GUILD_CREATE stream to end before
+ preparing the member cache and firing READY. The default timeout is 2 seconds.
+
+ .. versionadded:: 1.4
+ guild_subscriptions: :class:`bool`
+ Whether to dispatch presence or typing events. Defaults to ``True``.
+
+ .. versionadded:: 1.3
+
+ .. warning::
+
+ If this is set to ``False`` then the following features will be disabled:
+
+ - No user related updates (:func:`on_user_update` will not dispatch)
+ - All member related events will be disabled.
+ - :func:`on_member_update`
+ - :func:`on_member_join`
+ - :func:`on_member_remove`
+
+ - Typing events will be disabled (:func:`on_typing`).
+ - If ``fetch_offline_members`` is set to ``False`` then the user cache will not exist.
+ This makes it difficult or impossible to do many things, for example:
+
+ - Computing permissions
+ - Querying members in a voice channel via :attr:`VoiceChannel.members` will be empty.
+ - Most forms of receiving :class:`Member` will be
+ receiving :class:`User` instead, except for message events.
+ - :attr:`Guild.owner` will usually resolve to ``None``.
+ - :meth:`Guild.get_member` will usually be unavailable.
+ - Anything that involves using :class:`Member`.
+ - :attr:`users` will not be as populated.
+ - etc.
+
+ In short, this makes it so the only member you can reliably query is the
+ message author. Useful for bots that do not require any state.
+ assume_unsync_clock: :class:`bool`
+ Whether to assume the system clock is unsynced. This applies to the ratelimit handling
+ code. If this is set to ``True``, the default, then the library uses the time to reset
+ a rate limit bucket given by Discord. If this is ``False`` then your system clock is
+ used to calculate how long to sleep for. If this is set to ``False`` it is recommended to
+ sync your system clock to Google's NTP server.
+
+ .. versionadded:: 1.3
+
+ Attributes
+ -----------
+ ws
+ The websocket gateway the client is currently connected to. Could be ``None``.
+ loop: :class:`asyncio.AbstractEventLoop`
+ The event loop that the client uses for HTTP requests and websocket operations.
+ """
+ def __init__(self, *, loop=None, **options):
+ self.ws = None
+ self.loop = asyncio.get_event_loop() if loop is None else loop
+ self._listeners = {}
+ self.shard_id = options.get('shard_id')
+ self.shard_count = options.get('shard_count')
+
+ connector = options.pop('connector', None)
+ proxy = options.pop('proxy', None)
+ proxy_auth = options.pop('proxy_auth', None)
+ unsync_clock = options.pop('assume_unsync_clock', True)
+ self.http = HTTPClient(connector, proxy=proxy, proxy_auth=proxy_auth, unsync_clock=unsync_clock, loop=self.loop)
+
+ self._handlers = {
+ 'ready': self._handle_ready
+ }
+
+ self._hooks = {
+ 'before_identify': self._call_before_identify_hook
+ }
+
+ self._connection = self._get_state(**options)
+ self._connection.shard_count = self.shard_count
+ self._closed = False
+ self._ready = asyncio.Event()
+ self._connection._get_websocket = self._get_websocket
+ self._connection._get_client = lambda: self
+
+ if VoiceClient.warn_nacl:
+ VoiceClient.warn_nacl = False
+ log.warning("PyNaCl is not installed, voice will NOT be supported")
+
+ # internals
+
+ def _get_websocket(self, guild_id=None, *, shard_id=None):
+ return self.ws
+
+ def _get_state(self, **options):
+ return ConnectionState(dispatch=self.dispatch, handlers=self._handlers,
+ hooks=self._hooks, syncer=self._syncer, http=self.http, loop=self.loop, **options)
+
+ async def _syncer(self, guilds):
+ await self.ws.request_sync(guilds)
+
+ def _handle_ready(self):
+ self._ready.set()
+
+ @property
+ def latency(self):
+ """:class:`float`: Measures latency between a HEARTBEAT and a HEARTBEAT_ACK in seconds.
+
+ This could be referred to as the Discord WebSocket protocol latency.
+ """
+ ws = self.ws
+ return float('nan') if not ws else ws.latency
+
+ def is_ws_ratelimited(self):
+ """:class:`bool`: Whether the websocket is currently rate limited.
+
+ This can be useful to know when deciding whether you should query members
+ using HTTP or via the gateway.
+
+ .. versionadded:: 1.6
+ """
+ if self.ws:
+ return self.ws.is_ratelimited()
+ return False
+
+ @property
+ def user(self):
+ """Optional[:class:`.ClientUser`]: Represents the connected client. ``None`` if not logged in."""
+ return self._connection.user
+
+ @property
+ def guilds(self):
+ """List[:class:`.Guild`]: The guilds that the connected client is a member of."""
+ return self._connection.guilds
+
+ @property
+ def emojis(self):
+ """List[:class:`.Emoji`]: The emojis that the connected client has."""
+ return self._connection.emojis
+
+ @property
+ def cached_messages(self):
+ """Sequence[:class:`.Message`]: Read-only list of messages the connected client has cached.
+
+ .. versionadded:: 1.1
+ """
+ return utils.SequenceProxy(self._connection._messages or [])
+
+ @property
+ def private_channels(self):
+ """List[:class:`.abc.PrivateChannel`]: The private channels that the connected client is participating on.
+
+ .. note::
+
+ This returns only up to 128 most recent private channels due to an internal working
+ on how Discord deals with private channels.
+ """
+ return self._connection.private_channels
+
+ @property
+ def voice_clients(self):
+ """List[:class:`.VoiceProtocol`]: Represents a list of voice connections.
+
+ These are usually :class:`.VoiceClient` instances.
+ """
+ return self._connection.voice_clients
+
+ def is_ready(self):
+ """:class:`bool`: Specifies if the client's internal cache is ready for use."""
+ return self._ready.is_set()
+
+ async def _run_event(self, coro, event_name, *args, **kwargs):
+ try:
+ await coro(*args, **kwargs)
+ except asyncio.CancelledError:
+ pass
+ except Exception:
+ try:
+ await self.on_error(event_name, *args, **kwargs)
+ except asyncio.CancelledError:
+ pass
+
+ def _schedule_event(self, coro, event_name, *args, **kwargs):
+ wrapped = self._run_event(coro, event_name, *args, **kwargs)
+ # Schedules the task
+ return _ClientEventTask(original_coro=coro, event_name=event_name, coro=wrapped, loop=self.loop)
+
+ def dispatch(self, event, *args, **kwargs):
+ log.debug('Dispatching event %s', event)
+ method = 'on_' + event
+
+ listeners = self._listeners.get(event)
+ if listeners:
+ removed = []
+ for i, (future, condition) in enumerate(listeners):
+ if future.cancelled():
+ removed.append(i)
+ continue
+
+ try:
+ result = condition(*args)
+ except Exception as exc:
+ future.set_exception(exc)
+ removed.append(i)
+ else:
+ if result:
+ if len(args) == 0:
+ future.set_result(None)
+ elif len(args) == 1:
+ future.set_result(args[0])
+ else:
+ future.set_result(args)
+ removed.append(i)
+
+ if len(removed) == len(listeners):
+ self._listeners.pop(event)
+ else:
+ for idx in reversed(removed):
+ del listeners[idx]
+
+ try:
+ coro = getattr(self, method)
+ except AttributeError:
+ pass
+ else:
+ self._schedule_event(coro, method, *args, **kwargs)
+
+ async def on_error(self, event_method, *args, **kwargs):
+ """|coro|
+
+ The default error handler provided by the client.
+
+ By default this prints to :data:`sys.stderr` however it could be
+ overridden to have a different implementation.
+ Check :func:`~discord.on_error` for more details.
+ """
+ print('Ignoring exception in {}'.format(event_method), file=sys.stderr)
+ traceback.print_exc()
+
+ @utils.deprecated('Guild.chunk')
+ async def request_offline_members(self, *guilds):
+ r"""|coro|
+
+ Requests previously offline members from the guild to be filled up
+ into the :attr:`.Guild.members` cache. This function is usually not
+ called. It should only be used if you have the ``fetch_offline_members``
+ parameter set to ``False``.
+
+ When the client logs on and connects to the websocket, Discord does
+ not provide the library with offline members if the number of members
+ in the guild is larger than 250. You can check if a guild is large
+ if :attr:`.Guild.large` is ``True``.
+
+ .. warning::
+
+ This method is deprecated. Use :meth:`Guild.chunk` instead.
+
+ Parameters
+ -----------
+ \*guilds: :class:`.Guild`
+ An argument list of guilds to request offline members for.
+
+ Raises
+ -------
+ :exc:`.InvalidArgument`
+ If any guild is unavailable in the collection.
+ """
+ if any(g.unavailable for g in guilds):
+ raise InvalidArgument('An unavailable guild was passed.')
+
+ for guild in guilds:
+ await self._connection.chunk_guild(guild)
+
+ # hooks
+
+ async def _call_before_identify_hook(self, shard_id, *, initial=False):
+ # This hook is an internal hook that actually calls the public one.
+ # It allows the library to have its own hook without stepping on the
+ # toes of those who need to override their own hook.
+ await self.before_identify_hook(shard_id, initial=initial)
+
+ async def before_identify_hook(self, shard_id, *, initial=False):
+ """|coro|
+
+ A hook that is called before IDENTIFYing a session. This is useful
+ if you wish to have more control over the synchronization of multiple
+ IDENTIFYing clients.
+
+ The default implementation sleeps for 5 seconds.
+
+ .. versionadded:: 1.4
+
+ Parameters
+ ------------
+ shard_id: :class:`int`
+ The shard ID that requested being IDENTIFY'd
+ initial: :class:`bool`
+ Whether this IDENTIFY is the first initial IDENTIFY.
+ """
+
+ if not initial:
+ await asyncio.sleep(5.0)
+
+ # login state management
+
+ async def login(self, token, *, bot=True):
+ """|coro|
+
+ Logs in the client with the specified credentials.
+
+ This function can be used in two different ways.
+
+ .. warning::
+
+ Logging on with a user token is against the Discord
+ `Terms of Service `_
+ and doing so might potentially get your account banned.
+ Use this at your own risk.
+
+ Parameters
+ -----------
+ token: :class:`str`
+ The authentication token. Do not prefix this token with
+ anything as the library will do it for you.
+ bot: :class:`bool`
+ Keyword argument that specifies if the account logging on is a bot
+ token or not.
+
+ .. deprecated:: 1.7
+
+ Raises
+ ------
+ :exc:`.LoginFailure`
+ The wrong credentials are passed.
+ :exc:`.HTTPException`
+ An unknown HTTP related error occurred,
+ usually when it isn't 200 or the known incorrect credentials
+ passing status code.
+ """
+
+ log.info('logging in using static token')
+ await self.http.static_login(token.strip(), bot=bot)
+ self._connection.is_bot = bot
+
+ @utils.deprecated('Client.close')
+ async def logout(self):
+ """|coro|
+
+ Logs out of Discord and closes all connections.
+
+ .. deprecated:: 1.7
+
+ .. note::
+
+ This is just an alias to :meth:`close`. If you want
+ to do extraneous cleanup when subclassing, it is suggested
+ to override :meth:`close` instead.
+ """
+ await self.close()
+
+ async def connect(self, *, reconnect=True):
+ """|coro|
+
+ Creates a websocket connection and lets the websocket listen
+ to messages from Discord. This is a loop that runs the entire
+ event system and miscellaneous aspects of the library. Control
+ is not resumed until the WebSocket connection is terminated.
+
+ Parameters
+ -----------
+ reconnect: :class:`bool`
+ If we should attempt reconnecting, either due to internet
+ failure or a specific failure on Discord's part. Certain
+ disconnects that lead to bad state will not be handled (such as
+ invalid sharding payloads or bad tokens).
+
+ Raises
+ -------
+ :exc:`.GatewayNotFound`
+ If the gateway to connect to Discord is not found. Usually if this
+ is thrown then there is a Discord API outage.
+ :exc:`.ConnectionClosed`
+ The websocket connection has been terminated.
+ """
+
+ backoff = ExponentialBackoff()
+ ws_params = {
+ 'initial': True,
+ 'shard_id': self.shard_id,
+ }
+ while not self.is_closed():
+ try:
+ coro = DiscordWebSocket.from_client(self, **ws_params)
+ self.ws = await asyncio.wait_for(coro, timeout=60.0)
+ ws_params['initial'] = False
+ while True:
+ await self.ws.poll_event()
+ except ReconnectWebSocket as e:
+ log.info('Got a request to %s the websocket.', e.op)
+ self.dispatch('disconnect')
+ ws_params.update(sequence=self.ws.sequence, resume=e.resume, session=self.ws.session_id)
+ continue
+ except (OSError,
+ HTTPException,
+ GatewayNotFound,
+ ConnectionClosed,
+ aiohttp.ClientError,
+ asyncio.TimeoutError) as exc:
+
+ self.dispatch('disconnect')
+ if not reconnect:
+ await self.close()
+ if isinstance(exc, ConnectionClosed) and exc.code == 1000:
+ # clean close, don't re-raise this
+ return
+ raise
+
+ if self.is_closed():
+ return
+
+ # If we get connection reset by peer then try to RESUME
+ if isinstance(exc, OSError) and exc.errno in (54, 10054):
+ ws_params.update(sequence=self.ws.sequence, initial=False, resume=True, session=self.ws.session_id)
+ continue
+
+ # We should only get this when an unhandled close code happens,
+ # such as a clean disconnect (1000) or a bad state (bad token, no sharding, etc)
+ # sometimes, discord sends us 1000 for unknown reasons so we should reconnect
+ # regardless and rely on is_closed instead
+ if isinstance(exc, ConnectionClosed):
+ if exc.code == 4014:
+ raise PrivilegedIntentsRequired(exc.shard_id) from None
+ if exc.code != 1000:
+ await self.close()
+ raise
+
+ retry = backoff.delay()
+ log.exception("Attempting a reconnect in %.2fs", retry)
+ await asyncio.sleep(retry)
+ # Always try to RESUME the connection
+ # If the connection is not RESUME-able then the gateway will invalidate the session.
+ # This is apparently what the official Discord client does.
+ ws_params.update(sequence=self.ws.sequence, resume=True, session=self.ws.session_id)
+
+ async def close(self):
+ """|coro|
+
+ Closes the connection to Discord.
+ """
+ if self._closed:
+ return
+
+ await self.http.close()
+ self._closed = True
+
+ for voice in self.voice_clients:
+ try:
+ await voice.disconnect()
+ except Exception:
+ # if an error happens during disconnects, disregard it.
+ pass
+
+ if self.ws is not None and self.ws.open:
+ await self.ws.close(code=1000)
+
+ self._ready.clear()
+
+ def clear(self):
+ """Clears the internal state of the bot.
+
+ After this, the bot can be considered "re-opened", i.e. :meth:`is_closed`
+ and :meth:`is_ready` both return ``False`` along with the bot's internal
+ cache cleared.
+ """
+ self._closed = False
+ self._ready.clear()
+ self._connection.clear()
+ self.http.recreate()
+
+ async def start(self, *args, **kwargs):
+ """|coro|
+
+ A shorthand coroutine for :meth:`login` + :meth:`connect`.
+
+ Raises
+ -------
+ TypeError
+ An unexpected keyword argument was received.
+ """
+ bot = kwargs.pop('bot', True)
+ reconnect = kwargs.pop('reconnect', True)
+
+ if kwargs:
+ raise TypeError("unexpected keyword argument(s) %s" % list(kwargs.keys()))
+
+ await self.login(*args, bot=bot)
+ await self.connect(reconnect=reconnect)
+
+ def run(self, *args, **kwargs):
+ """A blocking call that abstracts away the event loop
+ initialisation from you.
+
+ If you want more control over the event loop then this
+ function should not be used. Use :meth:`start` coroutine
+ or :meth:`connect` + :meth:`login`.
+
+ Roughly Equivalent to: ::
+
+ try:
+ loop.run_until_complete(start(*args, **kwargs))
+ except KeyboardInterrupt:
+ loop.run_until_complete(close())
+ # cancel all tasks lingering
+ finally:
+ loop.close()
+
+ .. warning::
+
+ This function must be the last function to call due to the fact that it
+ is blocking. That means that registration of events or anything being
+ called after this function call will not execute until it returns.
+ """
+ loop = self.loop
+
+ try:
+ loop.add_signal_handler(signal.SIGINT, lambda: loop.stop())
+ loop.add_signal_handler(signal.SIGTERM, lambda: loop.stop())
+ except NotImplementedError:
+ pass
+
+ async def runner():
+ try:
+ await self.start(*args, **kwargs)
+ finally:
+ if not self.is_closed():
+ await self.close()
+
+ def stop_loop_on_completion(f):
+ loop.stop()
+
+ future = asyncio.ensure_future(runner(), loop=loop)
+ future.add_done_callback(stop_loop_on_completion)
+ try:
+ loop.run_forever()
+ except KeyboardInterrupt:
+ log.info('Received signal to terminate bot and event loop.')
+ finally:
+ future.remove_done_callback(stop_loop_on_completion)
+ log.info('Cleaning up tasks.')
+ _cleanup_loop(loop)
+
+ if not future.cancelled():
+ try:
+ return future.result()
+ except KeyboardInterrupt:
+ # I am unsure why this gets raised here but suppress it anyway
+ return None
+
+ # properties
+
+ def is_closed(self):
+ """:class:`bool`: Indicates if the websocket connection is closed."""
+ return self._closed
+
+ @property
+ def activity(self):
+ """Optional[:class:`.BaseActivity`]: The activity being used upon
+ logging in.
+ """
+ return create_activity(self._connection._activity)
+
+ @activity.setter
+ def activity(self, value):
+ if value is None:
+ self._connection._activity = None
+ elif isinstance(value, BaseActivity):
+ self._connection._activity = value.to_dict()
+ else:
+ raise TypeError('activity must derive from BaseActivity.')
+
+ @property
+ def allowed_mentions(self):
+ """Optional[:class:`~discord.AllowedMentions`]: The allowed mention configuration.
+
+ .. versionadded:: 1.4
+ """
+ return self._connection.allowed_mentions
+
+ @allowed_mentions.setter
+ def allowed_mentions(self, value):
+ if value is None or isinstance(value, AllowedMentions):
+ self._connection.allowed_mentions = value
+ else:
+ raise TypeError('allowed_mentions must be AllowedMentions not {0.__class__!r}'.format(value))
+
+ @property
+ def intents(self):
+ """:class:`~discord.Intents`: The intents configured for this connection.
+
+ .. versionadded:: 1.5
+ """
+ return self._connection.intents
+
+ # helpers/getters
+
+ @property
+ def users(self):
+ """List[:class:`~discord.User`]: Returns a list of all the users the bot can see."""
+ return list(self._connection._users.values())
+
+ def get_channel(self, id):
+ """Returns a channel with the given ID.
+
+ Parameters
+ -----------
+ id: :class:`int`
+ The ID to search for.
+
+ Returns
+ --------
+ Optional[Union[:class:`.abc.GuildChannel`, :class:`.abc.PrivateChannel`]]
+ The returned channel or ``None`` if not found.
+ """
+ return self._connection.get_channel(id)
+
+ def get_guild(self, id):
+ """Returns a guild with the given ID.
+
+ Parameters
+ -----------
+ id: :class:`int`
+ The ID to search for.
+
+ Returns
+ --------
+ Optional[:class:`.Guild`]
+ The guild or ``None`` if not found.
+ """
+ return self._connection._get_guild(id)
+
+ def get_user(self, id):
+ """Returns a user with the given ID.
+
+ Parameters
+ -----------
+ id: :class:`int`
+ The ID to search for.
+
+ Returns
+ --------
+ Optional[:class:`~discord.User`]
+ The user or ``None`` if not found.
+ """
+ return self._connection.get_user(id)
+
+ def get_emoji(self, id):
+ """Returns an emoji with the given ID.
+
+ Parameters
+ -----------
+ id: :class:`int`
+ The ID to search for.
+
+ Returns
+ --------
+ Optional[:class:`.Emoji`]
+ The custom emoji or ``None`` if not found.
+ """
+ return self._connection.get_emoji(id)
+
+ def get_all_channels(self):
+ """A generator that retrieves every :class:`.abc.GuildChannel` the client can 'access'.
+
+ This is equivalent to: ::
+
+ for guild in client.guilds:
+ for channel in guild.channels:
+ yield channel
+
+ .. note::
+
+ Just because you receive a :class:`.abc.GuildChannel` does not mean that
+ you can communicate in said channel. :meth:`.abc.GuildChannel.permissions_for` should
+ be used for that.
+
+ Yields
+ ------
+ :class:`.abc.GuildChannel`
+ A channel the client can 'access'.
+ """
+
+ for guild in self.guilds:
+ for channel in guild.channels:
+ yield channel
+
+ def get_all_members(self):
+ """Returns a generator with every :class:`.Member` the client can see.
+
+ This is equivalent to: ::
+
+ for guild in client.guilds:
+ for member in guild.members:
+ yield member
+
+ Yields
+ ------
+ :class:`.Member`
+ A member the client can see.
+ """
+ for guild in self.guilds:
+ for member in guild.members:
+ yield member
+
+ # listeners/waiters
+
+ async def wait_until_ready(self):
+ """|coro|
+
+ Waits until the client's internal cache is all ready.
+ """
+ await self._ready.wait()
+
+ def wait_for(self, event, *, check=None, timeout=None):
+ """|coro|
+
+ Waits for a WebSocket event to be dispatched.
+
+ This could be used to wait for a user to reply to a message,
+ or to react to a message, or to edit a message in a self-contained
+ way.
+
+ The ``timeout`` parameter is passed onto :func:`asyncio.wait_for`. By default,
+ it does not timeout. Note that this does propagate the
+ :exc:`asyncio.TimeoutError` for you in case of timeout and is provided for
+ ease of use.
+
+ In case the event returns multiple arguments, a :class:`tuple` containing those
+ arguments is returned instead. Please check the
+ :ref:`documentation ` for a list of events and their
+ parameters.
+
+ This function returns the **first event that meets the requirements**.
+
+ Examples
+ ---------
+
+ Waiting for a user reply: ::
+
+ @client.event
+ async def on_message(message):
+ if message.content.startswith('$greet'):
+ channel = message.channel
+ await channel.send('Say hello!')
+
+ def check(m):
+ return m.content == 'hello' and m.channel == channel
+
+ msg = await client.wait_for('message', check=check)
+ await channel.send('Hello {.author}!'.format(msg))
+
+ Waiting for a thumbs up reaction from the message author: ::
+
+ @client.event
+ async def on_message(message):
+ if message.content.startswith('$thumb'):
+ channel = message.channel
+ await channel.send('Send me that \N{THUMBS UP SIGN} reaction, mate')
+
+ def check(reaction, user):
+ return user == message.author and str(reaction.emoji) == '\N{THUMBS UP SIGN}'
+
+ try:
+ reaction, user = await client.wait_for('reaction_add', timeout=60.0, check=check)
+ except asyncio.TimeoutError:
+ await channel.send('\N{THUMBS DOWN SIGN}')
+ else:
+ await channel.send('\N{THUMBS UP SIGN}')
+
+
+ Parameters
+ ------------
+ event: :class:`str`
+ The event name, similar to the :ref:`event reference `,
+ but without the ``on_`` prefix, to wait for.
+ check: Optional[Callable[..., :class:`bool`]]
+ A predicate to check what to wait for. The arguments must meet the
+ parameters of the event being waited for.
+ timeout: Optional[:class:`float`]
+ The number of seconds to wait before timing out and raising
+ :exc:`asyncio.TimeoutError`.
+
+ Raises
+ -------
+ asyncio.TimeoutError
+ If a timeout is provided and it was reached.
+
+ Returns
+ --------
+ Any
+ Returns no arguments, a single argument, or a :class:`tuple` of multiple
+ arguments that mirrors the parameters passed in the
+ :ref:`event reference `.
+ """
+
+ future = self.loop.create_future()
+ if check is None:
+ def _check(*args):
+ return True
+ check = _check
+
+ ev = event.lower()
+ try:
+ listeners = self._listeners[ev]
+ except KeyError:
+ listeners = []
+ self._listeners[ev] = listeners
+
+ listeners.append((future, check))
+ return asyncio.wait_for(future, timeout)
+
+ # event registration
+
+ def event(self, coro):
+ """A decorator that registers an event to listen to.
+
+ You can find more info about the events on the :ref:`documentation below `.
+
+ The events must be a :ref:`coroutine `, if not, :exc:`TypeError` is raised.
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ @client.event
+ async def on_ready():
+ print('Ready!')
+
+ Raises
+ --------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('event registered must be a coroutine function')
+
+ setattr(self, coro.__name__, coro)
+ log.debug('%s has successfully been registered as an event', coro.__name__)
+ return coro
+
+ async def change_presence(self, *, activity=None, status=None, afk=False):
+ """|coro|
+
+ Changes the client's presence.
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ game = discord.Game("with the API")
+ await client.change_presence(status=discord.Status.idle, activity=game)
+
+ Parameters
+ ----------
+ activity: Optional[:class:`.BaseActivity`]
+ The activity being done. ``None`` if no currently active activity is done.
+ status: Optional[:class:`.Status`]
+ Indicates what status to change to. If ``None``, then
+ :attr:`.Status.online` is used.
+ afk: Optional[:class:`bool`]
+ Indicates if you are going AFK. This allows the discord
+ client to know how to handle push notifications better
+ for you in case you are actually idle and not lying.
+
+ Raises
+ ------
+ :exc:`.InvalidArgument`
+ If the ``activity`` parameter is not the proper type.
+ """
+
+ if status is None:
+ status = 'online'
+ status_enum = Status.online
+ elif status is Status.offline:
+ status = 'invisible'
+ status_enum = Status.offline
+ else:
+ status_enum = status
+ status = str(status)
+
+ await self.ws.change_presence(activity=activity, status=status, afk=afk)
+
+ for guild in self._connection.guilds:
+ me = guild.me
+ if me is None:
+ continue
+
+ if activity is not None:
+ me.activities = (activity,)
+ else:
+ me.activities = ()
+
+ me.status = status_enum
+
+ # Guild stuff
+
+ def fetch_guilds(self, *, limit=100, before=None, after=None):
+ """Retrieves an :class:`.AsyncIterator` that enables receiving your guilds.
+
+ .. note::
+
+ Using this, you will only receive :attr:`.Guild.owner`, :attr:`.Guild.icon`,
+ :attr:`.Guild.id`, and :attr:`.Guild.name` per :class:`.Guild`.
+
+ .. note::
+
+ This method is an API call. For general usage, consider :attr:`guilds` instead.
+
+ Examples
+ ---------
+
+ Usage ::
+
+ async for guild in client.fetch_guilds(limit=150):
+ print(guild.name)
+
+ Flattening into a list ::
+
+ guilds = await client.fetch_guilds(limit=150).flatten()
+ # guilds is now a list of Guild...
+
+ All parameters are optional.
+
+ Parameters
+ -----------
+ limit: Optional[:class:`int`]
+ The number of guilds to retrieve.
+ If ``None``, it retrieves every guild you have access to. Note, however,
+ that this would make it a slow operation.
+ Defaults to ``100``.
+ before: Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`]
+ Retrieves guilds before this date or object.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+ after: Union[:class:`.abc.Snowflake`, :class:`datetime.datetime`]
+ Retrieve guilds after this date or object.
+ If a date is provided it must be a timezone-naive datetime representing UTC time.
+
+ Raises
+ ------
+ :exc:`.HTTPException`
+ Getting the guilds failed.
+
+ Yields
+ --------
+ :class:`.Guild`
+ The guild with the guild data parsed.
+ """
+ return GuildIterator(self, limit=limit, before=before, after=after)
+
+ async def fetch_template(self, code):
+ """|coro|
+
+ Gets a :class:`.Template` from a discord.new URL or code.
+
+ Parameters
+ -----------
+ code: Union[:class:`.Template`, :class:`str`]
+ The Discord Template Code or URL (must be a discord.new URL).
+
+ Raises
+ -------
+ :exc:`.NotFound`
+ The template is invalid.
+ :exc:`.HTTPException`
+ Getting the template failed.
+
+ Returns
+ --------
+ :class:`.Template`
+ The template from the URL/code.
+ """
+ code = utils.resolve_template(code)
+ data = await self.http.get_template(code)
+ return Template(data=data, state=self._connection)
+
+ async def fetch_guild(self, guild_id):
+ """|coro|
+
+ Retrieves a :class:`.Guild` from an ID.
+
+ .. note::
+
+ Using this, you will **not** receive :attr:`.Guild.channels`, :attr:`.Guild.members`,
+ :attr:`.Member.activity` and :attr:`.Member.voice` per :class:`.Member`.
+
+ .. note::
+
+ This method is an API call. For general usage, consider :meth:`get_guild` instead.
+
+ Parameters
+ -----------
+ guild_id: :class:`int`
+ The guild's ID to fetch from.
+
+ Raises
+ ------
+ :exc:`.Forbidden`
+ You do not have access to the guild.
+ :exc:`.HTTPException`
+ Getting the guild failed.
+
+ Returns
+ --------
+ :class:`.Guild`
+ The guild from the ID.
+ """
+ data = await self.http.get_guild(guild_id)
+ return Guild(data=data, state=self._connection)
+
+ async def create_guild(self, name, region=None, icon=None, *, code=None):
+ """|coro|
+
+ Creates a :class:`.Guild`.
+
+ Bot accounts in more than 10 guilds are not allowed to create guilds.
+
+ Parameters
+ ----------
+ name: :class:`str`
+ The name of the guild.
+ region: :class:`.VoiceRegion`
+ The region for the voice communication server.
+ Defaults to :attr:`.VoiceRegion.us_west`.
+ icon: :class:`bytes`
+ The :term:`py:bytes-like object` representing the icon. See :meth:`.ClientUser.edit`
+ for more details on what is expected.
+ code: Optional[:class:`str`]
+ The code for a template to create the guild with.
+
+ .. versionadded:: 1.4
+
+ Raises
+ ------
+ :exc:`.HTTPException`
+ Guild creation failed.
+ :exc:`.InvalidArgument`
+ Invalid icon image format given. Must be PNG or JPG.
+
+ Returns
+ -------
+ :class:`.Guild`
+ The guild created. This is not the same guild that is
+ added to cache.
+ """
+ if icon is not None:
+ icon = utils._bytes_to_base64_data(icon)
+
+ region = region or VoiceRegion.us_west
+ region_value = region.value
+
+ if code:
+ data = await self.http.create_from_template(code, name, region_value, icon)
+ else:
+ data = await self.http.create_guild(name, region_value, icon)
+ return Guild(data=data, state=self._connection)
+
+ # Invite management
+
+ async def fetch_invite(self, url, *, with_counts=True):
+ """|coro|
+
+ Gets an :class:`.Invite` from a discord.gg URL or ID.
+
+ .. note::
+
+ If the invite is for a guild you have not joined, the guild and channel
+ attributes of the returned :class:`.Invite` will be :class:`.PartialInviteGuild` and
+ :class:`.PartialInviteChannel` respectively.
+
+ Parameters
+ -----------
+ url: Union[:class:`.Invite`, :class:`str`]
+ The Discord invite ID or URL (must be a discord.gg URL).
+ with_counts: :class:`bool`
+ Whether to include count information in the invite. This fills the
+ :attr:`.Invite.approximate_member_count` and :attr:`.Invite.approximate_presence_count`
+ fields.
+
+ Raises
+ -------
+ :exc:`.NotFound`
+ The invite has expired or is invalid.
+ :exc:`.HTTPException`
+ Getting the invite failed.
+
+ Returns
+ --------
+ :class:`.Invite`
+ The invite from the URL/ID.
+ """
+
+ invite_id = utils.resolve_invite(url)
+ data = await self.http.get_invite(invite_id, with_counts=with_counts)
+ return Invite.from_incomplete(state=self._connection, data=data)
+
+ async def delete_invite(self, invite):
+ """|coro|
+
+ Revokes an :class:`.Invite`, URL, or ID to an invite.
+
+ You must have the :attr:`~.Permissions.manage_channels` permission in
+ the associated guild to do this.
+
+ Parameters
+ ----------
+ invite: Union[:class:`.Invite`, :class:`str`]
+ The invite to revoke.
+
+ Raises
+ -------
+ :exc:`.Forbidden`
+ You do not have permissions to revoke invites.
+ :exc:`.NotFound`
+ The invite is invalid or expired.
+ :exc:`.HTTPException`
+ Revoking the invite failed.
+ """
+
+ invite_id = utils.resolve_invite(invite)
+ await self.http.delete_invite(invite_id)
+
+ # Miscellaneous stuff
+
+ async def fetch_widget(self, guild_id):
+ """|coro|
+
+ Gets a :class:`.Widget` from a guild ID.
+
+ .. note::
+
+ The guild must have the widget enabled to get this information.
+
+ Parameters
+ -----------
+ guild_id: :class:`int`
+ The ID of the guild.
+
+ Raises
+ -------
+ :exc:`.Forbidden`
+ The widget for this guild is disabled.
+ :exc:`.HTTPException`
+ Retrieving the widget failed.
+
+ Returns
+ --------
+ :class:`.Widget`
+ The guild's widget.
+ """
+ data = await self.http.get_widget(guild_id)
+
+ return Widget(state=self._connection, data=data)
+
+ async def application_info(self):
+ """|coro|
+
+ Retrieves the bot's application information.
+
+ Raises
+ -------
+ :exc:`.HTTPException`
+ Retrieving the information failed somehow.
+
+ Returns
+ --------
+ :class:`.AppInfo`
+ The bot's application information.
+ """
+ data = await self.http.application_info()
+ if 'rpc_origins' not in data:
+ data['rpc_origins'] = None
+ return AppInfo(self._connection, data)
+
+ async def fetch_user(self, user_id):
+ """|coro|
+
+ Retrieves a :class:`~discord.User` based on their ID. This can only
+ be used by bot accounts. You do not have to share any guilds
+ with the user to get this information, however many operations
+ do require that you do.
+
+ .. note::
+
+ This method is an API call. If you have :attr:`Intents.members` and member cache enabled, consider :meth:`get_user` instead.
+
+ Parameters
+ -----------
+ user_id: :class:`int`
+ The user's ID to fetch from.
+
+ Raises
+ -------
+ :exc:`.NotFound`
+ A user with this ID does not exist.
+ :exc:`.HTTPException`
+ Fetching the user failed.
+
+ Returns
+ --------
+ :class:`~discord.User`
+ The user you requested.
+ """
+ data = await self.http.get_user(user_id)
+ return User(state=self._connection, data=data)
+
+ @utils.deprecated()
+ async def fetch_user_profile(self, user_id):
+ """|coro|
+
+ Gets an arbitrary user's profile.
+
+ .. deprecated:: 1.7
+
+ .. note::
+
+ This can only be used by non-bot accounts.
+
+ Parameters
+ ------------
+ user_id: :class:`int`
+ The ID of the user to fetch their profile for.
+
+ Raises
+ -------
+ :exc:`.Forbidden`
+ Not allowed to fetch profiles.
+ :exc:`.HTTPException`
+ Fetching the profile failed.
+
+ Returns
+ --------
+ :class:`.Profile`
+ The profile of the user.
+ """
+
+ state = self._connection
+ data = await self.http.get_user_profile(user_id)
+
+ def transform(d):
+ return state._get_guild(int(d['id']))
+
+ since = data.get('premium_since')
+ mutual_guilds = list(filter(None, map(transform, data.get('mutual_guilds', []))))
+ user = data['user']
+ return Profile(flags=user.get('flags', 0),
+ premium_since=utils.parse_time(since),
+ mutual_guilds=mutual_guilds,
+ user=User(data=user, state=state),
+ connected_accounts=data['connected_accounts'])
+
+ async def fetch_channel(self, channel_id):
+ """|coro|
+
+ Retrieves a :class:`.abc.GuildChannel` or :class:`.abc.PrivateChannel` with the specified ID.
+
+ .. note::
+
+ This method is an API call. For general usage, consider :meth:`get_channel` instead.
+
+ .. versionadded:: 1.2
+
+ Raises
+ -------
+ :exc:`.InvalidData`
+ An unknown channel type was received from Discord.
+ :exc:`.HTTPException`
+ Retrieving the channel failed.
+ :exc:`.NotFound`
+ Invalid Channel ID.
+ :exc:`.Forbidden`
+ You do not have permission to fetch this channel.
+
+ Returns
+ --------
+ Union[:class:`.abc.GuildChannel`, :class:`.abc.PrivateChannel`]
+ The channel from the ID.
+ """
+ data = await self.http.get_channel(channel_id)
+
+ factory, ch_type = _channel_factory(data['type'])
+ if factory is None:
+ raise InvalidData('Unknown channel type {type} for channel ID {id}.'.format_map(data))
+
+ if ch_type in (ChannelType.group, ChannelType.private):
+ channel = factory(me=self.user, data=data, state=self._connection)
+ else:
+ guild_id = int(data['guild_id'])
+ guild = self.get_guild(guild_id) or Object(id=guild_id)
+ channel = factory(guild=guild, state=self._connection, data=data)
+
+ return channel
+
+ async def fetch_webhook(self, webhook_id):
+ """|coro|
+
+ Retrieves a :class:`.Webhook` with the specified ID.
+
+ Raises
+ --------
+ :exc:`.HTTPException`
+ Retrieving the webhook failed.
+ :exc:`.NotFound`
+ Invalid webhook ID.
+ :exc:`.Forbidden`
+ You do not have permission to fetch this webhook.
+
+ Returns
+ ---------
+ :class:`.Webhook`
+ The webhook you requested.
+ """
+ data = await self.http.get_webhook(webhook_id)
+ return Webhook.from_state(data, state=self._connection)
diff --git a/venv/lib64/python3.8/site-packages/discord/colour.py b/venv/lib64/python3.8/site-packages/discord/colour.py
new file mode 100644
index 0000000..fbf9aae
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/colour.py
@@ -0,0 +1,269 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import colorsys
+import random
+
+class Colour:
+ """Represents a Discord role colour. This class is similar
+ to a (red, green, blue) :class:`tuple`.
+
+ There is an alias for this called Color.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two colours are equal.
+
+ .. describe:: x != y
+
+ Checks if two colours are not equal.
+
+ .. describe:: hash(x)
+
+ Return the colour's hash.
+
+ .. describe:: str(x)
+
+ Returns the hex format for the colour.
+
+ Attributes
+ ------------
+ value: :class:`int`
+ The raw integer colour value.
+ """
+
+ __slots__ = ('value',)
+
+ def __init__(self, value):
+ if not isinstance(value, int):
+ raise TypeError('Expected int parameter, received %s instead.' % value.__class__.__name__)
+
+ self.value = value
+
+ def _get_byte(self, byte):
+ return (self.value >> (8 * byte)) & 0xff
+
+ def __eq__(self, other):
+ return isinstance(other, Colour) and self.value == other.value
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __str__(self):
+ return '#{:0>6x}'.format(self.value)
+
+ def __repr__(self):
+ return '' % self.value
+
+ def __hash__(self):
+ return hash(self.value)
+
+ @property
+ def r(self):
+ """:class:`int`: Returns the red component of the colour."""
+ return self._get_byte(2)
+
+ @property
+ def g(self):
+ """:class:`int`: Returns the green component of the colour."""
+ return self._get_byte(1)
+
+ @property
+ def b(self):
+ """:class:`int`: Returns the blue component of the colour."""
+ return self._get_byte(0)
+
+ def to_rgb(self):
+ """Tuple[:class:`int`, :class:`int`, :class:`int`]: Returns an (r, g, b) tuple representing the colour."""
+ return (self.r, self.g, self.b)
+
+ @classmethod
+ def from_rgb(cls, r, g, b):
+ """Constructs a :class:`Colour` from an RGB tuple."""
+ return cls((r << 16) + (g << 8) + b)
+
+ @classmethod
+ def from_hsv(cls, h, s, v):
+ """Constructs a :class:`Colour` from an HSV tuple."""
+ rgb = colorsys.hsv_to_rgb(h, s, v)
+ return cls.from_rgb(*(int(x * 255) for x in rgb))
+
+ @classmethod
+ def default(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0``."""
+ return cls(0)
+
+ @classmethod
+ def random(cls, *, seed=None):
+ """A factory method that returns a :class:`Colour` with a random hue.
+
+ .. note::
+
+ The random algorithm works by choosing a colour with a random hue but
+ with maxed out saturation and value.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ ------------
+ seed: Optional[Union[:class:`int`, :class:`str`, :class:`float`, :class:`bytes`, :class:`bytearray`]]
+ The seed to initialize the RNG with. If ``None`` is passed the default RNG is used.
+
+ .. versionadded:: 1.7
+ """
+ rand = random if seed is None else random.Random(seed)
+ return cls.from_hsv(rand.random(), 1, 1)
+
+ @classmethod
+ def teal(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x1abc9c``."""
+ return cls(0x1abc9c)
+
+ @classmethod
+ def dark_teal(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x11806a``."""
+ return cls(0x11806a)
+
+ @classmethod
+ def green(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x2ecc71``."""
+ return cls(0x2ecc71)
+
+ @classmethod
+ def dark_green(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x1f8b4c``."""
+ return cls(0x1f8b4c)
+
+ @classmethod
+ def blue(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x3498db``."""
+ return cls(0x3498db)
+
+ @classmethod
+ def dark_blue(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x206694``."""
+ return cls(0x206694)
+
+ @classmethod
+ def purple(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x9b59b6``."""
+ return cls(0x9b59b6)
+
+ @classmethod
+ def dark_purple(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x71368a``."""
+ return cls(0x71368a)
+
+ @classmethod
+ def magenta(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xe91e63``."""
+ return cls(0xe91e63)
+
+ @classmethod
+ def dark_magenta(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xad1457``."""
+ return cls(0xad1457)
+
+ @classmethod
+ def gold(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xf1c40f``."""
+ return cls(0xf1c40f)
+
+ @classmethod
+ def dark_gold(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xc27c0e``."""
+ return cls(0xc27c0e)
+
+ @classmethod
+ def orange(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xe67e22``."""
+ return cls(0xe67e22)
+
+ @classmethod
+ def dark_orange(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xa84300``."""
+ return cls(0xa84300)
+
+ @classmethod
+ def red(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0xe74c3c``."""
+ return cls(0xe74c3c)
+
+ @classmethod
+ def dark_red(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x992d22``."""
+ return cls(0x992d22)
+
+ @classmethod
+ def lighter_grey(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x95a5a6``."""
+ return cls(0x95a5a6)
+
+ lighter_gray = lighter_grey
+
+ @classmethod
+ def dark_grey(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x607d8b``."""
+ return cls(0x607d8b)
+
+ dark_gray = dark_grey
+
+ @classmethod
+ def light_grey(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x979c9f``."""
+ return cls(0x979c9f)
+
+ light_gray = light_grey
+
+ @classmethod
+ def darker_grey(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x546e7a``."""
+ return cls(0x546e7a)
+
+ darker_gray = darker_grey
+
+ @classmethod
+ def blurple(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x7289da``."""
+ return cls(0x7289da)
+
+ @classmethod
+ def greyple(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x99aab5``."""
+ return cls(0x99aab5)
+
+ @classmethod
+ def dark_theme(cls):
+ """A factory method that returns a :class:`Colour` with a value of ``0x36393F``.
+ This will appear transparent on Discord's dark theme.
+
+ .. versionadded:: 1.5
+ """
+ return cls(0x36393F)
+
+Color = Colour
diff --git a/venv/lib64/python3.8/site-packages/discord/context_managers.py b/venv/lib64/python3.8/site-packages/discord/context_managers.py
new file mode 100644
index 0000000..e4fde6b
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/context_managers.py
@@ -0,0 +1,67 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import asyncio
+
+def _typing_done_callback(fut):
+ # just retrieve any exception and call it a day
+ try:
+ fut.exception()
+ except (asyncio.CancelledError, Exception):
+ pass
+
+class Typing:
+ def __init__(self, messageable):
+ self.loop = messageable._state.loop
+ self.messageable = messageable
+
+ async def do_typing(self):
+ try:
+ channel = self._channel
+ except AttributeError:
+ channel = await self.messageable._get_channel()
+
+ typing = channel._state.http.send_typing
+
+ while True:
+ await typing(channel.id)
+ await asyncio.sleep(5)
+
+ def __enter__(self):
+ self.task = asyncio.ensure_future(self.do_typing(), loop=self.loop)
+ self.task.add_done_callback(_typing_done_callback)
+ return self
+
+ def __exit__(self, exc_type, exc, tb):
+ self.task.cancel()
+
+ async def __aenter__(self):
+ self._channel = channel = await self.messageable._get_channel()
+ await channel._state.http.send_typing(channel.id)
+ return self.__enter__()
+
+ async def __aexit__(self, exc_type, exc, tb):
+ self.task.cancel()
diff --git a/venv/lib64/python3.8/site-packages/discord/embeds.py b/venv/lib64/python3.8/site-packages/discord/embeds.py
new file mode 100644
index 0000000..cbe1146
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/embeds.py
@@ -0,0 +1,618 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import datetime
+
+from . import utils
+from .colour import Colour
+
+class _EmptyEmbed:
+ def __bool__(self):
+ return False
+
+ def __repr__(self):
+ return 'Embed.Empty'
+
+ def __len__(self):
+ return 0
+
+EmptyEmbed = _EmptyEmbed()
+
+class EmbedProxy:
+ def __init__(self, layer):
+ self.__dict__.update(layer)
+
+ def __len__(self):
+ return len(self.__dict__)
+
+ def __repr__(self):
+ return 'EmbedProxy(%s)' % ', '.join(('%s=%r' % (k, v) for k, v in self.__dict__.items() if not k.startswith('_')))
+
+ def __getattr__(self, attr):
+ return EmptyEmbed
+
+class Embed:
+ """Represents a Discord embed.
+
+ .. container:: operations
+
+ .. describe:: len(x)
+
+ Returns the total size of the embed.
+ Useful for checking if it's within the 6000 character limit.
+
+ Certain properties return an ``EmbedProxy``, a type
+ that acts similar to a regular :class:`dict` except using dotted access,
+ e.g. ``embed.author.icon_url``. If the attribute
+ is invalid or empty, then a special sentinel value is returned,
+ :attr:`Embed.Empty`.
+
+ For ease of use, all parameters that expect a :class:`str` are implicitly
+ casted to :class:`str` for you.
+
+ Attributes
+ -----------
+ title: :class:`str`
+ The title of the embed.
+ This can be set during initialisation.
+ type: :class:`str`
+ The type of embed. Usually "rich".
+ This can be set during initialisation.
+ Possible strings for embed types can be found on discord's
+ `api docs `_
+ description: :class:`str`
+ The description of the embed.
+ This can be set during initialisation.
+ url: :class:`str`
+ The URL of the embed.
+ This can be set during initialisation.
+ timestamp: :class:`datetime.datetime`
+ The timestamp of the embed content. This could be a naive or aware datetime.
+ colour: Union[:class:`Colour`, :class:`int`]
+ The colour code of the embed. Aliased to ``color`` as well.
+ This can be set during initialisation.
+ Empty
+ A special sentinel value used by ``EmbedProxy`` and this class
+ to denote that the value or attribute is empty.
+ """
+
+ __slots__ = ('title', 'url', 'type', '_timestamp', '_colour', '_footer',
+ '_image', '_thumbnail', '_video', '_provider', '_author',
+ '_fields', 'description')
+
+ Empty = EmptyEmbed
+
+ def __init__(self, **kwargs):
+ # swap the colour/color aliases
+ try:
+ colour = kwargs['colour']
+ except KeyError:
+ colour = kwargs.get('color', EmptyEmbed)
+
+ self.colour = colour
+ self.title = kwargs.get('title', EmptyEmbed)
+ self.type = kwargs.get('type', 'rich')
+ self.url = kwargs.get('url', EmptyEmbed)
+ self.description = kwargs.get('description', EmptyEmbed)
+
+ if self.title is not EmptyEmbed:
+ self.title = str(self.title)
+
+ if self.description is not EmptyEmbed:
+ self.description = str(self.description)
+
+ if self.url is not EmptyEmbed:
+ self.url = str(self.url)
+
+ try:
+ timestamp = kwargs['timestamp']
+ except KeyError:
+ pass
+ else:
+ self.timestamp = timestamp
+
+ @classmethod
+ def from_dict(cls, data):
+ """Converts a :class:`dict` to a :class:`Embed` provided it is in the
+ format that Discord expects it to be in.
+
+ You can find out about this format in the `official Discord documentation`__.
+
+ .. _DiscordDocs: https://discord.com/developers/docs/resources/channel#embed-object
+
+ __ DiscordDocs_
+
+ Parameters
+ -----------
+ data: :class:`dict`
+ The dictionary to convert into an embed.
+ """
+ # we are bypassing __init__ here since it doesn't apply here
+ self = cls.__new__(cls)
+
+ # fill in the basic fields
+
+ self.title = data.get('title', EmptyEmbed)
+ self.type = data.get('type', EmptyEmbed)
+ self.description = data.get('description', EmptyEmbed)
+ self.url = data.get('url', EmptyEmbed)
+
+ if self.title is not EmptyEmbed:
+ self.title = str(self.title)
+
+ if self.description is not EmptyEmbed:
+ self.description = str(self.description)
+
+ if self.url is not EmptyEmbed:
+ self.url = str(self.url)
+
+ # try to fill in the more rich fields
+
+ try:
+ self._colour = Colour(value=data['color'])
+ except KeyError:
+ pass
+
+ try:
+ self._timestamp = utils.parse_time(data['timestamp'])
+ except KeyError:
+ pass
+
+ for attr in ('thumbnail', 'video', 'provider', 'author', 'fields', 'image', 'footer'):
+ try:
+ value = data[attr]
+ except KeyError:
+ continue
+ else:
+ setattr(self, '_' + attr, value)
+
+ return self
+
+ def copy(self):
+ """Returns a shallow copy of the embed."""
+ return Embed.from_dict(self.to_dict())
+
+ def __len__(self):
+ total = len(self.title) + len(self.description)
+ for field in getattr(self, '_fields', []):
+ total += len(field['name']) + len(field['value'])
+
+ try:
+ footer = self._footer
+ except AttributeError:
+ pass
+ else:
+ total += len(footer['text'])
+
+ try:
+ author = self._author
+ except AttributeError:
+ pass
+ else:
+ total += len(author['name'])
+
+ return total
+
+ @property
+ def colour(self):
+ return getattr(self, '_colour', EmptyEmbed)
+
+ @colour.setter
+ def colour(self, value):
+ if isinstance(value, (Colour, _EmptyEmbed)):
+ self._colour = value
+ elif isinstance(value, int):
+ self._colour = Colour(value=value)
+ else:
+ raise TypeError('Expected discord.Colour, int, or Embed.Empty but received %s instead.' % value.__class__.__name__)
+
+ color = colour
+
+ @property
+ def timestamp(self):
+ return getattr(self, '_timestamp', EmptyEmbed)
+
+ @timestamp.setter
+ def timestamp(self, value):
+ if isinstance(value, (datetime.datetime, _EmptyEmbed)):
+ self._timestamp = value
+ else:
+ raise TypeError("Expected datetime.datetime or Embed.Empty received %s instead" % value.__class__.__name__)
+
+ @property
+ def footer(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the footer contents.
+
+ See :meth:`set_footer` for possible values you can access.
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_footer', {}))
+
+ def set_footer(self, *, text=EmptyEmbed, icon_url=EmptyEmbed):
+ """Sets the footer for the embed content.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ Parameters
+ -----------
+ text: :class:`str`
+ The footer text.
+ icon_url: :class:`str`
+ The URL of the footer icon. Only HTTP(S) is supported.
+ """
+
+ self._footer = {}
+ if text is not EmptyEmbed:
+ self._footer['text'] = str(text)
+
+ if icon_url is not EmptyEmbed:
+ self._footer['icon_url'] = str(icon_url)
+
+ return self
+
+ @property
+ def image(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the image contents.
+
+ Possible attributes you can access are:
+
+ - ``url``
+ - ``proxy_url``
+ - ``width``
+ - ``height``
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_image', {}))
+
+ def set_image(self, *, url):
+ """Sets the image for the embed content.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ .. versionchanged:: 1.4
+ Passing :attr:`Empty` removes the image.
+
+ Parameters
+ -----------
+ url: :class:`str`
+ The source URL for the image. Only HTTP(S) is supported.
+ """
+
+ if url is EmptyEmbed:
+ try:
+ del self._image
+ except AttributeError:
+ pass
+ else:
+ self._image = {
+ 'url': str(url)
+ }
+
+ return self
+
+ @property
+ def thumbnail(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the thumbnail contents.
+
+ Possible attributes you can access are:
+
+ - ``url``
+ - ``proxy_url``
+ - ``width``
+ - ``height``
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_thumbnail', {}))
+
+ def set_thumbnail(self, *, url):
+ """Sets the thumbnail for the embed content.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ .. versionchanged:: 1.4
+ Passing :attr:`Empty` removes the thumbnail.
+
+ Parameters
+ -----------
+ url: :class:`str`
+ The source URL for the thumbnail. Only HTTP(S) is supported.
+ """
+
+ if url is EmptyEmbed:
+ try:
+ del self._thumbnail
+ except AttributeError:
+ pass
+ else:
+ self._thumbnail = {
+ 'url': str(url)
+ }
+
+ return self
+
+ @property
+ def video(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the video contents.
+
+ Possible attributes include:
+
+ - ``url`` for the video URL.
+ - ``height`` for the video height.
+ - ``width`` for the video width.
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_video', {}))
+
+ @property
+ def provider(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the provider contents.
+
+ The only attributes that might be accessed are ``name`` and ``url``.
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_provider', {}))
+
+ @property
+ def author(self):
+ """Union[:class:`EmbedProxy`, :attr:`Empty`]: Returns an ``EmbedProxy`` denoting the author contents.
+
+ See :meth:`set_author` for possible values you can access.
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return EmbedProxy(getattr(self, '_author', {}))
+
+ def set_author(self, *, name, url=EmptyEmbed, icon_url=EmptyEmbed):
+ """Sets the author for the embed content.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the author.
+ url: :class:`str`
+ The URL for the author.
+ icon_url: :class:`str`
+ The URL of the author icon. Only HTTP(S) is supported.
+ """
+
+ self._author = {
+ 'name': str(name)
+ }
+
+ if url is not EmptyEmbed:
+ self._author['url'] = str(url)
+
+ if icon_url is not EmptyEmbed:
+ self._author['icon_url'] = str(icon_url)
+
+ return self
+
+ def remove_author(self):
+ """Clears embed's author information.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ .. versionadded:: 1.4
+ """
+ try:
+ del self._author
+ except AttributeError:
+ pass
+
+ return self
+
+ @property
+ def fields(self):
+ """List[Union[``EmbedProxy``, :attr:`Empty`]]: Returns a :class:`list` of ``EmbedProxy`` denoting the field contents.
+
+ See :meth:`add_field` for possible values you can access.
+
+ If the attribute has no value then :attr:`Empty` is returned.
+ """
+ return [EmbedProxy(d) for d in getattr(self, '_fields', [])]
+
+ def add_field(self, *, name, value, inline=True):
+ """Adds a field to the embed object.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the field.
+ value: :class:`str`
+ The value of the field.
+ inline: :class:`bool`
+ Whether the field should be displayed inline.
+ """
+
+ field = {
+ 'inline': inline,
+ 'name': str(name),
+ 'value': str(value)
+ }
+
+ try:
+ self._fields.append(field)
+ except AttributeError:
+ self._fields = [field]
+
+ return self
+
+ def insert_field_at(self, index, *, name, value, inline=True):
+ """Inserts a field before a specified index to the embed.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ .. versionadded:: 1.2
+
+ Parameters
+ -----------
+ index: :class:`int`
+ The index of where to insert the field.
+ name: :class:`str`
+ The name of the field.
+ value: :class:`str`
+ The value of the field.
+ inline: :class:`bool`
+ Whether the field should be displayed inline.
+ """
+
+ field = {
+ 'inline': inline,
+ 'name': str(name),
+ 'value': str(value)
+ }
+
+ try:
+ self._fields.insert(index, field)
+ except AttributeError:
+ self._fields = [field]
+
+ return self
+
+ def clear_fields(self):
+ """Removes all fields from this embed."""
+ try:
+ self._fields.clear()
+ except AttributeError:
+ self._fields = []
+
+ def remove_field(self, index):
+ """Removes a field at a specified index.
+
+ If the index is invalid or out of bounds then the error is
+ silently swallowed.
+
+ .. note::
+
+ When deleting a field by index, the index of the other fields
+ shift to fill the gap just like a regular list.
+
+ Parameters
+ -----------
+ index: :class:`int`
+ The index of the field to remove.
+ """
+ try:
+ del self._fields[index]
+ except (AttributeError, IndexError):
+ pass
+
+ def set_field_at(self, index, *, name, value, inline=True):
+ """Modifies a field to the embed object.
+
+ The index must point to a valid pre-existing field.
+
+ This function returns the class instance to allow for fluent-style
+ chaining.
+
+ Parameters
+ -----------
+ index: :class:`int`
+ The index of the field to modify.
+ name: :class:`str`
+ The name of the field.
+ value: :class:`str`
+ The value of the field.
+ inline: :class:`bool`
+ Whether the field should be displayed inline.
+
+ Raises
+ -------
+ IndexError
+ An invalid index was provided.
+ """
+
+ try:
+ field = self._fields[index]
+ except (TypeError, IndexError, AttributeError):
+ raise IndexError('field index out of range')
+
+ field['name'] = str(name)
+ field['value'] = str(value)
+ field['inline'] = inline
+ return self
+
+ def to_dict(self):
+ """Converts this embed object into a dict."""
+
+ # add in the raw data into the dict
+ result = {
+ key[1:]: getattr(self, key)
+ for key in self.__slots__
+ if key[0] == '_' and hasattr(self, key)
+ }
+
+ # deal with basic convenience wrappers
+
+ try:
+ colour = result.pop('colour')
+ except KeyError:
+ pass
+ else:
+ if colour:
+ result['color'] = colour.value
+
+ try:
+ timestamp = result.pop('timestamp')
+ except KeyError:
+ pass
+ else:
+ if timestamp:
+ if timestamp.tzinfo:
+ result['timestamp'] = timestamp.astimezone(tz=datetime.timezone.utc).isoformat()
+ else:
+ result['timestamp'] = timestamp.replace(tzinfo=datetime.timezone.utc).isoformat()
+
+ # add in the non raw attribute ones
+ if self.type:
+ result['type'] = self.type
+
+ if self.description:
+ result['description'] = self.description
+
+ if self.url:
+ result['url'] = self.url
+
+ if self.title:
+ result['title'] = self.title
+
+ return result
diff --git a/venv/lib64/python3.8/site-packages/discord/emoji.py b/venv/lib64/python3.8/site-packages/discord/emoji.py
new file mode 100644
index 0000000..735d508
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/emoji.py
@@ -0,0 +1,254 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+from .asset import Asset
+from . import utils
+from .partial_emoji import _EmojiTag
+from .user import User
+
+class Emoji(_EmojiTag):
+ """Represents a custom emoji.
+
+ Depending on the way this object was created, some of the attributes can
+ have a value of ``None``.
+
+ .. container:: operations
+
+ .. describe:: x == y
+
+ Checks if two emoji are the same.
+
+ .. describe:: x != y
+
+ Checks if two emoji are not the same.
+
+ .. describe:: hash(x)
+
+ Return the emoji's hash.
+
+ .. describe:: iter(x)
+
+ Returns an iterator of ``(field, value)`` pairs. This allows this class
+ to be used as an iterable in list/dict/etc constructions.
+
+ .. describe:: str(x)
+
+ Returns the emoji rendered for discord.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The name of the emoji.
+ id: :class:`int`
+ The emoji's ID.
+ require_colons: :class:`bool`
+ If colons are required to use this emoji in the client (:PJSalt: vs PJSalt).
+ animated: :class:`bool`
+ Whether an emoji is animated or not.
+ managed: :class:`bool`
+ If this emoji is managed by a Twitch integration.
+ guild_id: :class:`int`
+ The guild ID the emoji belongs to.
+ available: :class:`bool`
+ Whether the emoji is available for use.
+ user: Optional[:class:`User`]
+ The user that created the emoji. This can only be retrieved using :meth:`Guild.fetch_emoji` and
+ having the :attr:`~Permissions.manage_emojis` permission.
+ """
+ __slots__ = ('require_colons', 'animated', 'managed', 'id', 'name', '_roles', 'guild_id',
+ '_state', 'user', 'available')
+
+ def __init__(self, *, guild, state, data):
+ self.guild_id = guild.id
+ self._state = state
+ self._from_data(data)
+
+ def _from_data(self, emoji):
+ self.require_colons = emoji['require_colons']
+ self.managed = emoji['managed']
+ self.id = int(emoji['id'])
+ self.name = emoji['name']
+ self.animated = emoji.get('animated', False)
+ self.available = emoji.get('available', True)
+ self._roles = utils.SnowflakeList(map(int, emoji.get('roles', [])))
+ user = emoji.get('user')
+ self.user = User(state=self._state, data=user) if user else None
+
+ def _iterator(self):
+ for attr in self.__slots__:
+ if attr[0] != '_':
+ value = getattr(self, attr, None)
+ if value is not None:
+ yield (attr, value)
+
+ def __iter__(self):
+ return self._iterator()
+
+ def __str__(self):
+ if self.animated:
+ return ''.format(self)
+ return "<:{0.name}:{0.id}>".format(self)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def __eq__(self, other):
+ return isinstance(other, _EmojiTag) and self.id == other.id
+
+ def __ne__(self, other):
+ return not self.__eq__(other)
+
+ def __hash__(self):
+ return self.id >> 22
+
+ @property
+ def created_at(self):
+ """:class:`datetime.datetime`: Returns the emoji's creation time in UTC."""
+ return utils.snowflake_time(self.id)
+
+ @property
+ def url(self):
+ """:class:`Asset`: Returns the asset of the emoji.
+
+ This is equivalent to calling :meth:`url_as` with
+ the default parameters (i.e. png/gif detection).
+ """
+ return self.url_as(format=None)
+
+ @property
+ def roles(self):
+ """List[:class:`Role`]: A :class:`list` of roles that is allowed to use this emoji.
+
+ If roles is empty, the emoji is unrestricted.
+ """
+ guild = self.guild
+ if guild is None:
+ return []
+
+ return [role for role in guild.roles if self._roles.has(role.id)]
+
+ @property
+ def guild(self):
+ """:class:`Guild`: The guild this emoji belongs to."""
+ return self._state._get_guild(self.guild_id)
+
+
+ def url_as(self, *, format=None, static_format="png"):
+ """Returns an :class:`Asset` for the emoji's url.
+
+ The format must be one of 'webp', 'jpeg', 'jpg', 'png' or 'gif'.
+ 'gif' is only valid for animated emojis.
+
+ .. versionadded:: 1.6
+
+ Parameters
+ -----------
+ format: Optional[:class:`str`]
+ The format to attempt to convert the emojis to.
+ If the format is ``None``, then it is automatically
+ detected as either 'gif' or static_format, depending on whether the
+ emoji is animated or not.
+ static_format: Optional[:class:`str`]
+ Format to attempt to convert only non-animated emoji's to.
+ Defaults to 'png'
+
+ Raises
+ -------
+ InvalidArgument
+ Bad image format passed to ``format`` or ``static_format``.
+
+ Returns
+ --------
+ :class:`Asset`
+ The resulting CDN asset.
+ """
+ return Asset._from_emoji(self._state, self, format=format, static_format=static_format)
+
+
+ def is_usable(self):
+ """:class:`bool`: Whether the bot can use this emoji.
+
+ .. versionadded:: 1.3
+ """
+ if not self.available:
+ return False
+ if not self._roles:
+ return True
+ emoji_roles, my_roles = self._roles, self.guild.me._roles
+ return any(my_roles.has(role_id) for role_id in emoji_roles)
+
+ async def delete(self, *, reason=None):
+ """|coro|
+
+ Deletes the custom emoji.
+
+ You must have :attr:`~Permissions.manage_emojis` permission to
+ do this.
+
+ Parameters
+ -----------
+ reason: Optional[:class:`str`]
+ The reason for deleting this emoji. Shows up on the audit log.
+
+ Raises
+ -------
+ Forbidden
+ You are not allowed to delete emojis.
+ HTTPException
+ An error occurred deleting the emoji.
+ """
+
+ await self._state.http.delete_custom_emoji(self.guild.id, self.id, reason=reason)
+
+ async def edit(self, *, name=None, roles=None, reason=None):
+ r"""|coro|
+
+ Edits the custom emoji.
+
+ You must have :attr:`~Permissions.manage_emojis` permission to
+ do this.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The new emoji name.
+ roles: Optional[list[:class:`Role`]]
+ A :class:`list` of :class:`Role`\s that can use this emoji. Leave empty to make it available to everyone.
+ reason: Optional[:class:`str`]
+ The reason for editing this emoji. Shows up on the audit log.
+
+ Raises
+ -------
+ Forbidden
+ You are not allowed to edit emojis.
+ HTTPException
+ An error occurred editing the emoji.
+ """
+
+ name = name or self.name
+ if roles:
+ roles = [role.id for role in roles]
+ await self._state.http.edit_custom_emoji(self.guild.id, self.id, name=name, roles=roles, reason=reason)
diff --git a/venv/lib64/python3.8/site-packages/discord/enums.py b/venv/lib64/python3.8/site-packages/discord/enums.py
new file mode 100644
index 0000000..91592a6
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/enums.py
@@ -0,0 +1,471 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import types
+from collections import namedtuple
+
+__all__ = (
+ 'Enum',
+ 'ChannelType',
+ 'MessageType',
+ 'VoiceRegion',
+ 'SpeakingState',
+ 'VerificationLevel',
+ 'ContentFilter',
+ 'Status',
+ 'DefaultAvatar',
+ 'RelationshipType',
+ 'AuditLogAction',
+ 'AuditLogActionCategory',
+ 'UserFlags',
+ 'ActivityType',
+ 'HypeSquadHouse',
+ 'NotificationLevel',
+ 'PremiumType',
+ 'UserContentFilter',
+ 'FriendFlags',
+ 'TeamMembershipState',
+ 'Theme',
+ 'WebhookType',
+ 'ExpireBehaviour',
+ 'ExpireBehavior',
+ 'StickerType',
+)
+
+def _create_value_cls(name):
+ cls = namedtuple('_EnumValue_' + name, 'name value')
+ cls.__repr__ = lambda self: '<%s.%s: %r>' % (name, self.name, self.value)
+ cls.__str__ = lambda self: '%s.%s' % (name, self.name)
+ return cls
+
+def _is_descriptor(obj):
+ return hasattr(obj, '__get__') or hasattr(obj, '__set__') or hasattr(obj, '__delete__')
+
+class EnumMeta(type):
+ def __new__(cls, name, bases, attrs):
+ value_mapping = {}
+ member_mapping = {}
+ member_names = []
+
+ value_cls = _create_value_cls(name)
+ for key, value in list(attrs.items()):
+ is_descriptor = _is_descriptor(value)
+ if key[0] == '_' and not is_descriptor:
+ continue
+
+ # Special case classmethod to just pass through
+ if isinstance(value, classmethod):
+ continue
+
+ if is_descriptor:
+ setattr(value_cls, key, value)
+ del attrs[key]
+ continue
+
+ try:
+ new_value = value_mapping[value]
+ except KeyError:
+ new_value = value_cls(name=key, value=value)
+ value_mapping[value] = new_value
+ member_names.append(key)
+
+ member_mapping[key] = new_value
+ attrs[key] = new_value
+
+ attrs['_enum_value_map_'] = value_mapping
+ attrs['_enum_member_map_'] = member_mapping
+ attrs['_enum_member_names_'] = member_names
+ actual_cls = super().__new__(cls, name, bases, attrs)
+ value_cls._actual_enum_cls_ = actual_cls
+ return actual_cls
+
+ def __iter__(cls):
+ return (cls._enum_member_map_[name] for name in cls._enum_member_names_)
+
+ def __reversed__(cls):
+ return (cls._enum_member_map_[name] for name in reversed(cls._enum_member_names_))
+
+ def __len__(cls):
+ return len(cls._enum_member_names_)
+
+ def __repr__(cls):
+ return '' % cls.__name__
+
+ @property
+ def __members__(cls):
+ return types.MappingProxyType(cls._enum_member_map_)
+
+ def __call__(cls, value):
+ try:
+ return cls._enum_value_map_[value]
+ except (KeyError, TypeError):
+ raise ValueError("%r is not a valid %s" % (value, cls.__name__))
+
+ def __getitem__(cls, key):
+ return cls._enum_member_map_[key]
+
+ def __setattr__(cls, name, value):
+ raise TypeError('Enums are immutable.')
+
+ def __delattr__(cls, attr):
+ raise TypeError('Enums are immutable')
+
+ def __instancecheck__(self, instance):
+ # isinstance(x, Y)
+ # -> __instancecheck__(Y, x)
+ try:
+ return instance._actual_enum_cls_ is self
+ except AttributeError:
+ return False
+
+class Enum(metaclass=EnumMeta):
+ @classmethod
+ def try_value(cls, value):
+ try:
+ return cls._enum_value_map_[value]
+ except (KeyError, TypeError):
+ return value
+
+
+class ChannelType(Enum):
+ text = 0
+ private = 1
+ voice = 2
+ group = 3
+ category = 4
+ news = 5
+ store = 6
+ stage_voice = 13
+
+ def __str__(self):
+ return self.name
+
+class MessageType(Enum):
+ default = 0
+ recipient_add = 1
+ recipient_remove = 2
+ call = 3
+ channel_name_change = 4
+ channel_icon_change = 5
+ pins_add = 6
+ new_member = 7
+ premium_guild_subscription = 8
+ premium_guild_tier_1 = 9
+ premium_guild_tier_2 = 10
+ premium_guild_tier_3 = 11
+ channel_follow_add = 12
+ guild_stream = 13
+ guild_discovery_disqualified = 14
+ guild_discovery_requalified = 15
+ guild_discovery_grace_period_initial_warning = 16
+ guild_discovery_grace_period_final_warning = 17
+
+class VoiceRegion(Enum):
+ us_west = 'us-west'
+ us_east = 'us-east'
+ us_south = 'us-south'
+ us_central = 'us-central'
+ eu_west = 'eu-west'
+ eu_central = 'eu-central'
+ singapore = 'singapore'
+ london = 'london'
+ sydney = 'sydney'
+ amsterdam = 'amsterdam'
+ frankfurt = 'frankfurt'
+ brazil = 'brazil'
+ hongkong = 'hongkong'
+ russia = 'russia'
+ japan = 'japan'
+ southafrica = 'southafrica'
+ south_korea = 'south-korea'
+ india = 'india'
+ europe = 'europe'
+ dubai = 'dubai'
+ vip_us_east = 'vip-us-east'
+ vip_us_west = 'vip-us-west'
+ vip_amsterdam = 'vip-amsterdam'
+
+ def __str__(self):
+ return self.value
+
+class SpeakingState(Enum):
+ none = 0
+ voice = 1
+ soundshare = 2
+ priority = 4
+
+ def __str__(self):
+ return self.name
+
+ def __int__(self):
+ return self.value
+
+class VerificationLevel(Enum):
+ none = 0
+ low = 1
+ medium = 2
+ high = 3
+ table_flip = 3
+ extreme = 4
+ double_table_flip = 4
+ very_high = 4
+
+ def __str__(self):
+ return self.name
+
+class ContentFilter(Enum):
+ disabled = 0
+ no_role = 1
+ all_members = 2
+
+ def __str__(self):
+ return self.name
+
+class UserContentFilter(Enum):
+ disabled = 0
+ friends = 1
+ all_messages = 2
+
+class FriendFlags(Enum):
+ noone = 0
+ mutual_guilds = 1
+ mutual_friends = 2
+ guild_and_friends = 3
+ everyone = 4
+
+class Theme(Enum):
+ light = 'light'
+ dark = 'dark'
+
+class Status(Enum):
+ online = 'online'
+ offline = 'offline'
+ idle = 'idle'
+ dnd = 'dnd'
+ do_not_disturb = 'dnd'
+ invisible = 'invisible'
+
+ def __str__(self):
+ return self.value
+
+class DefaultAvatar(Enum):
+ blurple = 0
+ grey = 1
+ gray = 1
+ green = 2
+ orange = 3
+ red = 4
+
+ def __str__(self):
+ return self.name
+
+class RelationshipType(Enum):
+ friend = 1
+ blocked = 2
+ incoming_request = 3
+ outgoing_request = 4
+
+class NotificationLevel(Enum):
+ all_messages = 0
+ only_mentions = 1
+
+class AuditLogActionCategory(Enum):
+ create = 1
+ delete = 2
+ update = 3
+
+class AuditLogAction(Enum):
+ guild_update = 1
+ channel_create = 10
+ channel_update = 11
+ channel_delete = 12
+ overwrite_create = 13
+ overwrite_update = 14
+ overwrite_delete = 15
+ kick = 20
+ member_prune = 21
+ ban = 22
+ unban = 23
+ member_update = 24
+ member_role_update = 25
+ member_move = 26
+ member_disconnect = 27
+ bot_add = 28
+ role_create = 30
+ role_update = 31
+ role_delete = 32
+ invite_create = 40
+ invite_update = 41
+ invite_delete = 42
+ webhook_create = 50
+ webhook_update = 51
+ webhook_delete = 52
+ emoji_create = 60
+ emoji_update = 61
+ emoji_delete = 62
+ message_delete = 72
+ message_bulk_delete = 73
+ message_pin = 74
+ message_unpin = 75
+ integration_create = 80
+ integration_update = 81
+ integration_delete = 82
+
+ @property
+ def category(self):
+ lookup = {
+ AuditLogAction.guild_update: AuditLogActionCategory.update,
+ AuditLogAction.channel_create: AuditLogActionCategory.create,
+ AuditLogAction.channel_update: AuditLogActionCategory.update,
+ AuditLogAction.channel_delete: AuditLogActionCategory.delete,
+ AuditLogAction.overwrite_create: AuditLogActionCategory.create,
+ AuditLogAction.overwrite_update: AuditLogActionCategory.update,
+ AuditLogAction.overwrite_delete: AuditLogActionCategory.delete,
+ AuditLogAction.kick: None,
+ AuditLogAction.member_prune: None,
+ AuditLogAction.ban: None,
+ AuditLogAction.unban: None,
+ AuditLogAction.member_update: AuditLogActionCategory.update,
+ AuditLogAction.member_role_update: AuditLogActionCategory.update,
+ AuditLogAction.member_move: None,
+ AuditLogAction.member_disconnect: None,
+ AuditLogAction.bot_add: None,
+ AuditLogAction.role_create: AuditLogActionCategory.create,
+ AuditLogAction.role_update: AuditLogActionCategory.update,
+ AuditLogAction.role_delete: AuditLogActionCategory.delete,
+ AuditLogAction.invite_create: AuditLogActionCategory.create,
+ AuditLogAction.invite_update: AuditLogActionCategory.update,
+ AuditLogAction.invite_delete: AuditLogActionCategory.delete,
+ AuditLogAction.webhook_create: AuditLogActionCategory.create,
+ AuditLogAction.webhook_update: AuditLogActionCategory.update,
+ AuditLogAction.webhook_delete: AuditLogActionCategory.delete,
+ AuditLogAction.emoji_create: AuditLogActionCategory.create,
+ AuditLogAction.emoji_update: AuditLogActionCategory.update,
+ AuditLogAction.emoji_delete: AuditLogActionCategory.delete,
+ AuditLogAction.message_delete: AuditLogActionCategory.delete,
+ AuditLogAction.message_bulk_delete: AuditLogActionCategory.delete,
+ AuditLogAction.message_pin: None,
+ AuditLogAction.message_unpin: None,
+ AuditLogAction.integration_create: AuditLogActionCategory.create,
+ AuditLogAction.integration_update: AuditLogActionCategory.update,
+ AuditLogAction.integration_delete: AuditLogActionCategory.delete,
+ }
+ return lookup[self]
+
+ @property
+ def target_type(self):
+ v = self.value
+ if v == -1:
+ return 'all'
+ elif v < 10:
+ return 'guild'
+ elif v < 20:
+ return 'channel'
+ elif v < 30:
+ return 'user'
+ elif v < 40:
+ return 'role'
+ elif v < 50:
+ return 'invite'
+ elif v < 60:
+ return 'webhook'
+ elif v < 70:
+ return 'emoji'
+ elif v == 73:
+ return 'channel'
+ elif v < 80:
+ return 'message'
+ elif v < 90:
+ return 'integration'
+
+class UserFlags(Enum):
+ staff = 1
+ partner = 2
+ hypesquad = 4
+ bug_hunter = 8
+ mfa_sms = 16
+ premium_promo_dismissed = 32
+ hypesquad_bravery = 64
+ hypesquad_brilliance = 128
+ hypesquad_balance = 256
+ early_supporter = 512
+ team_user = 1024
+ system = 4096
+ has_unread_urgent_messages = 8192
+ bug_hunter_level_2 = 16384
+ verified_bot = 65536
+ verified_bot_developer = 131072
+
+class ActivityType(Enum):
+ unknown = -1
+ playing = 0
+ streaming = 1
+ listening = 2
+ watching = 3
+ custom = 4
+ competing = 5
+
+ def __int__(self):
+ return self.value
+
+class HypeSquadHouse(Enum):
+ bravery = 1
+ brilliance = 2
+ balance = 3
+
+class PremiumType(Enum):
+ nitro_classic = 1
+ nitro = 2
+
+class TeamMembershipState(Enum):
+ invited = 1
+ accepted = 2
+
+class WebhookType(Enum):
+ incoming = 1
+ channel_follower = 2
+
+class ExpireBehaviour(Enum):
+ remove_role = 0
+ kick = 1
+
+ExpireBehavior = ExpireBehaviour
+
+class StickerType(Enum):
+ png = 1
+ apng = 2
+ lottie = 3
+
+def try_enum(cls, val):
+ """A function that tries to turn the value into enum ``cls``.
+
+ If it fails it returns the value instead.
+ """
+
+ try:
+ return cls._enum_value_map_[val]
+ except (KeyError, TypeError, AttributeError):
+ return val
diff --git a/venv/lib64/python3.8/site-packages/discord/errors.py b/venv/lib64/python3.8/site-packages/discord/errors.py
new file mode 100644
index 0000000..7247051
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/errors.py
@@ -0,0 +1,201 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+class DiscordException(Exception):
+ """Base exception class for discord.py
+
+ Ideally speaking, this could be caught to handle any exceptions thrown from this library.
+ """
+ pass
+
+class ClientException(DiscordException):
+ """Exception that's thrown when an operation in the :class:`Client` fails.
+
+ These are usually for exceptions that happened due to user input.
+ """
+ pass
+
+class NoMoreItems(DiscordException):
+ """Exception that is thrown when an async iteration operation has no more
+ items."""
+ pass
+
+class GatewayNotFound(DiscordException):
+ """An exception that is usually thrown when the gateway hub
+ for the :class:`Client` websocket is not found."""
+ def __init__(self):
+ message = 'The gateway to connect to discord was not found.'
+ super(GatewayNotFound, self).__init__(message)
+
+def flatten_error_dict(d, key=''):
+ items = []
+ for k, v in d.items():
+ new_key = key + '.' + k if key else k
+
+ if isinstance(v, dict):
+ try:
+ _errors = v['_errors']
+ except KeyError:
+ items.extend(flatten_error_dict(v, new_key).items())
+ else:
+ items.append((new_key, ' '.join(x.get('message', '') for x in _errors)))
+ else:
+ items.append((new_key, v))
+
+ return dict(items)
+
+class HTTPException(DiscordException):
+ """Exception that's thrown when an HTTP request operation fails.
+
+ Attributes
+ ------------
+ response: :class:`aiohttp.ClientResponse`
+ The response of the failed HTTP request. This is an
+ instance of :class:`aiohttp.ClientResponse`. In some cases
+ this could also be a :class:`requests.Response`.
+
+ text: :class:`str`
+ The text of the error. Could be an empty string.
+ status: :class:`int`
+ The status code of the HTTP request.
+ code: :class:`int`
+ The Discord specific error code for the failure.
+ """
+
+ def __init__(self, response, message):
+ self.response = response
+ self.status = response.status
+ if isinstance(message, dict):
+ self.code = message.get('code', 0)
+ base = message.get('message', '')
+ errors = message.get('errors')
+ if errors:
+ errors = flatten_error_dict(errors)
+ helpful = '\n'.join('In %s: %s' % t for t in errors.items())
+ self.text = base + '\n' + helpful
+ else:
+ self.text = base
+ else:
+ self.text = message
+ self.code = 0
+
+ fmt = '{0.status} {0.reason} (error code: {1})'
+ if len(self.text):
+ fmt += ': {2}'
+
+ super().__init__(fmt.format(self.response, self.code, self.text))
+
+class Forbidden(HTTPException):
+ """Exception that's thrown for when status code 403 occurs.
+
+ Subclass of :exc:`HTTPException`
+ """
+ pass
+
+class NotFound(HTTPException):
+ """Exception that's thrown for when status code 404 occurs.
+
+ Subclass of :exc:`HTTPException`
+ """
+ pass
+
+class DiscordServerError(HTTPException):
+ """Exception that's thrown for when a 500 range status code occurs.
+
+ Subclass of :exc:`HTTPException`.
+
+ .. versionadded:: 1.5
+ """
+ pass
+
+class InvalidData(ClientException):
+ """Exception that's raised when the library encounters unknown
+ or invalid data from Discord.
+ """
+ pass
+
+class InvalidArgument(ClientException):
+ """Exception that's thrown when an argument to a function
+ is invalid some way (e.g. wrong value or wrong type).
+
+ This could be considered the analogous of ``ValueError`` and
+ ``TypeError`` except inherited from :exc:`ClientException` and thus
+ :exc:`DiscordException`.
+ """
+ pass
+
+class LoginFailure(ClientException):
+ """Exception that's thrown when the :meth:`Client.login` function
+ fails to log you in from improper credentials or some other misc.
+ failure.
+ """
+ pass
+
+class ConnectionClosed(ClientException):
+ """Exception that's thrown when the gateway connection is
+ closed for reasons that could not be handled internally.
+
+ Attributes
+ -----------
+ code: :class:`int`
+ The close code of the websocket.
+ reason: :class:`str`
+ The reason provided for the closure.
+ shard_id: Optional[:class:`int`]
+ The shard ID that got closed if applicable.
+ """
+ def __init__(self, socket, *, shard_id, code=None):
+ # This exception is just the same exception except
+ # reconfigured to subclass ClientException for users
+ self.code = code or socket.close_code
+ # aiohttp doesn't seem to consistently provide close reason
+ self.reason = ''
+ self.shard_id = shard_id
+ super().__init__('Shard ID %s WebSocket closed with %s' % (self.shard_id, self.code))
+
+class PrivilegedIntentsRequired(ClientException):
+ """Exception that's thrown when the gateway is requesting privileged intents
+ but they're not ticked in the developer page yet.
+
+ Go to https://discord.com/developers/applications/ and enable the intents
+ that are required. Currently these are as follows:
+
+ - :attr:`Intents.members`
+ - :attr:`Intents.presences`
+
+ Attributes
+ -----------
+ shard_id: Optional[:class:`int`]
+ The shard ID that got closed if applicable.
+ """
+
+ def __init__(self, shard_id):
+ self.shard_id = shard_id
+ msg = 'Shard ID %s is requesting privileged intents that have not been explicitly enabled in the ' \
+ 'developer portal. It is recommended to go to https://discord.com/developers/applications/ ' \
+ 'and explicitly enable the privileged intents within your application\'s page. If this is not ' \
+ 'possible, then consider disabling the privileged intents instead.'
+ super().__init__(msg % shard_id)
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__init__.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/__init__.py
new file mode 100644
index 0000000..6f356c5
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/__init__.py
@@ -0,0 +1,20 @@
+# -*- coding: utf-8 -*-
+
+"""
+discord.ext.commands
+~~~~~~~~~~~~~~~~~~~~~
+
+An extension module to facilitate creation of bot commands.
+
+:copyright: (c) 2015-present Rapptz
+:license: MIT, see LICENSE for more details.
+"""
+
+from .bot import Bot, AutoShardedBot, when_mentioned, when_mentioned_or
+from .context import Context
+from .core import *
+from .errors import *
+from .help import *
+from .converter import *
+from .cooldowns import *
+from .cog import *
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/__init__.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..1ed152d
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/__init__.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/_types.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/_types.cpython-38.pyc
new file mode 100644
index 0000000..4e9fa62
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/_types.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/bot.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/bot.cpython-38.pyc
new file mode 100644
index 0000000..68935a6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/bot.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cog.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cog.cpython-38.pyc
new file mode 100644
index 0000000..3e45740
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cog.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/context.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/context.cpython-38.pyc
new file mode 100644
index 0000000..e37661a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/context.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/converter.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/converter.cpython-38.pyc
new file mode 100644
index 0000000..f4db8c2
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/converter.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-38.pyc
new file mode 100644
index 0000000..0cd4fa1
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/cooldowns.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/core.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/core.cpython-38.pyc
new file mode 100644
index 0000000..c21afd6
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/core.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/errors.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/errors.cpython-38.pyc
new file mode 100644
index 0000000..6164790
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/errors.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/help.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/help.cpython-38.pyc
new file mode 100644
index 0000000..466a56a
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/help.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/view.cpython-38.pyc b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/view.cpython-38.pyc
new file mode 100644
index 0000000..e1cd87b
Binary files /dev/null and b/venv/lib64/python3.8/site-packages/discord/ext/commands/__pycache__/view.cpython-38.pyc differ
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/_types.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/_types.py
new file mode 100644
index 0000000..36d0efc
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/_types.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+# This is merely a tag type to avoid circular import issues.
+# Yes, this is a terrible solution but ultimately it is the only solution.
+class _BaseCommand:
+ __slots__ = ()
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/bot.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/bot.py
new file mode 100644
index 0000000..ee0308e
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/bot.py
@@ -0,0 +1,1061 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import asyncio
+import collections
+import inspect
+import importlib.util
+import sys
+import traceback
+import types
+
+import discord
+
+from .core import GroupMixin
+from .view import StringView
+from .context import Context
+from . import errors
+from .help import HelpCommand, DefaultHelpCommand
+from .cog import Cog
+
+def when_mentioned(bot, msg):
+ """A callable that implements a command prefix equivalent to being mentioned.
+
+ These are meant to be passed into the :attr:`.Bot.command_prefix` attribute.
+ """
+ return [bot.user.mention + ' ', '<@!%s> ' % bot.user.id]
+
+def when_mentioned_or(*prefixes):
+ """A callable that implements when mentioned or other prefixes provided.
+
+ These are meant to be passed into the :attr:`.Bot.command_prefix` attribute.
+
+ Example
+ --------
+
+ .. code-block:: python3
+
+ bot = commands.Bot(command_prefix=commands.when_mentioned_or('!'))
+
+
+ .. note::
+
+ This callable returns another callable, so if this is done inside a custom
+ callable, you must call the returned callable, for example:
+
+ .. code-block:: python3
+
+ async def get_prefix(bot, message):
+ extras = await prefixes_for(message.guild) # returns a list
+ return commands.when_mentioned_or(*extras)(bot, message)
+
+
+ See Also
+ ----------
+ :func:`.when_mentioned`
+ """
+ def inner(bot, msg):
+ r = list(prefixes)
+ r = when_mentioned(bot, msg) + r
+ return r
+
+ return inner
+
+def _is_submodule(parent, child):
+ return parent == child or child.startswith(parent + ".")
+
+class _DefaultRepr:
+ def __repr__(self):
+ return ''
+
+_default = _DefaultRepr()
+
+class BotBase(GroupMixin):
+ def __init__(self, command_prefix, help_command=_default, description=None, **options):
+ super().__init__(**options)
+ self.command_prefix = command_prefix
+ self.extra_events = {}
+ self.__cogs = {}
+ self.__extensions = {}
+ self._checks = []
+ self._check_once = []
+ self._before_invoke = None
+ self._after_invoke = None
+ self._help_command = None
+ self.description = inspect.cleandoc(description) if description else ''
+ self.owner_id = options.get('owner_id')
+ self.owner_ids = options.get('owner_ids', set())
+ self.strip_after_prefix = options.get('strip_after_prefix', False)
+
+ if self.owner_id and self.owner_ids:
+ raise TypeError('Both owner_id and owner_ids are set.')
+
+ if self.owner_ids and not isinstance(self.owner_ids, collections.abc.Collection):
+ raise TypeError('owner_ids must be a collection not {0.__class__!r}'.format(self.owner_ids))
+
+ if options.pop('self_bot', False):
+ self._skip_check = lambda x, y: x != y
+ else:
+ self._skip_check = lambda x, y: x == y
+
+ if help_command is _default:
+ self.help_command = DefaultHelpCommand()
+ else:
+ self.help_command = help_command
+
+ # internal helpers
+
+ def dispatch(self, event_name, *args, **kwargs):
+ super().dispatch(event_name, *args, **kwargs)
+ ev = 'on_' + event_name
+ for event in self.extra_events.get(ev, []):
+ self._schedule_event(event, ev, *args, **kwargs)
+
+ async def close(self):
+ for extension in tuple(self.__extensions):
+ try:
+ self.unload_extension(extension)
+ except Exception:
+ pass
+
+ for cog in tuple(self.__cogs):
+ try:
+ self.remove_cog(cog)
+ except Exception:
+ pass
+
+ await super().close()
+
+ async def on_command_error(self, context, exception):
+ """|coro|
+
+ The default command error handler provided by the bot.
+
+ By default this prints to :data:`sys.stderr` however it could be
+ overridden to have a different implementation.
+
+ This only fires if you do not specify any listeners for command error.
+ """
+ if self.extra_events.get('on_command_error', None):
+ return
+
+ if hasattr(context.command, 'on_error'):
+ return
+
+ cog = context.cog
+ if cog and Cog._get_overridden_method(cog.cog_command_error) is not None:
+ return
+
+ print('Ignoring exception in command {}:'.format(context.command), file=sys.stderr)
+ traceback.print_exception(type(exception), exception, exception.__traceback__, file=sys.stderr)
+
+ # global check registration
+
+ def check(self, func):
+ r"""A decorator that adds a global check to the bot.
+
+ A global check is similar to a :func:`.check` that is applied
+ on a per command basis except it is run before any command checks
+ have been verified and applies to every command the bot has.
+
+ .. note::
+
+ This function can either be a regular function or a coroutine.
+
+ Similar to a command :func:`.check`\, this takes a single parameter
+ of type :class:`.Context` and can only raise exceptions inherited from
+ :exc:`.CommandError`.
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ @bot.check
+ def check_commands(ctx):
+ return ctx.command.qualified_name in allowed_commands
+
+ """
+ self.add_check(func)
+ return func
+
+ def add_check(self, func, *, call_once=False):
+ """Adds a global check to the bot.
+
+ This is the non-decorator interface to :meth:`.check`
+ and :meth:`.check_once`.
+
+ Parameters
+ -----------
+ func
+ The function that was used as a global check.
+ call_once: :class:`bool`
+ If the function should only be called once per
+ :meth:`.Command.invoke` call.
+ """
+
+ if call_once:
+ self._check_once.append(func)
+ else:
+ self._checks.append(func)
+
+ def remove_check(self, func, *, call_once=False):
+ """Removes a global check from the bot.
+
+ This function is idempotent and will not raise an exception
+ if the function is not in the global checks.
+
+ Parameters
+ -----------
+ func
+ The function to remove from the global checks.
+ call_once: :class:`bool`
+ If the function was added with ``call_once=True`` in
+ the :meth:`.Bot.add_check` call or using :meth:`.check_once`.
+ """
+ l = self._check_once if call_once else self._checks
+
+ try:
+ l.remove(func)
+ except ValueError:
+ pass
+
+ def check_once(self, func):
+ r"""A decorator that adds a "call once" global check to the bot.
+
+ Unlike regular global checks, this one is called only once
+ per :meth:`.Command.invoke` call.
+
+ Regular global checks are called whenever a command is called
+ or :meth:`.Command.can_run` is called. This type of check
+ bypasses that and ensures that it's called only once, even inside
+ the default help command.
+
+ .. note::
+
+ When using this function the :class:`.Context` sent to a group subcommand
+ may only parse the parent command and not the subcommands due to it
+ being invoked once per :meth:`.Bot.invoke` call.
+
+ .. note::
+
+ This function can either be a regular function or a coroutine.
+
+ Similar to a command :func:`.check`\, this takes a single parameter
+ of type :class:`.Context` and can only raise exceptions inherited from
+ :exc:`.CommandError`.
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ @bot.check_once
+ def whitelist(ctx):
+ return ctx.message.author.id in my_whitelist
+
+ """
+ self.add_check(func, call_once=True)
+ return func
+
+ async def can_run(self, ctx, *, call_once=False):
+ data = self._check_once if call_once else self._checks
+
+ if len(data) == 0:
+ return True
+
+ return await discord.utils.async_all(f(ctx) for f in data)
+
+ async def is_owner(self, user):
+ """|coro|
+
+ Checks if a :class:`~discord.User` or :class:`~discord.Member` is the owner of
+ this bot.
+
+ If an :attr:`owner_id` is not set, it is fetched automatically
+ through the use of :meth:`~.Bot.application_info`.
+
+ .. versionchanged:: 1.3
+ The function also checks if the application is team-owned if
+ :attr:`owner_ids` is not set.
+
+ Parameters
+ -----------
+ user: :class:`.abc.User`
+ The user to check for.
+
+ Returns
+ --------
+ :class:`bool`
+ Whether the user is the owner.
+ """
+
+ if self.owner_id:
+ return user.id == self.owner_id
+ elif self.owner_ids:
+ return user.id in self.owner_ids
+ else:
+ app = await self.application_info()
+ if app.team:
+ self.owner_ids = ids = {m.id for m in app.team.members}
+ return user.id in ids
+ else:
+ self.owner_id = owner_id = app.owner.id
+ return user.id == owner_id
+
+ def before_invoke(self, coro):
+ """A decorator that registers a coroutine as a pre-invoke hook.
+
+ A pre-invoke hook is called directly before the command is
+ called. This makes it a useful function to set up database
+ connections or any type of set up required.
+
+ This pre-invoke hook takes a sole parameter, a :class:`.Context`.
+
+ .. note::
+
+ The :meth:`~.Bot.before_invoke` and :meth:`~.Bot.after_invoke` hooks are
+ only called if all checks and argument parsing procedures pass
+ without error. If any check or argument parsing procedures fail
+ then the hooks are not called.
+
+ Parameters
+ -----------
+ coro: :ref:`coroutine `
+ The coroutine to register as the pre-invoke hook.
+
+ Raises
+ -------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('The pre-invoke hook must be a coroutine.')
+
+ self._before_invoke = coro
+ return coro
+
+ def after_invoke(self, coro):
+ r"""A decorator that registers a coroutine as a post-invoke hook.
+
+ A post-invoke hook is called directly after the command is
+ called. This makes it a useful function to clean-up database
+ connections or any type of clean up required.
+
+ This post-invoke hook takes a sole parameter, a :class:`.Context`.
+
+ .. note::
+
+ Similar to :meth:`~.Bot.before_invoke`\, this is not called unless
+ checks and argument parsing procedures succeed. This hook is,
+ however, **always** called regardless of the internal command
+ callback raising an error (i.e. :exc:`.CommandInvokeError`\).
+ This makes it ideal for clean-up scenarios.
+
+ Parameters
+ -----------
+ coro: :ref:`coroutine `
+ The coroutine to register as the post-invoke hook.
+
+ Raises
+ -------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('The post-invoke hook must be a coroutine.')
+
+ self._after_invoke = coro
+ return coro
+
+ # listener registration
+
+ def add_listener(self, func, name=None):
+ """The non decorator alternative to :meth:`.listen`.
+
+ Parameters
+ -----------
+ func: :ref:`coroutine `
+ The function to call.
+ name: Optional[:class:`str`]
+ The name of the event to listen for. Defaults to ``func.__name__``.
+
+ Example
+ --------
+
+ .. code-block:: python3
+
+ async def on_ready(): pass
+ async def my_message(message): pass
+
+ bot.add_listener(on_ready)
+ bot.add_listener(my_message, 'on_message')
+
+ """
+ name = func.__name__ if name is None else name
+
+ if not asyncio.iscoroutinefunction(func):
+ raise TypeError('Listeners must be coroutines')
+
+ if name in self.extra_events:
+ self.extra_events[name].append(func)
+ else:
+ self.extra_events[name] = [func]
+
+ def remove_listener(self, func, name=None):
+ """Removes a listener from the pool of listeners.
+
+ Parameters
+ -----------
+ func
+ The function that was used as a listener to remove.
+ name: :class:`str`
+ The name of the event we want to remove. Defaults to
+ ``func.__name__``.
+ """
+
+ name = func.__name__ if name is None else name
+
+ if name in self.extra_events:
+ try:
+ self.extra_events[name].remove(func)
+ except ValueError:
+ pass
+
+ def listen(self, name=None):
+ """A decorator that registers another function as an external
+ event listener. Basically this allows you to listen to multiple
+ events from different places e.g. such as :func:`.on_ready`
+
+ The functions being listened to must be a :ref:`coroutine `.
+
+ Example
+ --------
+
+ .. code-block:: python3
+
+ @bot.listen()
+ async def on_message(message):
+ print('one')
+
+ # in some other file...
+
+ @bot.listen('on_message')
+ async def my_message(message):
+ print('two')
+
+ Would print one and two in an unspecified order.
+
+ Raises
+ -------
+ TypeError
+ The function being listened to is not a coroutine.
+ """
+
+ def decorator(func):
+ self.add_listener(func, name)
+ return func
+
+ return decorator
+
+ # cogs
+
+ def add_cog(self, cog):
+ """Adds a "cog" to the bot.
+
+ A cog is a class that has its own event listeners and commands.
+
+ Parameters
+ -----------
+ cog: :class:`.Cog`
+ The cog to register to the bot.
+
+ Raises
+ -------
+ TypeError
+ The cog does not inherit from :class:`.Cog`.
+ CommandError
+ An error happened during loading.
+ """
+
+ if not isinstance(cog, Cog):
+ raise TypeError('cogs must derive from Cog')
+
+ cog = cog._inject(self)
+ self.__cogs[cog.__cog_name__] = cog
+
+ def get_cog(self, name):
+ """Gets the cog instance requested.
+
+ If the cog is not found, ``None`` is returned instead.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the cog you are requesting.
+ This is equivalent to the name passed via keyword
+ argument in class creation or the class name if unspecified.
+
+ Returns
+ --------
+ Optional[:class:`Cog`]
+ The cog that was requested. If not found, returns ``None``.
+ """
+ return self.__cogs.get(name)
+
+ def remove_cog(self, name):
+ """Removes a cog from the bot.
+
+ All registered commands and event listeners that the
+ cog has registered will be removed as well.
+
+ If no cog is found then this method has no effect.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the cog to remove.
+ """
+
+ cog = self.__cogs.pop(name, None)
+ if cog is None:
+ return
+
+ help_command = self._help_command
+ if help_command and help_command.cog is cog:
+ help_command.cog = None
+ cog._eject(self)
+
+ @property
+ def cogs(self):
+ """Mapping[:class:`str`, :class:`Cog`]: A read-only mapping of cog name to cog."""
+ return types.MappingProxyType(self.__cogs)
+
+ # extensions
+
+ def _remove_module_references(self, name):
+ # find all references to the module
+ # remove the cogs registered from the module
+ for cogname, cog in self.__cogs.copy().items():
+ if _is_submodule(name, cog.__module__):
+ self.remove_cog(cogname)
+
+ # remove all the commands from the module
+ for cmd in self.all_commands.copy().values():
+ if cmd.module is not None and _is_submodule(name, cmd.module):
+ if isinstance(cmd, GroupMixin):
+ cmd.recursively_remove_all_commands()
+ self.remove_command(cmd.name)
+
+ # remove all the listeners from the module
+ for event_list in self.extra_events.copy().values():
+ remove = []
+ for index, event in enumerate(event_list):
+ if event.__module__ is not None and _is_submodule(name, event.__module__):
+ remove.append(index)
+
+ for index in reversed(remove):
+ del event_list[index]
+
+ def _call_module_finalizers(self, lib, key):
+ try:
+ func = getattr(lib, 'teardown')
+ except AttributeError:
+ pass
+ else:
+ try:
+ func(self)
+ except Exception:
+ pass
+ finally:
+ self.__extensions.pop(key, None)
+ sys.modules.pop(key, None)
+ name = lib.__name__
+ for module in list(sys.modules.keys()):
+ if _is_submodule(name, module):
+ del sys.modules[module]
+
+ def _load_from_module_spec(self, spec, key):
+ # precondition: key not in self.__extensions
+ lib = importlib.util.module_from_spec(spec)
+ sys.modules[key] = lib
+ try:
+ spec.loader.exec_module(lib)
+ except Exception as e:
+ del sys.modules[key]
+ raise errors.ExtensionFailed(key, e) from e
+
+ try:
+ setup = getattr(lib, 'setup')
+ except AttributeError:
+ del sys.modules[key]
+ raise errors.NoEntryPointError(key)
+
+ try:
+ setup(self)
+ except Exception as e:
+ del sys.modules[key]
+ self._remove_module_references(lib.__name__)
+ self._call_module_finalizers(lib, key)
+ raise errors.ExtensionFailed(key, e) from e
+ else:
+ self.__extensions[key] = lib
+
+ def _resolve_name(self, name, package):
+ try:
+ return importlib.util.resolve_name(name, package)
+ except ImportError:
+ raise errors.ExtensionNotFound(name)
+
+ def load_extension(self, name, *, package=None):
+ """Loads an extension.
+
+ An extension is a python module that contains commands, cogs, or
+ listeners.
+
+ An extension must have a global function, ``setup`` defined as
+ the entry point on what to do when the extension is loaded. This entry
+ point must have a single argument, the ``bot``.
+
+ Parameters
+ ------------
+ name: :class:`str`
+ The extension name to load. It must be dot separated like
+ regular Python imports if accessing a sub-module. e.g.
+ ``foo.test`` if you want to import ``foo/test.py``.
+ package: Optional[:class:`str`]
+ The package name to resolve relative imports with.
+ This is required when loading an extension using a relative path, e.g ``.foo.test``.
+ Defaults to ``None``.
+
+ .. versionadded:: 1.7
+
+ Raises
+ --------
+ ExtensionNotFound
+ The extension could not be imported.
+ This is also raised if the name of the extension could not
+ be resolved using the provided ``package`` parameter.
+ ExtensionAlreadyLoaded
+ The extension is already loaded.
+ NoEntryPointError
+ The extension does not have a setup function.
+ ExtensionFailed
+ The extension or its setup function had an execution error.
+ """
+
+ name = self._resolve_name(name, package)
+ if name in self.__extensions:
+ raise errors.ExtensionAlreadyLoaded(name)
+
+ spec = importlib.util.find_spec(name)
+ if spec is None:
+ raise errors.ExtensionNotFound(name)
+
+ self._load_from_module_spec(spec, name)
+
+ def unload_extension(self, name, *, package=None):
+ """Unloads an extension.
+
+ When the extension is unloaded, all commands, listeners, and cogs are
+ removed from the bot and the module is un-imported.
+
+ The extension can provide an optional global function, ``teardown``,
+ to do miscellaneous clean-up if necessary. This function takes a single
+ parameter, the ``bot``, similar to ``setup`` from
+ :meth:`~.Bot.load_extension`.
+
+ Parameters
+ ------------
+ name: :class:`str`
+ The extension name to unload. It must be dot separated like
+ regular Python imports if accessing a sub-module. e.g.
+ ``foo.test`` if you want to import ``foo/test.py``.
+ package: Optional[:class:`str`]
+ The package name to resolve relative imports with.
+ This is required when unloading an extension using a relative path, e.g ``.foo.test``.
+ Defaults to ``None``.
+
+ .. versionadded:: 1.7
+
+ Raises
+ -------
+ ExtensionNotFound
+ The name of the extension could not
+ be resolved using the provided ``package`` parameter.
+ ExtensionNotLoaded
+ The extension was not loaded.
+ """
+
+ name = self._resolve_name(name, package)
+ lib = self.__extensions.get(name)
+ if lib is None:
+ raise errors.ExtensionNotLoaded(name)
+
+ self._remove_module_references(lib.__name__)
+ self._call_module_finalizers(lib, name)
+
+ def reload_extension(self, name, *, package=None):
+ """Atomically reloads an extension.
+
+ This replaces the extension with the same extension, only refreshed. This is
+ equivalent to a :meth:`unload_extension` followed by a :meth:`load_extension`
+ except done in an atomic way. That is, if an operation fails mid-reload then
+ the bot will roll-back to the prior working state.
+
+ Parameters
+ ------------
+ name: :class:`str`
+ The extension name to reload. It must be dot separated like
+ regular Python imports if accessing a sub-module. e.g.
+ ``foo.test`` if you want to import ``foo/test.py``.
+ package: Optional[:class:`str`]
+ The package name to resolve relative imports with.
+ This is required when reloading an extension using a relative path, e.g ``.foo.test``.
+ Defaults to ``None``.
+
+ .. versionadded:: 1.7
+
+ Raises
+ -------
+ ExtensionNotLoaded
+ The extension was not loaded.
+ ExtensionNotFound
+ The extension could not be imported.
+ This is also raised if the name of the extension could not
+ be resolved using the provided ``package`` parameter.
+ NoEntryPointError
+ The extension does not have a setup function.
+ ExtensionFailed
+ The extension setup function had an execution error.
+ """
+
+ name = self._resolve_name(name, package)
+ lib = self.__extensions.get(name)
+ if lib is None:
+ raise errors.ExtensionNotLoaded(name)
+
+ # get the previous module states from sys modules
+ modules = {
+ name: module
+ for name, module in sys.modules.items()
+ if _is_submodule(lib.__name__, name)
+ }
+
+ try:
+ # Unload and then load the module...
+ self._remove_module_references(lib.__name__)
+ self._call_module_finalizers(lib, name)
+ self.load_extension(name)
+ except Exception:
+ # if the load failed, the remnants should have been
+ # cleaned from the load_extension function call
+ # so let's load it from our old compiled library.
+ lib.setup(self)
+ self.__extensions[name] = lib
+
+ # revert sys.modules back to normal and raise back to caller
+ sys.modules.update(modules)
+ raise
+
+ @property
+ def extensions(self):
+ """Mapping[:class:`str`, :class:`py:types.ModuleType`]: A read-only mapping of extension name to extension."""
+ return types.MappingProxyType(self.__extensions)
+
+ # help command stuff
+
+ @property
+ def help_command(self):
+ return self._help_command
+
+ @help_command.setter
+ def help_command(self, value):
+ if value is not None:
+ if not isinstance(value, HelpCommand):
+ raise TypeError('help_command must be a subclass of HelpCommand')
+ if self._help_command is not None:
+ self._help_command._remove_from_bot(self)
+ self._help_command = value
+ value._add_to_bot(self)
+ elif self._help_command is not None:
+ self._help_command._remove_from_bot(self)
+ self._help_command = None
+ else:
+ self._help_command = None
+
+ # command processing
+
+ async def get_prefix(self, message):
+ """|coro|
+
+ Retrieves the prefix the bot is listening to
+ with the message as a context.
+
+ Parameters
+ -----------
+ message: :class:`discord.Message`
+ The message context to get the prefix of.
+
+ Returns
+ --------
+ Union[List[:class:`str`], :class:`str`]
+ A list of prefixes or a single prefix that the bot is
+ listening for.
+ """
+ prefix = ret = self.command_prefix
+ if callable(prefix):
+ ret = await discord.utils.maybe_coroutine(prefix, self, message)
+
+ if not isinstance(ret, str):
+ try:
+ ret = list(ret)
+ except TypeError:
+ # It's possible that a generator raised this exception. Don't
+ # replace it with our own error if that's the case.
+ if isinstance(ret, collections.abc.Iterable):
+ raise
+
+ raise TypeError("command_prefix must be plain string, iterable of strings, or callable "
+ "returning either of these, not {}".format(ret.__class__.__name__))
+
+ if not ret:
+ raise ValueError("Iterable command_prefix must contain at least one prefix")
+
+ return ret
+
+ async def get_context(self, message, *, cls=Context):
+ r"""|coro|
+
+ Returns the invocation context from the message.
+
+ This is a more low-level counter-part for :meth:`.process_commands`
+ to allow users more fine grained control over the processing.
+
+ The returned context is not guaranteed to be a valid invocation
+ context, :attr:`.Context.valid` must be checked to make sure it is.
+ If the context is not valid then it is not a valid candidate to be
+ invoked under :meth:`~.Bot.invoke`.
+
+ Parameters
+ -----------
+ message: :class:`discord.Message`
+ The message to get the invocation context from.
+ cls
+ The factory class that will be used to create the context.
+ By default, this is :class:`.Context`. Should a custom
+ class be provided, it must be similar enough to :class:`.Context`\'s
+ interface.
+
+ Returns
+ --------
+ :class:`.Context`
+ The invocation context. The type of this can change via the
+ ``cls`` parameter.
+ """
+
+ view = StringView(message.content)
+ ctx = cls(prefix=None, view=view, bot=self, message=message)
+
+ if self._skip_check(message.author.id, self.user.id):
+ return ctx
+
+ prefix = await self.get_prefix(message)
+ invoked_prefix = prefix
+
+ if isinstance(prefix, str):
+ if not view.skip_string(prefix):
+ return ctx
+ else:
+ try:
+ # if the context class' __init__ consumes something from the view this
+ # will be wrong. That seems unreasonable though.
+ if message.content.startswith(tuple(prefix)):
+ invoked_prefix = discord.utils.find(view.skip_string, prefix)
+ else:
+ return ctx
+
+ except TypeError:
+ if not isinstance(prefix, list):
+ raise TypeError("get_prefix must return either a string or a list of string, "
+ "not {}".format(prefix.__class__.__name__))
+
+ # It's possible a bad command_prefix got us here.
+ for value in prefix:
+ if not isinstance(value, str):
+ raise TypeError("Iterable command_prefix or list returned from get_prefix must "
+ "contain only strings, not {}".format(value.__class__.__name__))
+
+ # Getting here shouldn't happen
+ raise
+
+ if self.strip_after_prefix:
+ view.skip_ws()
+
+ invoker = view.get_word()
+ ctx.invoked_with = invoker
+ ctx.prefix = invoked_prefix
+ ctx.command = self.all_commands.get(invoker)
+ return ctx
+
+ async def invoke(self, ctx):
+ """|coro|
+
+ Invokes the command given under the invocation context and
+ handles all the internal event dispatch mechanisms.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context to invoke.
+ """
+ if ctx.command is not None:
+ self.dispatch('command', ctx)
+ try:
+ if await self.can_run(ctx, call_once=True):
+ await ctx.command.invoke(ctx)
+ else:
+ raise errors.CheckFailure('The global check once functions failed.')
+ except errors.CommandError as exc:
+ await ctx.command.dispatch_error(ctx, exc)
+ else:
+ self.dispatch('command_completion', ctx)
+ elif ctx.invoked_with:
+ exc = errors.CommandNotFound('Command "{}" is not found'.format(ctx.invoked_with))
+ self.dispatch('command_error', ctx, exc)
+
+ async def process_commands(self, message):
+ """|coro|
+
+ This function processes the commands that have been registered
+ to the bot and other groups. Without this coroutine, none of the
+ commands will be triggered.
+
+ By default, this coroutine is called inside the :func:`.on_message`
+ event. If you choose to override the :func:`.on_message` event, then
+ you should invoke this coroutine as well.
+
+ This is built using other low level tools, and is equivalent to a
+ call to :meth:`~.Bot.get_context` followed by a call to :meth:`~.Bot.invoke`.
+
+ This also checks if the message's author is a bot and doesn't
+ call :meth:`~.Bot.get_context` or :meth:`~.Bot.invoke` if so.
+
+ Parameters
+ -----------
+ message: :class:`discord.Message`
+ The message to process commands for.
+ """
+ if message.author.bot:
+ return
+
+ ctx = await self.get_context(message)
+ await self.invoke(ctx)
+
+ async def on_message(self, message):
+ await self.process_commands(message)
+
+class Bot(BotBase, discord.Client):
+ """Represents a discord bot.
+
+ This class is a subclass of :class:`discord.Client` and as a result
+ anything that you can do with a :class:`discord.Client` you can do with
+ this bot.
+
+ This class also subclasses :class:`.GroupMixin` to provide the functionality
+ to manage commands.
+
+ Attributes
+ -----------
+ command_prefix
+ The command prefix is what the message content must contain initially
+ to have a command invoked. This prefix could either be a string to
+ indicate what the prefix should be, or a callable that takes in the bot
+ as its first parameter and :class:`discord.Message` as its second
+ parameter and returns the prefix. This is to facilitate "dynamic"
+ command prefixes. This callable can be either a regular function or
+ a coroutine.
+
+ An empty string as the prefix always matches, enabling prefix-less
+ command invocation. While this may be useful in DMs it should be avoided
+ in servers, as it's likely to cause performance issues and unintended
+ command invocations.
+
+ The command prefix could also be an iterable of strings indicating that
+ multiple checks for the prefix should be used and the first one to
+ match will be the invocation prefix. You can get this prefix via
+ :attr:`.Context.prefix`. To avoid confusion empty iterables are not
+ allowed.
+
+ .. note::
+
+ When passing multiple prefixes be careful to not pass a prefix
+ that matches a longer prefix occurring later in the sequence. For
+ example, if the command prefix is ``('!', '!?')`` the ``'!?'``
+ prefix will never be matched to any message as the previous one
+ matches messages starting with ``!?``. This is especially important
+ when passing an empty string, it should always be last as no prefix
+ after it will be matched.
+ case_insensitive: :class:`bool`
+ Whether the commands should be case insensitive. Defaults to ``False``. This
+ attribute does not carry over to groups. You must set it to every group if
+ you require group commands to be case insensitive as well.
+ description: :class:`str`
+ The content prefixed into the default help message.
+ self_bot: :class:`bool`
+ If ``True``, the bot will only listen to commands invoked by itself rather
+ than ignoring itself. If ``False`` (the default) then the bot will ignore
+ itself. This cannot be changed once initialised.
+ help_command: Optional[:class:`.HelpCommand`]
+ The help command implementation to use. This can be dynamically
+ set at runtime. To remove the help command pass ``None``. For more
+ information on implementing a help command, see :ref:`ext_commands_help_command`.
+ owner_id: Optional[:class:`int`]
+ The user ID that owns the bot. If this is not set and is then queried via
+ :meth:`.is_owner` then it is fetched automatically using
+ :meth:`~.Bot.application_info`.
+ owner_ids: Optional[Collection[:class:`int`]]
+ The user IDs that owns the bot. This is similar to :attr:`owner_id`.
+ If this is not set and the application is team based, then it is
+ fetched automatically using :meth:`~.Bot.application_info`.
+ For performance reasons it is recommended to use a :class:`set`
+ for the collection. You cannot set both ``owner_id`` and ``owner_ids``.
+
+ .. versionadded:: 1.3
+ strip_after_prefix: :class:`bool`
+ Whether to strip whitespace characters after encountering the command
+ prefix. This allows for ``! hello`` and ``!hello`` to both work if
+ the ``command_prefix`` is set to ``!``. Defaults to ``False``.
+
+ .. versionadded:: 1.7
+ """
+ pass
+
+class AutoShardedBot(BotBase, discord.AutoShardedClient):
+ """This is similar to :class:`.Bot` except that it is inherited from
+ :class:`discord.AutoShardedClient` instead.
+ """
+ pass
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/cog.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/cog.py
new file mode 100644
index 0000000..e12b239
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/cog.py
@@ -0,0 +1,451 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import inspect
+import copy
+from ._types import _BaseCommand
+
+__all__ = (
+ 'CogMeta',
+ 'Cog',
+)
+
+class CogMeta(type):
+ """A metaclass for defining a cog.
+
+ Note that you should probably not use this directly. It is exposed
+ purely for documentation purposes along with making custom metaclasses to intermix
+ with other metaclasses such as the :class:`abc.ABCMeta` metaclass.
+
+ For example, to create an abstract cog mixin class, the following would be done.
+
+ .. code-block:: python3
+
+ import abc
+
+ class CogABCMeta(commands.CogMeta, abc.ABCMeta):
+ pass
+
+ class SomeMixin(metaclass=abc.ABCMeta):
+ pass
+
+ class SomeCogMixin(SomeMixin, commands.Cog, metaclass=CogABCMeta):
+ pass
+
+ .. note::
+
+ When passing an attribute of a metaclass that is documented below, note
+ that you must pass it as a keyword-only argument to the class creation
+ like the following example:
+
+ .. code-block:: python3
+
+ class MyCog(commands.Cog, name='My Cog'):
+ pass
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The cog name. By default, it is the name of the class with no modification.
+ description: :class:`str`
+ The cog description. By default, it is the cleaned docstring of the class.
+
+ .. versionadded:: 1.6
+
+ command_attrs: :class:`dict`
+ A list of attributes to apply to every command inside this cog. The dictionary
+ is passed into the :class:`Command` options at ``__init__``.
+ If you specify attributes inside the command attribute in the class, it will
+ override the one specified inside this attribute. For example:
+
+ .. code-block:: python3
+
+ class MyCog(commands.Cog, command_attrs=dict(hidden=True)):
+ @commands.command()
+ async def foo(self, ctx):
+ pass # hidden -> True
+
+ @commands.command(hidden=False)
+ async def bar(self, ctx):
+ pass # hidden -> False
+ """
+
+ def __new__(cls, *args, **kwargs):
+ name, bases, attrs = args
+ attrs['__cog_name__'] = kwargs.pop('name', name)
+ attrs['__cog_settings__'] = kwargs.pop('command_attrs', {})
+
+ description = kwargs.pop('description', None)
+ if description is None:
+ description = inspect.cleandoc(attrs.get('__doc__', ''))
+ attrs['__cog_description__'] = description
+
+ commands = {}
+ listeners = {}
+ no_bot_cog = 'Commands or listeners must not start with cog_ or bot_ (in method {0.__name__}.{1})'
+
+ new_cls = super().__new__(cls, name, bases, attrs, **kwargs)
+ for base in reversed(new_cls.__mro__):
+ for elem, value in base.__dict__.items():
+ if elem in commands:
+ del commands[elem]
+ if elem in listeners:
+ del listeners[elem]
+
+ is_static_method = isinstance(value, staticmethod)
+ if is_static_method:
+ value = value.__func__
+ if isinstance(value, _BaseCommand):
+ if is_static_method:
+ raise TypeError('Command in method {0}.{1!r} must not be staticmethod.'.format(base, elem))
+ if elem.startswith(('cog_', 'bot_')):
+ raise TypeError(no_bot_cog.format(base, elem))
+ commands[elem] = value
+ elif inspect.iscoroutinefunction(value):
+ try:
+ getattr(value, '__cog_listener__')
+ except AttributeError:
+ continue
+ else:
+ if elem.startswith(('cog_', 'bot_')):
+ raise TypeError(no_bot_cog.format(base, elem))
+ listeners[elem] = value
+
+ new_cls.__cog_commands__ = list(commands.values()) # this will be copied in Cog.__new__
+
+ listeners_as_list = []
+ for listener in listeners.values():
+ for listener_name in listener.__cog_listener_names__:
+ # I use __name__ instead of just storing the value so I can inject
+ # the self attribute when the time comes to add them to the bot
+ listeners_as_list.append((listener_name, listener.__name__))
+
+ new_cls.__cog_listeners__ = listeners_as_list
+ return new_cls
+
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args)
+
+ @classmethod
+ def qualified_name(cls):
+ return cls.__cog_name__
+
+def _cog_special_method(func):
+ func.__cog_special_method__ = None
+ return func
+
+class Cog(metaclass=CogMeta):
+ """The base class that all cogs must inherit from.
+
+ A cog is a collection of commands, listeners, and optional state to
+ help group commands together. More information on them can be found on
+ the :ref:`ext_commands_cogs` page.
+
+ When inheriting from this class, the options shown in :class:`CogMeta`
+ are equally valid here.
+ """
+
+ def __new__(cls, *args, **kwargs):
+ # For issue 426, we need to store a copy of the command objects
+ # since we modify them to inject `self` to them.
+ # To do this, we need to interfere with the Cog creation process.
+ self = super().__new__(cls)
+ cmd_attrs = cls.__cog_settings__
+
+ # Either update the command with the cog provided defaults or copy it.
+ self.__cog_commands__ = tuple(c._update_copy(cmd_attrs) for c in cls.__cog_commands__)
+
+ lookup = {
+ cmd.qualified_name: cmd
+ for cmd in self.__cog_commands__
+ }
+
+ # Update the Command instances dynamically as well
+ for command in self.__cog_commands__:
+ setattr(self, command.callback.__name__, command)
+ parent = command.parent
+ if parent is not None:
+ # Get the latest parent reference
+ parent = lookup[parent.qualified_name]
+
+ # Update our parent's reference to our self
+ parent.remove_command(command.name)
+ parent.add_command(command)
+
+ return self
+
+ def get_commands(self):
+ r"""
+ Returns
+ --------
+ List[:class:`.Command`]
+ A :class:`list` of :class:`.Command`\s that are
+ defined inside this cog.
+
+ .. note::
+
+ This does not include subcommands.
+ """
+ return [c for c in self.__cog_commands__ if c.parent is None]
+
+ @property
+ def qualified_name(self):
+ """:class:`str`: Returns the cog's specified name, not the class name."""
+ return self.__cog_name__
+
+ @property
+ def description(self):
+ """:class:`str`: Returns the cog's description, typically the cleaned docstring."""
+ return self.__cog_description__
+
+ @description.setter
+ def description(self, description):
+ self.__cog_description__ = description
+
+ def walk_commands(self):
+ """An iterator that recursively walks through this cog's commands and subcommands.
+
+ Yields
+ ------
+ Union[:class:`.Command`, :class:`.Group`]
+ A command or group from the cog.
+ """
+ from .core import GroupMixin
+ for command in self.__cog_commands__:
+ if command.parent is None:
+ yield command
+ if isinstance(command, GroupMixin):
+ yield from command.walk_commands()
+
+ def get_listeners(self):
+ """Returns a :class:`list` of (name, function) listener pairs that are defined in this cog.
+
+ Returns
+ --------
+ List[Tuple[:class:`str`, :ref:`coroutine `]]
+ The listeners defined in this cog.
+ """
+ return [(name, getattr(self, method_name)) for name, method_name in self.__cog_listeners__]
+
+ @classmethod
+ def _get_overridden_method(cls, method):
+ """Return None if the method is not overridden. Otherwise returns the overridden method."""
+ return getattr(method.__func__, '__cog_special_method__', method)
+
+ @classmethod
+ def listener(cls, name=None):
+ """A decorator that marks a function as a listener.
+
+ This is the cog equivalent of :meth:`.Bot.listen`.
+
+ Parameters
+ ------------
+ name: :class:`str`
+ The name of the event being listened to. If not provided, it
+ defaults to the function's name.
+
+ Raises
+ --------
+ TypeError
+ The function is not a coroutine function or a string was not passed as
+ the name.
+ """
+
+ if name is not None and not isinstance(name, str):
+ raise TypeError('Cog.listener expected str but received {0.__class__.__name__!r} instead.'.format(name))
+
+ def decorator(func):
+ actual = func
+ if isinstance(actual, staticmethod):
+ actual = actual.__func__
+ if not inspect.iscoroutinefunction(actual):
+ raise TypeError('Listener function must be a coroutine function.')
+ actual.__cog_listener__ = True
+ to_assign = name or actual.__name__
+ try:
+ actual.__cog_listener_names__.append(to_assign)
+ except AttributeError:
+ actual.__cog_listener_names__ = [to_assign]
+ # we have to return `func` instead of `actual` because
+ # we need the type to be `staticmethod` for the metaclass
+ # to pick it up but the metaclass unfurls the function and
+ # thus the assignments need to be on the actual function
+ return func
+ return decorator
+
+ def has_error_handler(self):
+ """:class:`bool`: Checks whether the cog has an error handler.
+
+ .. versionadded:: 1.7
+ """
+ return not hasattr(self.cog_command_error.__func__, '__cog_special_method__')
+
+ @_cog_special_method
+ def cog_unload(self):
+ """A special method that is called when the cog gets removed.
+
+ This function **cannot** be a coroutine. It must be a regular
+ function.
+
+ Subclasses must replace this if they want special unloading behaviour.
+ """
+ pass
+
+ @_cog_special_method
+ def bot_check_once(self, ctx):
+ """A special method that registers as a :meth:`.Bot.check_once`
+ check.
+
+ This function **can** be a coroutine and must take a sole parameter,
+ ``ctx``, to represent the :class:`.Context`.
+ """
+ return True
+
+ @_cog_special_method
+ def bot_check(self, ctx):
+ """A special method that registers as a :meth:`.Bot.check`
+ check.
+
+ This function **can** be a coroutine and must take a sole parameter,
+ ``ctx``, to represent the :class:`.Context`.
+ """
+ return True
+
+ @_cog_special_method
+ def cog_check(self, ctx):
+ """A special method that registers as a :func:`commands.check`
+ for every command and subcommand in this cog.
+
+ This function **can** be a coroutine and must take a sole parameter,
+ ``ctx``, to represent the :class:`.Context`.
+ """
+ return True
+
+ @_cog_special_method
+ async def cog_command_error(self, ctx, error):
+ """A special method that is called whenever an error
+ is dispatched inside this cog.
+
+ This is similar to :func:`.on_command_error` except only applying
+ to the commands inside this cog.
+
+ This **must** be a coroutine.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context where the error happened.
+ error: :class:`CommandError`
+ The error that happened.
+ """
+ pass
+
+ @_cog_special_method
+ async def cog_before_invoke(self, ctx):
+ """A special method that acts as a cog local pre-invoke hook.
+
+ This is similar to :meth:`.Command.before_invoke`.
+
+ This **must** be a coroutine.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context.
+ """
+ pass
+
+ @_cog_special_method
+ async def cog_after_invoke(self, ctx):
+ """A special method that acts as a cog local post-invoke hook.
+
+ This is similar to :meth:`.Command.after_invoke`.
+
+ This **must** be a coroutine.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context.
+ """
+ pass
+
+ def _inject(self, bot):
+ cls = self.__class__
+
+ # realistically, the only thing that can cause loading errors
+ # is essentially just the command loading, which raises if there are
+ # duplicates. When this condition is met, we want to undo all what
+ # we've added so far for some form of atomic loading.
+ for index, command in enumerate(self.__cog_commands__):
+ command.cog = self
+ if command.parent is None:
+ try:
+ bot.add_command(command)
+ except Exception as e:
+ # undo our additions
+ for to_undo in self.__cog_commands__[:index]:
+ if to_undo.parent is None:
+ bot.remove_command(to_undo.name)
+ raise e
+
+ # check if we're overriding the default
+ if cls.bot_check is not Cog.bot_check:
+ bot.add_check(self.bot_check)
+
+ if cls.bot_check_once is not Cog.bot_check_once:
+ bot.add_check(self.bot_check_once, call_once=True)
+
+ # while Bot.add_listener can raise if it's not a coroutine,
+ # this precondition is already met by the listener decorator
+ # already, thus this should never raise.
+ # Outside of, memory errors and the like...
+ for name, method_name in self.__cog_listeners__:
+ bot.add_listener(getattr(self, method_name), name)
+
+ return self
+
+ def _eject(self, bot):
+ cls = self.__class__
+
+ try:
+ for command in self.__cog_commands__:
+ if command.parent is None:
+ bot.remove_command(command.name)
+
+ for _, method_name in self.__cog_listeners__:
+ bot.remove_listener(getattr(self, method_name))
+
+ if cls.bot_check is not Cog.bot_check:
+ bot.remove_check(self.bot_check)
+
+ if cls.bot_check_once is not Cog.bot_check_once:
+ bot.remove_check(self.bot_check_once, call_once=True)
+ finally:
+ try:
+ self.cog_unload()
+ except Exception:
+ pass
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/context.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/context.py
new file mode 100644
index 0000000..8df4f73
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/context.py
@@ -0,0 +1,340 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import discord.abc
+import discord.utils
+
+class Context(discord.abc.Messageable):
+ r"""Represents the context in which a command is being invoked under.
+
+ This class contains a lot of meta data to help you understand more about
+ the invocation context. This class is not created manually and is instead
+ passed around to commands as the first parameter.
+
+ This class implements the :class:`~discord.abc.Messageable` ABC.
+
+ Attributes
+ -----------
+ message: :class:`.Message`
+ The message that triggered the command being executed.
+ bot: :class:`.Bot`
+ The bot that contains the command being executed.
+ args: :class:`list`
+ The list of transformed arguments that were passed into the command.
+ If this is accessed during the :func:`on_command_error` event
+ then this list could be incomplete.
+ kwargs: :class:`dict`
+ A dictionary of transformed arguments that were passed into the command.
+ Similar to :attr:`args`\, if this is accessed in the
+ :func:`on_command_error` event then this dict could be incomplete.
+ prefix: :class:`str`
+ The prefix that was used to invoke the command.
+ command: :class:`Command`
+ The command that is being invoked currently.
+ invoked_with: :class:`str`
+ The command name that triggered this invocation. Useful for finding out
+ which alias called the command.
+ invoked_parents: List[:class:`str`]
+ The command names of the parents that triggered this invocation. Useful for
+ finding out which aliases called the command.
+
+ For example in commands ``?a b c test``, the invoked parents are ``['a', 'b', 'c']``.
+
+ .. versionadded:: 1.7
+
+ invoked_subcommand: :class:`Command`
+ The subcommand that was invoked.
+ If no valid subcommand was invoked then this is equal to ``None``.
+ subcommand_passed: Optional[:class:`str`]
+ The string that was attempted to call a subcommand. This does not have
+ to point to a valid registered subcommand and could just point to a
+ nonsense string. If nothing was passed to attempt a call to a
+ subcommand then this is set to ``None``.
+ command_failed: :class:`bool`
+ A boolean that indicates if the command failed to be parsed, checked,
+ or invoked.
+ """
+
+ def __init__(self, **attrs):
+ self.message = attrs.pop('message', None)
+ self.bot = attrs.pop('bot', None)
+ self.args = attrs.pop('args', [])
+ self.kwargs = attrs.pop('kwargs', {})
+ self.prefix = attrs.pop('prefix')
+ self.command = attrs.pop('command', None)
+ self.view = attrs.pop('view', None)
+ self.invoked_with = attrs.pop('invoked_with', None)
+ self.invoked_parents = attrs.pop('invoked_parents', [])
+ self.invoked_subcommand = attrs.pop('invoked_subcommand', None)
+ self.subcommand_passed = attrs.pop('subcommand_passed', None)
+ self.command_failed = attrs.pop('command_failed', False)
+ self._state = self.message._state
+
+ async def invoke(self, *args, **kwargs):
+ r"""|coro|
+
+ Calls a command with the arguments given.
+
+ This is useful if you want to just call the callback that a
+ :class:`.Command` holds internally.
+
+ .. note::
+
+ This does not handle converters, checks, cooldowns, pre-invoke,
+ or after-invoke hooks in any matter. It calls the internal callback
+ directly as-if it was a regular function.
+
+ You must take care in passing the proper arguments when
+ using this function.
+
+ .. warning::
+
+ The first parameter passed **must** be the command being invoked.
+
+ Parameters
+ -----------
+ command: :class:`.Command`
+ The command that is going to be called.
+ \*args
+ The arguments to to use.
+ \*\*kwargs
+ The keyword arguments to use.
+
+ Raises
+ -------
+ TypeError
+ The command argument to invoke is missing.
+ """
+
+ try:
+ command = args[0]
+ except IndexError:
+ raise TypeError('Missing command to invoke.') from None
+
+ arguments = []
+ if command.cog is not None:
+ arguments.append(command.cog)
+
+ arguments.append(self)
+ arguments.extend(args[1:])
+
+ ret = await command.callback(*arguments, **kwargs)
+ return ret
+
+ async def reinvoke(self, *, call_hooks=False, restart=True):
+ """|coro|
+
+ Calls the command again.
+
+ This is similar to :meth:`~.Context.invoke` except that it bypasses
+ checks, cooldowns, and error handlers.
+
+ .. note::
+
+ If you want to bypass :exc:`.UserInputError` derived exceptions,
+ it is recommended to use the regular :meth:`~.Context.invoke`
+ as it will work more naturally. After all, this will end up
+ using the old arguments the user has used and will thus just
+ fail again.
+
+ Parameters
+ ------------
+ call_hooks: :class:`bool`
+ Whether to call the before and after invoke hooks.
+ restart: :class:`bool`
+ Whether to start the call chain from the very beginning
+ or where we left off (i.e. the command that caused the error).
+ The default is to start where we left off.
+
+ Raises
+ -------
+ ValueError
+ The context to reinvoke is not valid.
+ """
+ cmd = self.command
+ view = self.view
+ if cmd is None:
+ raise ValueError('This context is not valid.')
+
+ # some state to revert to when we're done
+ index, previous = view.index, view.previous
+ invoked_with = self.invoked_with
+ invoked_subcommand = self.invoked_subcommand
+ invoked_parents = self.invoked_parents
+ subcommand_passed = self.subcommand_passed
+
+ if restart:
+ to_call = cmd.root_parent or cmd
+ view.index = len(self.prefix)
+ view.previous = 0
+ self.invoked_parents = []
+ self.invoked_with = view.get_word() # advance to get the root command
+ else:
+ to_call = cmd
+
+ try:
+ await to_call.reinvoke(self, call_hooks=call_hooks)
+ finally:
+ self.command = cmd
+ view.index = index
+ view.previous = previous
+ self.invoked_with = invoked_with
+ self.invoked_subcommand = invoked_subcommand
+ self.invoked_parents = invoked_parents
+ self.subcommand_passed = subcommand_passed
+
+ @property
+ def valid(self):
+ """:class:`bool`: Checks if the invocation context is valid to be invoked with."""
+ return self.prefix is not None and self.command is not None
+
+ async def _get_channel(self):
+ return self.channel
+
+ @property
+ def cog(self):
+ """Optional[:class:`.Cog`]: Returns the cog associated with this context's command. None if it does not exist."""
+
+ if self.command is None:
+ return None
+ return self.command.cog
+
+ @discord.utils.cached_property
+ def guild(self):
+ """Optional[:class:`.Guild`]: Returns the guild associated with this context's command. None if not available."""
+ return self.message.guild
+
+ @discord.utils.cached_property
+ def channel(self):
+ """Union[:class:`.abc.Messageable`]: Returns the channel associated with this context's command.
+ Shorthand for :attr:`.Message.channel`.
+ """
+ return self.message.channel
+
+ @discord.utils.cached_property
+ def author(self):
+ """Union[:class:`~discord.User`, :class:`.Member`]:
+ Returns the author associated with this context's command. Shorthand for :attr:`.Message.author`
+ """
+ return self.message.author
+
+ @discord.utils.cached_property
+ def me(self):
+ """Union[:class:`.Member`, :class:`.ClientUser`]:
+ Similar to :attr:`.Guild.me` except it may return the :class:`.ClientUser` in private message contexts.
+ """
+ return self.guild.me if self.guild is not None else self.bot.user
+
+ @property
+ def voice_client(self):
+ r"""Optional[:class:`.VoiceProtocol`]: A shortcut to :attr:`.Guild.voice_client`\, if applicable."""
+ g = self.guild
+ return g.voice_client if g else None
+
+ async def send_help(self, *args):
+ """send_help(entity=)
+
+ |coro|
+
+ Shows the help command for the specified entity if given.
+ The entity can be a command or a cog.
+
+ If no entity is given, then it'll show help for the
+ entire bot.
+
+ If the entity is a string, then it looks up whether it's a
+ :class:`Cog` or a :class:`Command`.
+
+ .. note::
+
+ Due to the way this function works, instead of returning
+ something similar to :meth:`~.commands.HelpCommand.command_not_found`
+ this returns :class:`None` on bad input or no help command.
+
+ Parameters
+ ------------
+ entity: Optional[Union[:class:`Command`, :class:`Cog`, :class:`str`]]
+ The entity to show help for.
+
+ Returns
+ --------
+ Any
+ The result of the help command, if any.
+ """
+ from .core import Group, Command, wrap_callback
+ from .errors import CommandError
+
+ bot = self.bot
+ cmd = bot.help_command
+
+ if cmd is None:
+ return None
+
+ cmd = cmd.copy()
+ cmd.context = self
+ if len(args) == 0:
+ await cmd.prepare_help_command(self, None)
+ mapping = cmd.get_bot_mapping()
+ injected = wrap_callback(cmd.send_bot_help)
+ try:
+ return await injected(mapping)
+ except CommandError as e:
+ await cmd.on_help_command_error(self, e)
+ return None
+
+ entity = args[0]
+ if entity is None:
+ return None
+
+ if isinstance(entity, str):
+ entity = bot.get_cog(entity) or bot.get_command(entity)
+
+ try:
+ entity.qualified_name
+ except AttributeError:
+ # if we're here then it's not a cog, group, or command.
+ return None
+
+ await cmd.prepare_help_command(self, entity.qualified_name)
+
+ try:
+ if hasattr(entity, '__cog_commands__'):
+ injected = wrap_callback(cmd.send_cog_help)
+ return await injected(entity)
+ elif isinstance(entity, Group):
+ injected = wrap_callback(cmd.send_group_help)
+ return await injected(entity)
+ elif isinstance(entity, Command):
+ injected = wrap_callback(cmd.send_command_help)
+ return await injected(entity)
+ else:
+ return None
+ except CommandError as e:
+ await cmd.on_help_command_error(self, e)
+
+ @discord.utils.copy_doc(discord.Message.reply)
+ async def reply(self, content=None, **kwargs):
+ return await self.message.reply(content, **kwargs)
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/converter.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/converter.py
new file mode 100644
index 0000000..fdc7649
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/converter.py
@@ -0,0 +1,852 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import re
+import inspect
+import typing
+
+import discord
+
+from .errors import *
+
+__all__ = (
+ 'Converter',
+ 'MemberConverter',
+ 'UserConverter',
+ 'MessageConverter',
+ 'PartialMessageConverter',
+ 'TextChannelConverter',
+ 'InviteConverter',
+ 'GuildConverter',
+ 'RoleConverter',
+ 'GameConverter',
+ 'ColourConverter',
+ 'ColorConverter',
+ 'VoiceChannelConverter',
+ 'StageChannelConverter',
+ 'EmojiConverter',
+ 'PartialEmojiConverter',
+ 'CategoryChannelConverter',
+ 'IDConverter',
+ 'StoreChannelConverter',
+ 'clean_content',
+ 'Greedy',
+)
+
+def _get_from_guilds(bot, getter, argument):
+ result = None
+ for guild in bot.guilds:
+ result = getattr(guild, getter)(argument)
+ if result:
+ return result
+ return result
+
+_utils_get = discord.utils.get
+
+class Converter:
+ """The base class of custom converters that require the :class:`.Context`
+ to be passed to be useful.
+
+ This allows you to implement converters that function similar to the
+ special cased ``discord`` classes.
+
+ Classes that derive from this should override the :meth:`~.Converter.convert`
+ method to do its conversion logic. This method must be a :ref:`coroutine `.
+ """
+
+ async def convert(self, ctx, argument):
+ """|coro|
+
+ The method to override to do conversion logic.
+
+ If an error is found while converting, it is recommended to
+ raise a :exc:`.CommandError` derived exception as it will
+ properly propagate to the error handlers.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context that the argument is being used in.
+ argument: :class:`str`
+ The argument that is being converted.
+
+ Raises
+ -------
+ :exc:`.CommandError`
+ A generic exception occurred when converting the argument.
+ :exc:`.BadArgument`
+ The converter failed to convert the argument.
+ """
+ raise NotImplementedError('Derived classes need to implement this.')
+
+class IDConverter(Converter):
+ def __init__(self):
+ self._id_regex = re.compile(r'([0-9]{15,20})$')
+ super().__init__()
+
+ def _get_id_match(self, argument):
+ return self._id_regex.match(argument)
+
+class MemberConverter(IDConverter):
+ """Converts to a :class:`~discord.Member`.
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name#discrim
+ 4. Lookup by name
+ 5. Lookup by nickname
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.MemberNotFound` instead of generic :exc:`.BadArgument`
+
+ .. versionchanged:: 1.5.1
+ This converter now lazily fetches members from the gateway and HTTP APIs,
+ optionally caching the result if :attr:`.MemberCacheFlags.joined` is enabled.
+ """
+
+ async def query_member_named(self, guild, argument):
+ cache = guild._state.member_cache_flags.joined
+ if len(argument) > 5 and argument[-5] == '#':
+ username, _, discriminator = argument.rpartition('#')
+ members = await guild.query_members(username, limit=100, cache=cache)
+ return discord.utils.get(members, name=username, discriminator=discriminator)
+ else:
+ members = await guild.query_members(argument, limit=100, cache=cache)
+ return discord.utils.find(lambda m: m.name == argument or m.nick == argument, members)
+
+ async def query_member_by_id(self, bot, guild, user_id):
+ ws = bot._get_websocket(shard_id=guild.shard_id)
+ cache = guild._state.member_cache_flags.joined
+ if ws.is_ratelimited():
+ # If we're being rate limited on the WS, then fall back to using the HTTP API
+ # So we don't have to wait ~60 seconds for the query to finish
+ try:
+ member = await guild.fetch_member(user_id)
+ except discord.HTTPException:
+ return None
+
+ if cache:
+ guild._add_member(member)
+ return member
+
+ # If we're not being rate limited then we can use the websocket to actually query
+ members = await guild.query_members(limit=1, user_ids=[user_id], cache=cache)
+ if not members:
+ return None
+ return members[0]
+
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+ match = self._get_id_match(argument) or re.match(r'<@!?([0-9]+)>$', argument)
+ guild = ctx.guild
+ result = None
+ user_id = None
+ if match is None:
+ # not a mention...
+ if guild:
+ result = guild.get_member_named(argument)
+ else:
+ result = _get_from_guilds(bot, 'get_member_named', argument)
+ else:
+ user_id = int(match.group(1))
+ if guild:
+ result = guild.get_member(user_id) or _utils_get(ctx.message.mentions, id=user_id)
+ else:
+ result = _get_from_guilds(bot, 'get_member', user_id)
+
+ if result is None:
+ if guild is None:
+ raise MemberNotFound(argument)
+
+ if user_id is not None:
+ result = await self.query_member_by_id(bot, guild, user_id)
+ else:
+ result = await self.query_member_named(guild, argument)
+
+ if not result:
+ raise MemberNotFound(argument)
+
+ return result
+
+class UserConverter(IDConverter):
+ """Converts to a :class:`~discord.User`.
+
+ All lookups are via the global user cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name#discrim
+ 4. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.UserNotFound` instead of generic :exc:`.BadArgument`
+
+ .. versionchanged:: 1.6
+ This converter now lazily fetches users from the HTTP APIs if an ID is passed
+ and it's not available in cache.
+ """
+ async def convert(self, ctx, argument):
+ match = self._get_id_match(argument) or re.match(r'<@!?([0-9]+)>$', argument)
+ result = None
+ state = ctx._state
+
+ if match is not None:
+ user_id = int(match.group(1))
+ result = ctx.bot.get_user(user_id) or _utils_get(ctx.message.mentions, id=user_id)
+ if result is None:
+ try:
+ result = await ctx.bot.fetch_user(user_id)
+ except discord.HTTPException:
+ raise UserNotFound(argument) from None
+
+ return result
+
+ arg = argument
+
+ # Remove the '@' character if this is the first character from the argument
+ if arg[0] == '@':
+ # Remove first character
+ arg = arg[1:]
+
+ # check for discriminator if it exists,
+ if len(arg) > 5 and arg[-5] == '#':
+ discrim = arg[-4:]
+ name = arg[:-5]
+ predicate = lambda u: u.name == name and u.discriminator == discrim
+ result = discord.utils.find(predicate, state._users.values())
+ if result is not None:
+ return result
+
+ predicate = lambda u: u.name == arg
+ result = discord.utils.find(predicate, state._users.values())
+
+ if result is None:
+ raise UserNotFound(argument)
+
+ return result
+
+class PartialMessageConverter(Converter):
+ """Converts to a :class:`discord.PartialMessage`.
+
+ .. versionadded:: 1.7
+
+ The creation strategy is as follows (in order):
+
+ 1. By "{channel ID}-{message ID}" (retrieved by shift-clicking on "Copy ID")
+ 2. By message ID (The message is assumed to be in the context channel.)
+ 3. By message URL
+ """
+ def _get_id_matches(self, argument):
+ id_regex = re.compile(r'(?:(?P[0-9]{15,20})-)?(?P[0-9]{15,20})$')
+ link_regex = re.compile(
+ r'https?://(?:(ptb|canary|www)\.)?discord(?:app)?\.com/channels/'
+ r'(?:[0-9]{15,20}|@me)'
+ r'/(?P[0-9]{15,20})/(?P[0-9]{15,20})/?$'
+ )
+ match = id_regex.match(argument) or link_regex.match(argument)
+ if not match:
+ raise MessageNotFound(argument)
+ channel_id = match.group("channel_id")
+ return int(match.group("message_id")), int(channel_id) if channel_id else None
+
+ async def convert(self, ctx, argument):
+ message_id, channel_id = self._get_id_matches(argument)
+ channel = ctx.bot.get_channel(channel_id) if channel_id else ctx.channel
+ if not channel:
+ raise ChannelNotFound(channel_id)
+ return discord.PartialMessage(channel=channel, id=message_id)
+
+class MessageConverter(PartialMessageConverter):
+ """Converts to a :class:`discord.Message`.
+
+ .. versionadded:: 1.1
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by "{channel ID}-{message ID}" (retrieved by shift-clicking on "Copy ID")
+ 2. Lookup by message ID (the message **must** be in the context channel)
+ 3. Lookup by message URL
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.ChannelNotFound`, :exc:`.MessageNotFound` or :exc:`.ChannelNotReadable` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ message_id, channel_id = self._get_id_matches(argument)
+ message = ctx.bot._connection._get_message(message_id)
+ if message:
+ return message
+ channel = ctx.bot.get_channel(channel_id) if channel_id else ctx.channel
+ if not channel:
+ raise ChannelNotFound(channel_id)
+ try:
+ return await channel.fetch_message(message_id)
+ except discord.NotFound:
+ raise MessageNotFound(argument)
+ except discord.Forbidden:
+ raise ChannelNotReadable(channel)
+
+class TextChannelConverter(IDConverter):
+ """Converts to a :class:`~discord.TextChannel`.
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+
+ match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
+ result = None
+ guild = ctx.guild
+
+ if match is None:
+ # not a mention
+ if guild:
+ result = discord.utils.get(guild.text_channels, name=argument)
+ else:
+ def check(c):
+ return isinstance(c, discord.TextChannel) and c.name == argument
+ result = discord.utils.find(check, bot.get_all_channels())
+ else:
+ channel_id = int(match.group(1))
+ if guild:
+ result = guild.get_channel(channel_id)
+ else:
+ result = _get_from_guilds(bot, 'get_channel', channel_id)
+
+ if not isinstance(result, discord.TextChannel):
+ raise ChannelNotFound(argument)
+
+ return result
+
+class VoiceChannelConverter(IDConverter):
+ """Converts to a :class:`~discord.VoiceChannel`.
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+ match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
+ result = None
+ guild = ctx.guild
+
+ if match is None:
+ # not a mention
+ if guild:
+ result = discord.utils.get(guild.voice_channels, name=argument)
+ else:
+ def check(c):
+ return isinstance(c, discord.VoiceChannel) and c.name == argument
+ result = discord.utils.find(check, bot.get_all_channels())
+ else:
+ channel_id = int(match.group(1))
+ if guild:
+ result = guild.get_channel(channel_id)
+ else:
+ result = _get_from_guilds(bot, 'get_channel', channel_id)
+
+ if not isinstance(result, discord.VoiceChannel):
+ raise ChannelNotFound(argument)
+
+ return result
+
+class StageChannelConverter(IDConverter):
+ """Converts to a :class:`~discord.StageChannel`.
+
+ .. versionadded:: 1.7
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name
+ """
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+ match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
+ result = None
+ guild = ctx.guild
+
+ if match is None:
+ # not a mention
+ if guild:
+ result = discord.utils.get(guild.stage_channels, name=argument)
+ else:
+ def check(c):
+ return isinstance(c, discord.StageChannel) and c.name == argument
+ result = discord.utils.find(check, bot.get_all_channels())
+ else:
+ channel_id = int(match.group(1))
+ if guild:
+ result = guild.get_channel(channel_id)
+ else:
+ result = _get_from_guilds(bot, 'get_channel', channel_id)
+
+ if not isinstance(result, discord.StageChannel):
+ raise ChannelNotFound(argument)
+
+ return result
+
+class CategoryChannelConverter(IDConverter):
+ """Converts to a :class:`~discord.CategoryChannel`.
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.ChannelNotFound` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+
+ match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
+ result = None
+ guild = ctx.guild
+
+ if match is None:
+ # not a mention
+ if guild:
+ result = discord.utils.get(guild.categories, name=argument)
+ else:
+ def check(c):
+ return isinstance(c, discord.CategoryChannel) and c.name == argument
+ result = discord.utils.find(check, bot.get_all_channels())
+ else:
+ channel_id = int(match.group(1))
+ if guild:
+ result = guild.get_channel(channel_id)
+ else:
+ result = _get_from_guilds(bot, 'get_channel', channel_id)
+
+ if not isinstance(result, discord.CategoryChannel):
+ raise ChannelNotFound(argument)
+
+ return result
+
+class StoreChannelConverter(IDConverter):
+ """Converts to a :class:`~discord.StoreChannel`.
+
+ All lookups are via the local guild. If in a DM context, then the lookup
+ is done by the global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name.
+
+ .. versionadded:: 1.7
+ """
+
+ async def convert(self, ctx, argument):
+ bot = ctx.bot
+ match = self._get_id_match(argument) or re.match(r'<#([0-9]+)>$', argument)
+ result = None
+ guild = ctx.guild
+
+ if match is None:
+ # not a mention
+ if guild:
+ result = discord.utils.get(guild.channels, name=argument)
+ else:
+ def check(c):
+ return isinstance(c, discord.StoreChannel) and c.name == argument
+ result = discord.utils.find(check, bot.get_all_channels())
+ else:
+ channel_id = int(match.group(1))
+ if guild:
+ result = guild.get_channel(channel_id)
+ else:
+ result = _get_from_guilds(bot, 'get_channel', channel_id)
+
+ if not isinstance(result, discord.StoreChannel):
+ raise ChannelNotFound(argument)
+
+ return result
+
+class ColourConverter(Converter):
+ """Converts to a :class:`~discord.Colour`.
+
+ .. versionchanged:: 1.5
+ Add an alias named ColorConverter
+
+ The following formats are accepted:
+
+ - ``0x``
+ - ``#``
+ - ``0x#``
+ - ``rgb(, , )``
+ - Any of the ``classmethod`` in :class:`Colour`
+
+ - The ``_`` in the name can be optionally replaced with spaces.
+
+ Like CSS, ```` can be either 0-255 or 0-100% and ```` can be
+ either a 6 digit hex number or a 3 digit hex shortcut (e.g. #fff).
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.BadColourArgument` instead of generic :exc:`.BadArgument`
+
+ .. versionchanged:: 1.7
+ Added support for ``rgb`` function and 3-digit hex shortcuts
+ """
+
+ RGB_REGEX = re.compile(r'rgb\s*\((?P[0-9]{1,3}%?)\s*,\s*(?P[0-9]{1,3}%?)\s*,\s*(?P[0-9]{1,3}%?)\s*\)')
+
+ def parse_hex_number(self, argument):
+ arg = ''.join(i * 2 for i in argument) if len(argument) == 3 else argument
+ try:
+ value = int(arg, base=16)
+ if not (0 <= value <= 0xFFFFFF):
+ raise BadColourArgument(argument)
+ except ValueError:
+ raise BadColourArgument(argument)
+ else:
+ return discord.Color(value=value)
+
+ def parse_rgb_number(self, argument, number):
+ if number[-1] == '%':
+ value = int(number[:-1])
+ if not (0 <= value <= 100):
+ raise BadColourArgument(argument)
+ return round(255 * (value / 100))
+
+ value = int(number)
+ if not (0 <= value <= 255):
+ raise BadColourArgument(argument)
+ return value
+
+ def parse_rgb(self, argument, *, regex=RGB_REGEX):
+ match = regex.match(argument)
+ if match is None:
+ raise BadColourArgument(argument)
+
+ red = self.parse_rgb_number(argument, match.group('r'))
+ green = self.parse_rgb_number(argument, match.group('g'))
+ blue = self.parse_rgb_number(argument, match.group('b'))
+ return discord.Color.from_rgb(red, green, blue)
+
+ async def convert(self, ctx, argument):
+ if argument[0] == '#':
+ return self.parse_hex_number(argument[1:])
+
+ if argument[0:2] == '0x':
+ rest = argument[2:]
+ # Legacy backwards compatible syntax
+ if rest.startswith('#'):
+ return self.parse_hex_number(rest[1:])
+ return self.parse_hex_number(rest)
+
+ arg = argument.lower()
+ if arg[0:3] == 'rgb':
+ return self.parse_rgb(arg)
+
+ arg = arg.replace(' ', '_')
+ method = getattr(discord.Colour, arg, None)
+ if arg.startswith('from_') or method is None or not inspect.ismethod(method):
+ raise BadColourArgument(arg)
+ return method()
+
+ColorConverter = ColourConverter
+
+class RoleConverter(IDConverter):
+ """Converts to a :class:`~discord.Role`.
+
+ All lookups are via the local guild. If in a DM context, the converter raises
+ :exc:`.NoPrivateMessage` exception.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by mention.
+ 3. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.RoleNotFound` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ guild = ctx.guild
+ if not guild:
+ raise NoPrivateMessage()
+
+ match = self._get_id_match(argument) or re.match(r'<@&([0-9]+)>$', argument)
+ if match:
+ result = guild.get_role(int(match.group(1)))
+ else:
+ result = discord.utils.get(guild._roles.values(), name=argument)
+
+ if result is None:
+ raise RoleNotFound(argument)
+ return result
+
+class GameConverter(Converter):
+ """Converts to :class:`~discord.Game`."""
+ async def convert(self, ctx, argument):
+ return discord.Game(name=argument)
+
+class InviteConverter(Converter):
+ """Converts to a :class:`~discord.Invite`.
+
+ This is done via an HTTP request using :meth:`.Bot.fetch_invite`.
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.BadInviteArgument` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ try:
+ invite = await ctx.bot.fetch_invite(argument)
+ return invite
+ except Exception as exc:
+ raise BadInviteArgument() from exc
+
+class GuildConverter(IDConverter):
+ """Converts to a :class:`~discord.Guild`.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by name. (There is no disambiguation for Guilds with multiple matching names).
+
+ .. versionadded:: 1.7
+ """
+
+ async def convert(self, ctx, argument):
+ match = self._get_id_match(argument)
+ result = None
+
+ if match is not None:
+ guild_id = int(match.group(1))
+ result = ctx.bot.get_guild(guild_id)
+
+ if result is None:
+ result = discord.utils.get(ctx.bot.guilds, name=argument)
+
+ if result is None:
+ raise GuildNotFound(argument)
+ return result
+
+class EmojiConverter(IDConverter):
+ """Converts to a :class:`~discord.Emoji`.
+
+ All lookups are done for the local guild first, if available. If that lookup
+ fails, then it checks the client's global cache.
+
+ The lookup strategy is as follows (in order):
+
+ 1. Lookup by ID.
+ 2. Lookup by extracting ID from the emoji.
+ 3. Lookup by name
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.EmojiNotFound` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ match = self._get_id_match(argument) or re.match(r'$', argument)
+ result = None
+ bot = ctx.bot
+ guild = ctx.guild
+
+ if match is None:
+ # Try to get the emoji by name. Try local guild first.
+ if guild:
+ result = discord.utils.get(guild.emojis, name=argument)
+
+ if result is None:
+ result = discord.utils.get(bot.emojis, name=argument)
+ else:
+ emoji_id = int(match.group(1))
+
+ # Try to look up emoji by id.
+ if guild:
+ result = discord.utils.get(guild.emojis, id=emoji_id)
+
+ if result is None:
+ result = discord.utils.get(bot.emojis, id=emoji_id)
+
+ if result is None:
+ raise EmojiNotFound(argument)
+
+ return result
+
+class PartialEmojiConverter(Converter):
+ """Converts to a :class:`~discord.PartialEmoji`.
+
+ This is done by extracting the animated flag, name and ID from the emoji.
+
+ .. versionchanged:: 1.5
+ Raise :exc:`.PartialEmojiConversionFailure` instead of generic :exc:`.BadArgument`
+ """
+ async def convert(self, ctx, argument):
+ match = re.match(r'<(a?):([a-zA-Z0-9\_]+):([0-9]+)>$', argument)
+
+ if match:
+ emoji_animated = bool(match.group(1))
+ emoji_name = match.group(2)
+ emoji_id = int(match.group(3))
+
+ return discord.PartialEmoji.with_state(ctx.bot._connection, animated=emoji_animated, name=emoji_name,
+ id=emoji_id)
+
+ raise PartialEmojiConversionFailure(argument)
+
+class clean_content(Converter):
+ """Converts the argument to mention scrubbed version of
+ said content.
+
+ This behaves similarly to :attr:`~discord.Message.clean_content`.
+
+ Attributes
+ ------------
+ fix_channel_mentions: :class:`bool`
+ Whether to clean channel mentions.
+ use_nicknames: :class:`bool`
+ Whether to use nicknames when transforming mentions.
+ escape_markdown: :class:`bool`
+ Whether to also escape special markdown characters.
+ remove_markdown: :class:`bool`
+ Whether to also remove special markdown characters. This option is not supported with ``escape_markdown``
+
+ .. versionadded:: 1.7
+ """
+ def __init__(self, *, fix_channel_mentions=False, use_nicknames=True, escape_markdown=False, remove_markdown=False):
+ self.fix_channel_mentions = fix_channel_mentions
+ self.use_nicknames = use_nicknames
+ self.escape_markdown = escape_markdown
+ self.remove_markdown = remove_markdown
+
+ async def convert(self, ctx, argument):
+ message = ctx.message
+ transformations = {}
+
+ if self.fix_channel_mentions and ctx.guild:
+ def resolve_channel(id, *, _get=ctx.guild.get_channel):
+ ch = _get(id)
+ return ('<#%s>' % id), ('#' + ch.name if ch else '#deleted-channel')
+
+ transformations.update(resolve_channel(channel) for channel in message.raw_channel_mentions)
+
+ if self.use_nicknames and ctx.guild:
+ def resolve_member(id, *, _get=ctx.guild.get_member):
+ m = _get(id)
+ return '@' + m.display_name if m else '@deleted-user'
+ else:
+ def resolve_member(id, *, _get=ctx.bot.get_user):
+ m = _get(id)
+ return '@' + m.name if m else '@deleted-user'
+
+
+ transformations.update(
+ ('<@%s>' % member_id, resolve_member(member_id))
+ for member_id in message.raw_mentions
+ )
+
+ transformations.update(
+ ('<@!%s>' % member_id, resolve_member(member_id))
+ for member_id in message.raw_mentions
+ )
+
+ if ctx.guild:
+ def resolve_role(_id, *, _find=ctx.guild.get_role):
+ r = _find(_id)
+ return '@' + r.name if r else '@deleted-role'
+
+ transformations.update(
+ ('<@&%s>' % role_id, resolve_role(role_id))
+ for role_id in message.raw_role_mentions
+ )
+
+ def repl(obj):
+ return transformations.get(obj.group(0), '')
+
+ pattern = re.compile('|'.join(transformations.keys()))
+ result = pattern.sub(repl, argument)
+
+ if self.escape_markdown:
+ result = discord.utils.escape_markdown(result)
+ elif self.remove_markdown:
+ result = discord.utils.remove_markdown(result)
+
+ # Completely ensure no mentions escape:
+ return discord.utils.escape_mentions(result)
+
+class _Greedy:
+ __slots__ = ('converter',)
+
+ def __init__(self, *, converter=None):
+ self.converter = converter
+
+ def __getitem__(self, params):
+ if not isinstance(params, tuple):
+ params = (params,)
+ if len(params) != 1:
+ raise TypeError('Greedy[...] only takes a single argument')
+ converter = params[0]
+
+ if not (callable(converter) or isinstance(converter, Converter) or hasattr(converter, '__origin__')):
+ raise TypeError('Greedy[...] expects a type or a Converter instance.')
+
+ if converter is str or converter is type(None) or converter is _Greedy:
+ raise TypeError('Greedy[%s] is invalid.' % converter.__name__)
+
+ if getattr(converter, '__origin__', None) is typing.Union and type(None) in converter.__args__:
+ raise TypeError('Greedy[%r] is invalid.' % converter)
+
+ return self.__class__(converter=converter)
+
+Greedy = _Greedy()
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/cooldowns.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/cooldowns.py
new file mode 100644
index 0000000..54a5339
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/cooldowns.py
@@ -0,0 +1,295 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+from discord.enums import Enum
+import time
+import asyncio
+from collections import deque
+
+from ...abc import PrivateChannel
+from .errors import MaxConcurrencyReached
+
+__all__ = (
+ 'BucketType',
+ 'Cooldown',
+ 'CooldownMapping',
+ 'MaxConcurrency',
+)
+
+class BucketType(Enum):
+ default = 0
+ user = 1
+ guild = 2
+ channel = 3
+ member = 4
+ category = 5
+ role = 6
+
+ def get_key(self, msg):
+ if self is BucketType.user:
+ return msg.author.id
+ elif self is BucketType.guild:
+ return (msg.guild or msg.author).id
+ elif self is BucketType.channel:
+ return msg.channel.id
+ elif self is BucketType.member:
+ return ((msg.guild and msg.guild.id), msg.author.id)
+ elif self is BucketType.category:
+ return (msg.channel.category or msg.channel).id
+ elif self is BucketType.role:
+ # we return the channel id of a private-channel as there are only roles in guilds
+ # and that yields the same result as for a guild with only the @everyone role
+ # NOTE: PrivateChannel doesn't actually have an id attribute but we assume we are
+ # recieving a DMChannel or GroupChannel which inherit from PrivateChannel and do
+ return (msg.channel if isinstance(msg.channel, PrivateChannel) else msg.author.top_role).id
+
+ def __call__(self, msg):
+ return self.get_key(msg)
+
+
+class Cooldown:
+ __slots__ = ('rate', 'per', 'type', '_window', '_tokens', '_last')
+
+ def __init__(self, rate, per, type):
+ self.rate = int(rate)
+ self.per = float(per)
+ self.type = type
+ self._window = 0.0
+ self._tokens = self.rate
+ self._last = 0.0
+
+ if not callable(self.type):
+ raise TypeError('Cooldown type must be a BucketType or callable')
+
+ def get_tokens(self, current=None):
+ if not current:
+ current = time.time()
+
+ tokens = self._tokens
+
+ if current > self._window + self.per:
+ tokens = self.rate
+ return tokens
+
+ def get_retry_after(self, current=None):
+ current = current or time.time()
+ tokens = self.get_tokens(current)
+
+ if tokens == 0:
+ return self.per - (current - self._window)
+
+ return 0.0
+
+ def update_rate_limit(self, current=None):
+ current = current or time.time()
+ self._last = current
+
+ self._tokens = self.get_tokens(current)
+
+ # first token used means that we start a new rate limit window
+ if self._tokens == self.rate:
+ self._window = current
+
+ # check if we are rate limited
+ if self._tokens == 0:
+ return self.per - (current - self._window)
+
+ # we're not so decrement our tokens
+ self._tokens -= 1
+
+ # see if we got rate limited due to this token change, and if
+ # so update the window to point to our current time frame
+ if self._tokens == 0:
+ self._window = current
+
+ def reset(self):
+ self._tokens = self.rate
+ self._last = 0.0
+
+ def copy(self):
+ return Cooldown(self.rate, self.per, self.type)
+
+ def __repr__(self):
+ return ''.format(self)
+
+class CooldownMapping:
+ def __init__(self, original):
+ self._cache = {}
+ self._cooldown = original
+
+ def copy(self):
+ ret = CooldownMapping(self._cooldown)
+ ret._cache = self._cache.copy()
+ return ret
+
+ @property
+ def valid(self):
+ return self._cooldown is not None
+
+ @classmethod
+ def from_cooldown(cls, rate, per, type):
+ return cls(Cooldown(rate, per, type))
+
+ def _bucket_key(self, msg):
+ return self._cooldown.type(msg)
+
+ def _verify_cache_integrity(self, current=None):
+ # we want to delete all cache objects that haven't been used
+ # in a cooldown window. e.g. if we have a command that has a
+ # cooldown of 60s and it has not been used in 60s then that key should be deleted
+ current = current or time.time()
+ dead_keys = [k for k, v in self._cache.items() if current > v._last + v.per]
+ for k in dead_keys:
+ del self._cache[k]
+
+ def get_bucket(self, message, current=None):
+ if self._cooldown.type is BucketType.default:
+ return self._cooldown
+
+ self._verify_cache_integrity(current)
+ key = self._bucket_key(message)
+ if key not in self._cache:
+ bucket = self._cooldown.copy()
+ self._cache[key] = bucket
+ else:
+ bucket = self._cache[key]
+
+ return bucket
+
+ def update_rate_limit(self, message, current=None):
+ bucket = self.get_bucket(message, current)
+ return bucket.update_rate_limit(current)
+
+class _Semaphore:
+ """This class is a version of a semaphore.
+
+ If you're wondering why asyncio.Semaphore isn't being used,
+ it's because it doesn't expose the internal value. This internal
+ value is necessary because I need to support both `wait=True` and
+ `wait=False`.
+
+ An asyncio.Queue could have been used to do this as well -- but it is
+ not as inefficient since internally that uses two queues and is a bit
+ overkill for what is basically a counter.
+ """
+
+ __slots__ = ('value', 'loop', '_waiters')
+
+ def __init__(self, number):
+ self.value = number
+ self.loop = asyncio.get_event_loop()
+ self._waiters = deque()
+
+ def __repr__(self):
+ return '<_Semaphore value={0.value} waiters={1}>'.format(self, len(self._waiters))
+
+ def locked(self):
+ return self.value == 0
+
+ def is_active(self):
+ return len(self._waiters) > 0
+
+ def wake_up(self):
+ while self._waiters:
+ future = self._waiters.popleft()
+ if not future.done():
+ future.set_result(None)
+ return
+
+ async def acquire(self, *, wait=False):
+ if not wait and self.value <= 0:
+ # signal that we're not acquiring
+ return False
+
+ while self.value <= 0:
+ future = self.loop.create_future()
+ self._waiters.append(future)
+ try:
+ await future
+ except:
+ future.cancel()
+ if self.value > 0 and not future.cancelled():
+ self.wake_up()
+ raise
+
+ self.value -= 1
+ return True
+
+ def release(self):
+ self.value += 1
+ self.wake_up()
+
+class MaxConcurrency:
+ __slots__ = ('number', 'per', 'wait', '_mapping')
+
+ def __init__(self, number, *, per, wait):
+ self._mapping = {}
+ self.per = per
+ self.number = number
+ self.wait = wait
+
+ if number <= 0:
+ raise ValueError('max_concurrency \'number\' cannot be less than 1')
+
+ if not isinstance(per, BucketType):
+ raise TypeError('max_concurrency \'per\' must be of type BucketType not %r' % type(per))
+
+ def copy(self):
+ return self.__class__(self.number, per=self.per, wait=self.wait)
+
+ def __repr__(self):
+ return ''.format(self)
+
+ def get_key(self, message):
+ return self.per.get_key(message)
+
+ async def acquire(self, message):
+ key = self.get_key(message)
+
+ try:
+ sem = self._mapping[key]
+ except KeyError:
+ self._mapping[key] = sem = _Semaphore(self.number)
+
+ acquired = await sem.acquire(wait=self.wait)
+ if not acquired:
+ raise MaxConcurrencyReached(self.number, self.per)
+
+ async def release(self, message):
+ # Technically there's no reason for this function to be async
+ # But it might be more useful in the future
+ key = self.get_key(message)
+
+ try:
+ sem = self._mapping[key]
+ except KeyError:
+ # ...? peculiar
+ return
+ else:
+ sem.release()
+
+ if sem.value >= self.number and not sem.is_active():
+ del self._mapping[key]
diff --git a/venv/lib64/python3.8/site-packages/discord/ext/commands/core.py b/venv/lib64/python3.8/site-packages/discord/ext/commands/core.py
new file mode 100644
index 0000000..1c22ec0
--- /dev/null
+++ b/venv/lib64/python3.8/site-packages/discord/ext/commands/core.py
@@ -0,0 +1,2070 @@
+# -*- coding: utf-8 -*-
+
+"""
+The MIT License (MIT)
+
+Copyright (c) 2015-present Rapptz
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+"""
+
+import asyncio
+import functools
+import inspect
+import typing
+import datetime
+
+import discord
+
+from .errors import *
+from .cooldowns import Cooldown, BucketType, CooldownMapping, MaxConcurrency
+from . import converter as converters
+from ._types import _BaseCommand
+from .cog import Cog
+
+__all__ = (
+ 'Command',
+ 'Group',
+ 'GroupMixin',
+ 'command',
+ 'group',
+ 'has_role',
+ 'has_permissions',
+ 'has_any_role',
+ 'check',
+ 'check_any',
+ 'before_invoke',
+ 'after_invoke',
+ 'bot_has_role',
+ 'bot_has_permissions',
+ 'bot_has_any_role',
+ 'cooldown',
+ 'max_concurrency',
+ 'dm_only',
+ 'guild_only',
+ 'is_owner',
+ 'is_nsfw',
+ 'has_guild_permissions',
+ 'bot_has_guild_permissions'
+)
+
+def wrap_callback(coro):
+ @functools.wraps(coro)
+ async def wrapped(*args, **kwargs):
+ try:
+ ret = await coro(*args, **kwargs)
+ except CommandError:
+ raise
+ except asyncio.CancelledError:
+ return
+ except Exception as exc:
+ raise CommandInvokeError(exc) from exc
+ return ret
+ return wrapped
+
+def hooked_wrapped_callback(command, ctx, coro):
+ @functools.wraps(coro)
+ async def wrapped(*args, **kwargs):
+ try:
+ ret = await coro(*args, **kwargs)
+ except CommandError:
+ ctx.command_failed = True
+ raise
+ except asyncio.CancelledError:
+ ctx.command_failed = True
+ return
+ except Exception as exc:
+ ctx.command_failed = True
+ raise CommandInvokeError(exc) from exc
+ finally:
+ if command._max_concurrency is not None:
+ await command._max_concurrency.release(ctx)
+
+ await command.call_after_hooks(ctx)
+ return ret
+ return wrapped
+
+def _convert_to_bool(argument):
+ lowered = argument.lower()
+ if lowered in ('yes', 'y', 'true', 't', '1', 'enable', 'on'):
+ return True
+ elif lowered in ('no', 'n', 'false', 'f', '0', 'disable', 'off'):
+ return False
+ else:
+ raise BadBoolArgument(lowered)
+
+class _CaseInsensitiveDict(dict):
+ def __contains__(self, k):
+ return super().__contains__(k.casefold())
+
+ def __delitem__(self, k):
+ return super().__delitem__(k.casefold())
+
+ def __getitem__(self, k):
+ return super().__getitem__(k.casefold())
+
+ def get(self, k, default=None):
+ return super().get(k.casefold(), default)
+
+ def pop(self, k, default=None):
+ return super().pop(k.casefold(), default)
+
+ def __setitem__(self, k, v):
+ super().__setitem__(k.casefold(), v)
+
+class Command(_BaseCommand):
+ r"""A class that implements the protocol for a bot text command.
+
+ These are not created manually, instead they are created via the
+ decorator or functional interface.
+
+ Attributes
+ -----------
+ name: :class:`str`
+ The name of the command.
+ callback: :ref:`coroutine `
+ The coroutine that is executed when the command is called.
+ help: :class:`str`
+ The long help text for the command.
+ brief: Optional[:class:`str`]
+ The short help text for the command.
+ usage: Optional[:class:`str`]
+ A replacement for arguments in the default help text.
+ aliases: Union[List[:class:`str`], Tuple[:class:`str`]]
+ The list of aliases the command can be invoked under.
+ enabled: :class:`bool`
+ A boolean that indicates if the command is currently enabled.
+ If the command is invoked while it is disabled, then
+ :exc:`.DisabledCommand` is raised to the :func:`.on_command_error`
+ event. Defaults to ``True``.
+ parent: Optional[:class:`Command`]
+ The parent command that this command belongs to. ``None`` if there
+ isn't one.
+ cog: Optional[:class:`Cog`]
+ The cog that this command belongs to. ``None`` if there isn't one.
+ checks: List[Callable[[:class:`.Context`], :class:`bool`]]
+ A list of predicates that verifies if the command could be executed
+ with the given :class:`.Context` as the sole parameter. If an exception
+ is necessary to be thrown to signal failure, then one inherited from
+ :exc:`.CommandError` should be used. Note that if the checks fail then
+ :exc:`.CheckFailure` exception is raised to the :func:`.on_command_error`
+ event.
+ description: :class:`str`
+ The message prefixed into the default help command.
+ hidden: :class:`bool`
+ If ``True``\, the default help command does not show this in the
+ help output.
+ rest_is_raw: :class:`bool`
+ If ``False`` and a keyword-only argument is provided then the keyword
+ only argument is stripped and handled as if it was a regular argument
+ that handles :exc:`.MissingRequiredArgument` and default values in a
+ regular matter rather than passing the rest completely raw. If ``True``
+ then the keyword-only argument will pass in the rest of the arguments
+ in a completely raw matter. Defaults to ``False``.
+ invoked_subcommand: Optional[:class:`Command`]
+ The subcommand that was invoked, if any.
+ require_var_positional: :class:`bool`
+ If ``True`` and a variadic positional argument is specified, requires
+ the user to specify at least one argument. Defaults to ``False``.
+
+ .. versionadded:: 1.5
+
+ ignore_extra: :class:`bool`
+ If ``True``\, ignores extraneous strings passed to a command if all its
+ requirements are met (e.g. ``?foo a b c`` when only expecting ``a``
+ and ``b``). Otherwise :func:`.on_command_error` and local error handlers
+ are called with :exc:`.TooManyArguments`. Defaults to ``True``.
+ cooldown_after_parsing: :class:`bool`
+ If ``True``\, cooldown processing is done after argument parsing,
+ which calls converters. If ``False`` then cooldown processing is done
+ first and then the converters are called second. Defaults to ``False``.
+ """
+
+ def __new__(cls, *args, **kwargs):
+ # if you're wondering why this is done, it's because we need to ensure
+ # we have a complete original copy of **kwargs even for classes that
+ # mess with it by popping before delegating to the subclass __init__.
+ # In order to do this, we need to control the instance creation and
+ # inject the original kwargs through __new__ rather than doing it
+ # inside __init__.
+ self = super().__new__(cls)
+
+ # we do a shallow copy because it's probably the most common use case.
+ # this could potentially break if someone modifies a list or something
+ # while it's in movement, but for now this is the cheapest and
+ # fastest way to do what we want.
+ self.__original_kwargs__ = kwargs.copy()
+ return self
+
+ def __init__(self, func, **kwargs):
+ if not asyncio.iscoroutinefunction(func):
+ raise TypeError('Callback must be a coroutine.')
+
+ self.name = name = kwargs.get('name') or func.__name__
+ if not isinstance(name, str):
+ raise TypeError('Name of a command must be a string.')
+
+ self.callback = func
+ self.enabled = kwargs.get('enabled', True)
+
+ help_doc = kwargs.get('help')
+ if help_doc is not None:
+ help_doc = inspect.cleandoc(help_doc)
+ else:
+ help_doc = inspect.getdoc(func)
+ if isinstance(help_doc, bytes):
+ help_doc = help_doc.decode('utf-8')
+
+ self.help = help_doc
+
+ self.brief = kwargs.get('brief')
+ self.usage = kwargs.get('usage')
+ self.rest_is_raw = kwargs.get('rest_is_raw', False)
+ self.aliases = kwargs.get('aliases', [])
+
+ if not isinstance(self.aliases, (list, tuple)):
+ raise TypeError("Aliases of a command must be a list or a tuple of strings.")
+
+ self.description = inspect.cleandoc(kwargs.get('description', ''))
+ self.hidden = kwargs.get('hidden', False)
+
+ try:
+ checks = func.__commands_checks__
+ checks.reverse()
+ except AttributeError:
+ checks = kwargs.get('checks', [])
+ finally:
+ self.checks = checks
+
+ try:
+ cooldown = func.__commands_cooldown__
+ except AttributeError:
+ cooldown = kwargs.get('cooldown')
+ finally:
+ self._buckets = CooldownMapping(cooldown)
+
+ try:
+ max_concurrency = func.__commands_max_concurrency__
+ except AttributeError:
+ max_concurrency = kwargs.get('max_concurrency')
+ finally:
+ self._max_concurrency = max_concurrency
+
+ self.require_var_positional = kwargs.get('require_var_positional', False)
+ self.ignore_extra = kwargs.get('ignore_extra', True)
+ self.cooldown_after_parsing = kwargs.get('cooldown_after_parsing', False)
+ self.cog = None
+
+ # bandaid for the fact that sometimes parent can be the bot instance
+ parent = kwargs.get('parent')
+ self.parent = parent if isinstance(parent, _BaseCommand) else None
+
+ try:
+ before_invoke = func.__before_invoke__
+ except AttributeError:
+ self._before_invoke = None
+ else:
+ self.before_invoke(before_invoke)
+
+ try:
+ after_invoke = func.__after_invoke__
+ except AttributeError:
+ self._after_invoke = None
+ else:
+ self.after_invoke(after_invoke)
+
+ @property
+ def callback(self):
+ return self._callback
+
+ @callback.setter
+ def callback(self, function):
+ self._callback = function
+ self.module = function.__module__
+
+ signature = inspect.signature(function)
+ self.params = signature.parameters.copy()
+
+ # PEP-563 allows postponing evaluation of annotations with a __future__
+ # import. When postponed, Parameter.annotation will be a string and must
+ # be replaced with the real value for the converters to work later on
+ for key, value in self.params.items():
+ if isinstance(value.annotation, str):
+ self.params[key] = value = value.replace(annotation=eval(value.annotation, function.__globals__))
+
+ # fail early for when someone passes an unparameterized Greedy type
+ if value.annotation is converters.Greedy:
+ raise TypeError('Unparameterized Greedy[...] is disallowed in signature.')
+
+ def add_check(self, func):
+ """Adds a check to the command.
+
+ This is the non-decorator interface to :func:`.check`.
+
+ .. versionadded:: 1.3
+
+ Parameters
+ -----------
+ func
+ The function that will be used as a check.
+ """
+
+ self.checks.append(func)
+
+ def remove_check(self, func):
+ """Removes a check from the command.
+
+ This function is idempotent and will not raise an exception
+ if the function is not in the command's checks.
+
+ .. versionadded:: 1.3
+
+ Parameters
+ -----------
+ func
+ The function to remove from the checks.
+ """
+
+ try:
+ self.checks.remove(func)
+ except ValueError:
+ pass
+
+ def update(self, **kwargs):
+ """Updates :class:`Command` instance with updated attribute.
+
+ This works similarly to the :func:`.command` decorator in terms
+ of parameters in that they are passed to the :class:`Command` or
+ subclass constructors, sans the name and callback.
+ """
+ self.__init__(self.callback, **dict(self.__original_kwargs__, **kwargs))
+
+ async def __call__(self, *args, **kwargs):
+ """|coro|
+
+ Calls the internal callback that the command holds.
+
+ .. note::
+
+ This bypasses all mechanisms -- including checks, converters,
+ invoke hooks, cooldowns, etc. You must take care to pass
+ the proper arguments and types to this function.
+
+ .. versionadded:: 1.3
+ """
+ if self.cog is not None:
+ return await self.callback(self.cog, *args, **kwargs)
+ else:
+ return await self.callback(*args, **kwargs)
+
+ def _ensure_assignment_on_copy(self, other):
+ other._before_invoke = self._before_invoke
+ other._after_invoke = self._after_invoke
+ if self.checks != other.checks:
+ other.checks = self.checks.copy()
+ if self._buckets.valid and not other._buckets.valid:
+ other._buckets = self._buckets.copy()
+ if self._max_concurrency != other._max_concurrency:
+ other._max_concurrency = self._max_concurrency.copy()
+
+ try:
+ other.on_error = self.on_error
+ except AttributeError:
+ pass
+ return other
+
+ def copy(self):
+ """Creates a copy of this command.
+
+ Returns
+ --------
+ :class:`Command`
+ A new instance of this command.
+ """
+ ret = self.__class__(self.callback, **self.__original_kwargs__)
+ return self._ensure_assignment_on_copy(ret)
+
+ def _update_copy(self, kwargs):
+ if kwargs:
+ kw = kwargs.copy()
+ kw.update(self.__original_kwargs__)
+ copy = self.__class__(self.callback, **kw)
+ return self._ensure_assignment_on_copy(copy)
+ else:
+ return self.copy()
+
+ async def dispatch_error(self, ctx, error):
+ ctx.command_failed = True
+ cog = self.cog
+ try:
+ coro = self.on_error
+ except AttributeError:
+ pass
+ else:
+ injected = wrap_callback(coro)
+ if cog is not None:
+ await injected(cog, ctx, error)
+ else:
+ await injected(ctx, error)
+
+ try:
+ if cog is not None:
+ local = Cog._get_overridden_method(cog.cog_command_error)
+ if local is not None:
+ wrapped = wrap_callback(local)
+ await wrapped(ctx, error)
+ finally:
+ ctx.bot.dispatch('command_error', ctx, error)
+
+ async def _actual_conversion(self, ctx, converter, argument, param):
+ if converter is bool:
+ return _convert_to_bool(argument)
+
+ try:
+ module = converter.__module__
+ except AttributeError:
+ pass
+ else:
+ if module is not None and (module.startswith('discord.') and not module.endswith('converter')):
+ converter = getattr(converters, converter.__name__ + 'Converter', converter)
+
+ try:
+ if inspect.isclass(converter):
+ if issubclass(converter, converters.Converter):
+ instance = converter()
+ ret = await instance.convert(ctx, argument)
+ return ret
+ else:
+ method = getattr(converter, 'convert', None)
+ if method is not None and inspect.ismethod(method):
+ ret = await method(ctx, argument)
+ return ret
+ elif isinstance(converter, converters.Converter):
+ ret = await converter.convert(ctx, argument)
+ return ret
+ except CommandError:
+ raise
+ except Exception as exc:
+ raise ConversionError(converter, exc) from exc
+
+ try:
+ return converter(argument)
+ except CommandError:
+ raise
+ except Exception as exc:
+ try:
+ name = converter.__name__
+ except AttributeError:
+ name = converter.__class__.__name__
+
+ raise BadArgument('Converting to "{}" failed for parameter "{}".'.format(name, param.name)) from exc
+
+ async def do_conversion(self, ctx, converter, argument, param):
+ try:
+ origin = converter.__origin__
+ except AttributeError:
+ pass
+ else:
+ if origin is typing.Union:
+ errors = []
+ _NoneType = type(None)
+ for conv in converter.__args__:
+ # if we got to this part in the code, then the previous conversions have failed
+ # so we should just undo the view, return the default, and allow parsing to continue
+ # with the other parameters
+ if conv is _NoneType and param.kind != param.VAR_POSITIONAL:
+ ctx.view.undo()
+ return None if param.default is param.empty else param.default
+
+ try:
+ value = await self._actual_conversion(ctx, conv, argument, param)
+ except CommandError as exc:
+ errors.append(exc)
+ else:
+ return value
+
+ # if we're here, then we failed all the converters
+ raise BadUnionArgument(param, converter.__args__, errors)
+
+ return await self._actual_conversion(ctx, converter, argument, param)
+
+ def _get_converter(self, param):
+ converter = param.annotation
+ if converter is param.empty:
+ if param.default is not param.empty:
+ converter = str if param.default is None else type(param.default)
+ else:
+ converter = str
+ return converter
+
+ async def transform(self, ctx, param):
+ required = param.default is param.empty
+ converter = self._get_converter(param)
+ consume_rest_is_special = param.kind == param.KEYWORD_ONLY and not self.rest_is_raw
+ view = ctx.view
+ view.skip_ws()
+
+ # The greedy converter is simple -- it keeps going until it fails in which case,
+ # it undos the view ready for the next parameter to use instead
+ if type(converter) is converters._Greedy:
+ if param.kind == param.POSITIONAL_OR_KEYWORD or param.kind == param.POSITIONAL_ONLY:
+ return await self._transform_greedy_pos(ctx, param, required, converter.converter)
+ elif param.kind == param.VAR_POSITIONAL:
+ return await self._transform_greedy_var_pos(ctx, param, converter.converter)
+ else:
+ # if we're here, then it's a KEYWORD_ONLY param type
+ # since this is mostly useless, we'll helpfully transform Greedy[X]
+ # into just X and do the parsing that way.
+ converter = converter.converter
+
+ if view.eof:
+ if param.kind == param.VAR_POSITIONAL:
+ raise RuntimeError() # break the loop
+ if required:
+ if self._is_typing_optional(param.annotation):
+ return None
+ raise MissingRequiredArgument(param)
+ return param.default
+
+ previous = view.index
+ if consume_rest_is_special:
+ argument = view.read_rest().strip()
+ else:
+ argument = view.get_quoted_word()
+ view.previous = previous
+
+ return await self.do_conversion(ctx, converter, argument, param)
+
+ async def _transform_greedy_pos(self, ctx, param, required, converter):
+ view = ctx.view
+ result = []
+ while not view.eof:
+ # for use with a manual undo
+ previous = view.index
+
+ view.skip_ws()
+ try:
+ argument = view.get_quoted_word()
+ value = await self.do_conversion(ctx, converter, argument, param)
+ except (CommandError, ArgumentParsingError):
+ view.index = previous
+ break
+ else:
+ result.append(value)
+
+ if not result and not required:
+ return param.default
+ return result
+
+ async def _transform_greedy_var_pos(self, ctx, param, converter):
+ view = ctx.view
+ previous = view.index
+ try:
+ argument = view.get_quoted_word()
+ value = await self.do_conversion(ctx, converter, argument, param)
+ except (CommandError, ArgumentParsingError):
+ view.index = previous
+ raise RuntimeError() from None # break loop
+ else:
+ return value
+
+ @property
+ def clean_params(self):
+ """OrderedDict[:class:`str`, :class:`inspect.Parameter`]:
+ Retrieves the parameter OrderedDict without the context or self parameters.
+
+ Useful for inspecting signature.
+ """
+ result = self.params.copy()
+ if self.cog is not None:
+ # first parameter is self
+ result.popitem(last=False)
+
+ try:
+ # first/second parameter is context
+ result.popitem(last=False)
+ except Exception:
+ raise ValueError('Missing context parameter') from None
+
+ return result
+
+ @property
+ def full_parent_name(self):
+ """:class:`str`: Retrieves the fully qualified parent command name.
+
+ This the base command name required to execute it. For example,
+ in ``?one two three`` the parent name would be ``one two``.
+ """
+ entries = []
+ command = self
+ while command.parent is not None:
+ command = command.parent
+ entries.append(command.name)
+
+ return ' '.join(reversed(entries))
+
+ @property
+ def parents(self):
+ """List[:class:`Command`]: Retrieves the parents of this command.
+
+ If the command has no parents then it returns an empty :class:`list`.
+
+ For example in commands ``?a b c test``, the parents are ``[c, b, a]``.
+
+ .. versionadded:: 1.1
+ """
+ entries = []
+ command = self
+ while command.parent is not None:
+ command = command.parent
+ entries.append(command)
+
+ return entries
+
+ @property
+ def root_parent(self):
+ """Optional[:class:`Command`]: Retrieves the root parent of this command.
+
+ If the command has no parents then it returns ``None``.
+
+ For example in commands ``?a b c test``, the root parent is ``a``.
+ """
+ if not self.parent:
+ return None
+ return self.parents[-1]
+
+ @property
+ def qualified_name(self):
+ """:class:`str`: Retrieves the fully qualified command name.
+
+ This is the full parent name with the command name as well.
+ For example, in ``?one two three`` the qualified name would be
+ ``one two three``.
+ """
+
+ parent = self.full_parent_name
+ if parent:
+ return parent + ' ' + self.name
+ else:
+ return self.name
+
+ def __str__(self):
+ return self.qualified_name
+
+ async def _parse_arguments(self, ctx):
+ ctx.args = [ctx] if self.cog is None else [self.cog, ctx]
+ ctx.kwargs = {}
+ args = ctx.args
+ kwargs = ctx.kwargs
+
+ view = ctx.view
+ iterator = iter(self.params.items())
+
+ if self.cog is not None:
+ # we have 'self' as the first parameter so just advance
+ # the iterator and resume parsing
+ try:
+ next(iterator)
+ except StopIteration:
+ fmt = 'Callback for {0.name} command is missing "self" parameter.'
+ raise discord.ClientException(fmt.format(self))
+
+ # next we have the 'ctx' as the next parameter
+ try:
+ next(iterator)
+ except StopIteration:
+ fmt = 'Callback for {0.name} command is missing "ctx" parameter.'
+ raise discord.ClientException(fmt.format(self))
+
+ for name, param in iterator:
+ if param.kind == param.POSITIONAL_OR_KEYWORD or param.kind == param.POSITIONAL_ONLY:
+ transformed = await self.transform(ctx, param)
+ args.append(transformed)
+ elif param.kind == param.KEYWORD_ONLY:
+ # kwarg only param denotes "consume rest" semantics
+ if self.rest_is_raw:
+ converter = self._get_converter(param)
+ argument = view.read_rest()
+ kwargs[name] = await self.do_conversion(ctx, converter, argument, param)
+ else:
+ kwargs[name] = await self.transform(ctx, param)
+ break
+ elif param.kind == param.VAR_POSITIONAL:
+ if view.eof and self.require_var_positional:
+ raise MissingRequiredArgument(param)
+ while not view.eof:
+ try:
+ transformed = await self.transform(ctx, param)
+ args.append(transformed)
+ except RuntimeError:
+ break
+
+ if not self.ignore_extra and not view.eof:
+ raise TooManyArguments('Too many arguments passed to ' + self.qualified_name)
+
+ async def call_before_hooks(self, ctx):
+ # now that we're done preparing we can call the pre-command hooks
+ # first, call the command local hook:
+ cog = self.cog
+ if self._before_invoke is not None:
+ # should be cog if @commands.before_invoke is used
+ instance = getattr(self._before_invoke, '__self__', cog)
+ # __self__ only exists for methods, not functions
+ # however, if @command.before_invoke is used, it will be a function
+ if instance:
+ await self._before_invoke(instance, ctx)
+ else:
+ await self._before_invoke(ctx)
+
+ # call the cog local hook if applicable:
+ if cog is not None:
+ hook = Cog._get_overridden_method(cog.cog_before_invoke)
+ if hook is not None:
+ await hook(ctx)
+
+ # call the bot global hook if necessary
+ hook = ctx.bot._before_invoke
+ if hook is not None:
+ await hook(ctx)
+
+ async def call_after_hooks(self, ctx):
+ cog = self.cog
+ if self._after_invoke is not None:
+ instance = getattr(self._after_invoke, '__self__', cog)
+ if instance:
+ await self._after_invoke(instance, ctx)
+ else:
+ await self._after_invoke(ctx)
+
+ # call the cog local hook if applicable:
+ if cog is not None:
+ hook = Cog._get_overridden_method(cog.cog_after_invoke)
+ if hook is not None:
+ await hook(ctx)
+
+ hook = ctx.bot._after_invoke
+ if hook is not None:
+ await hook(ctx)
+
+ def _prepare_cooldowns(self, ctx):
+ if self._buckets.valid:
+ dt = ctx.message.edited_at or ctx.message.created_at
+ current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
+ bucket = self._buckets.get_bucket(ctx.message, current)
+ retry_after = bucket.update_rate_limit(current)
+ if retry_after:
+ raise CommandOnCooldown(bucket, retry_after)
+
+ async def prepare(self, ctx):
+ ctx.command = self
+
+ if not await self.can_run(ctx):
+ raise CheckFailure('The check functions for command {0.qualified_name} failed.'.format(self))
+
+ if self._max_concurrency is not None:
+ await self._max_concurrency.acquire(ctx)
+
+ try:
+ if self.cooldown_after_parsing:
+ await self._parse_arguments(ctx)
+ self._prepare_cooldowns(ctx)
+ else:
+ self._prepare_cooldowns(ctx)
+ await self._parse_arguments(ctx)
+
+ await self.call_before_hooks(ctx)
+ except:
+ if self._max_concurrency is not None:
+ await self._max_concurrency.release(ctx)
+ raise
+
+ def is_on_cooldown(self, ctx):
+ """Checks whether the command is currently on cooldown.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context to use when checking the commands cooldown status.
+
+ Returns
+ --------
+ :class:`bool`
+ A boolean indicating if the command is on cooldown.
+ """
+ if not self._buckets.valid:
+ return False
+
+ bucket = self._buckets.get_bucket(ctx.message)
+ dt = ctx.message.edited_at or ctx.message.created_at
+ current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
+ return bucket.get_tokens(current) == 0
+
+ def reset_cooldown(self, ctx):
+ """Resets the cooldown on this command.
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context to reset the cooldown under.
+ """
+ if self._buckets.valid:
+ bucket = self._buckets.get_bucket(ctx.message)
+ bucket.reset()
+
+ def get_cooldown_retry_after(self, ctx):
+ """Retrieves the amount of seconds before this command can be tried again.
+
+ .. versionadded:: 1.4
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The invocation context to retrieve the cooldown from.
+
+ Returns
+ --------
+ :class:`float`
+ The amount of time left on this command's cooldown in seconds.
+ If this is ``0.0`` then the command isn't on cooldown.
+ """
+ if self._buckets.valid:
+ bucket = self._buckets.get_bucket(ctx.message)
+ dt = ctx.message.edited_at or ctx.message.created_at
+ current = dt.replace(tzinfo=datetime.timezone.utc).timestamp()
+ return bucket.get_retry_after(current)
+
+ return 0.0
+
+ async def invoke(self, ctx):
+ await self.prepare(ctx)
+
+ # terminate the invoked_subcommand chain.
+ # since we're in a regular command (and not a group) then
+ # the invoked subcommand is None.
+ ctx.invoked_subcommand = None
+ ctx.subcommand_passed = None
+ injected = hooked_wrapped_callback(self, ctx, self.callback)
+ await injected(*ctx.args, **ctx.kwargs)
+
+ async def reinvoke(self, ctx, *, call_hooks=False):
+ ctx.command = self
+ await self._parse_arguments(ctx)
+
+ if call_hooks:
+ await self.call_before_hooks(ctx)
+
+ ctx.invoked_subcommand = None
+ try:
+ await self.callback(*ctx.args, **ctx.kwargs)
+ except:
+ ctx.command_failed = True
+ raise
+ finally:
+ if call_hooks:
+ await self.call_after_hooks(ctx)
+
+ def error(self, coro):
+ """A decorator that registers a coroutine as a local error handler.
+
+ A local error handler is an :func:`.on_command_error` event limited to
+ a single command. However, the :func:`.on_command_error` is still
+ invoked afterwards as the catch-all.
+
+ Parameters
+ -----------
+ coro: :ref:`coroutine `
+ The coroutine to register as the local error handler.
+
+ Raises
+ -------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('The error handler must be a coroutine.')
+
+ self.on_error = coro
+ return coro
+
+ def has_error_handler(self):
+ """:class:`bool`: Checks whether the command has an error handler registered.
+
+ .. versionadded:: 1.7
+ """
+ return hasattr(self, 'on_error')
+
+ def before_invoke(self, coro):
+ """A decorator that registers a coroutine as a pre-invoke hook.
+
+ A pre-invoke hook is called directly before the command is
+ called. This makes it a useful function to set up database
+ connections or any type of set up required.
+
+ This pre-invoke hook takes a sole parameter, a :class:`.Context`.
+
+ See :meth:`.Bot.before_invoke` for more info.
+
+ Parameters
+ -----------
+ coro: :ref:`coroutine `
+ The coroutine to register as the pre-invoke hook.
+
+ Raises
+ -------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('The pre-invoke hook must be a coroutine.')
+
+ self._before_invoke = coro
+ return coro
+
+ def after_invoke(self, coro):
+ """A decorator that registers a coroutine as a post-invoke hook.
+
+ A post-invoke hook is called directly after the command is
+ called. This makes it a useful function to clean-up database
+ connections or any type of clean up required.
+
+ This post-invoke hook takes a sole parameter, a :class:`.Context`.
+
+ See :meth:`.Bot.after_invoke` for more info.
+
+ Parameters
+ -----------
+ coro: :ref:`coroutine `
+ The coroutine to register as the post-invoke hook.
+
+ Raises
+ -------
+ TypeError
+ The coroutine passed is not actually a coroutine.
+ """
+ if not asyncio.iscoroutinefunction(coro):
+ raise TypeError('The post-invoke hook must be a coroutine.')
+
+ self._after_invoke = coro
+ return coro
+
+ @property
+ def cog_name(self):
+ """Optional[:class:`str`]: The name of the cog this command belongs to, if any."""
+ return type(self.cog).__cog_name__ if self.cog is not None else None
+
+ @property
+ def short_doc(self):
+ """:class:`str`: Gets the "short" documentation of a command.
+
+ By default, this is the :attr:`brief` attribute.
+ If that lookup leads to an empty string then the first line of the
+ :attr:`help` attribute is used instead.
+ """
+ if self.brief is not None:
+ return self.brief
+ if self.help is not None:
+ return self.help.split('\n', 1)[0]
+ return ''
+
+ def _is_typing_optional(self, annotation):
+ try:
+ origin = annotation.__origin__
+ except AttributeError:
+ return False
+
+ if origin is not typing.Union:
+ return False
+
+ return annotation.__args__[-1] is type(None)
+
+ @property
+ def signature(self):
+ """:class:`str`: Returns a POSIX-like signature useful for help command output."""
+ if self.usage is not None:
+ return self.usage
+
+
+ params = self.clean_params
+ if not params:
+ return ''
+
+ result = []
+ for name, param in params.items():
+ greedy = isinstance(param.annotation, converters._Greedy)
+
+ if param.default is not param.empty:
+ # We don't want None or '' to trigger the [name=value] case and instead it should
+ # do [name] since [name=None] or [name=] are not exactly useful for the user.
+ should_print = param.default if isinstance(param.default, str) else param.default is not None
+ if should_print:
+ result.append('[%s=%s]' % (name, param.default) if not greedy else
+ '[%s=%s]...' % (name, param.default))
+ continue
+ else:
+ result.append('[%s]' % name)
+
+ elif param.kind == param.VAR_POSITIONAL:
+ if self.require_var_positional:
+ result.append('<%s...>' % name)
+ else:
+ result.append('[%s...]' % name)
+ elif greedy:
+ result.append('[%s]...' % name)
+ elif self._is_typing_optional(param.annotation):
+ result.append('[%s]' % name)
+ else:
+ result.append('<%s>' % name)
+
+ return ' '.join(result)
+
+ async def can_run(self, ctx):
+ """|coro|
+
+ Checks if the command can be executed by checking all the predicates
+ inside the :attr:`checks` attribute. This also checks whether the
+ command is disabled.
+
+ .. versionchanged:: 1.3
+ Checks whether the command is disabled or not
+
+ Parameters
+ -----------
+ ctx: :class:`.Context`
+ The ctx of the command currently being invoked.
+
+ Raises
+ -------
+ :class:`CommandError`
+ Any command error that was raised during a check call will be propagated
+ by this function.
+
+ Returns
+ --------
+ :class:`bool`
+ A boolean indicating if the command can be invoked.
+ """
+
+ if not self.enabled:
+ raise DisabledCommand('{0.name} command is disabled'.format(self))
+
+ original = ctx.command
+ ctx.command = self
+
+ try:
+ if not await ctx.bot.can_run(ctx):
+ raise CheckFailure('The global check functions for command {0.qualified_name} failed.'.format(self))
+
+ cog = self.cog
+ if cog is not None:
+ local_check = Cog._get_overridden_method(cog.cog_check)
+ if local_check is not None:
+ ret = await discord.utils.maybe_coroutine(local_check, ctx)
+ if not ret:
+ return False
+
+ predicates = self.checks
+ if not predicates:
+ # since we have no checks, then we just return True.
+ return True
+
+ return await discord.utils.async_all(predicate(ctx) for predicate in predicates)
+ finally:
+ ctx.command = original
+
+class GroupMixin:
+ """A mixin that implements common functionality for classes that behave
+ similar to :class:`.Group` and are allowed to register commands.
+
+ Attributes
+ -----------
+ all_commands: :class:`dict`
+ A mapping of command name to :class:`.Command`
+ objects.
+ case_insensitive: :class:`bool`
+ Whether the commands should be case insensitive. Defaults to ``False``.
+ """
+ def __init__(self, *args, **kwargs):
+ case_insensitive = kwargs.get('case_insensitive', False)
+ self.all_commands = _CaseInsensitiveDict() if case_insensitive else {}
+ self.case_insensitive = case_insensitive
+ super().__init__(*args, **kwargs)
+
+ @property
+ def commands(self):
+ """Set[:class:`.Command`]: A unique set of commands without aliases that are registered."""
+ return set(self.all_commands.values())
+
+ def recursively_remove_all_commands(self):
+ for command in self.all_commands.copy().values():
+ if isinstance(command, GroupMixin):
+ command.recursively_remove_all_commands()
+ self.remove_command(command.name)
+
+ def add_command(self, command):
+ """Adds a :class:`.Command` into the internal list of commands.
+
+ This is usually not called, instead the :meth:`~.GroupMixin.command` or
+ :meth:`~.GroupMixin.group` shortcut decorators are used instead.
+
+ .. versionchanged:: 1.4
+ Raise :exc:`.CommandRegistrationError` instead of generic :exc:`.ClientException`
+
+ Parameters
+ -----------
+ command: :class:`Command`
+ The command to add.
+
+ Raises
+ -------
+ :exc:`.CommandRegistrationError`
+ If the command or its alias is already registered by different command.
+ TypeError
+ If the command passed is not a subclass of :class:`.Command`.
+ """
+
+ if not isinstance(command, Command):
+ raise TypeError('The command passed must be a subclass of Command')
+
+ if isinstance(self, Command):
+ command.parent = self
+
+ if command.name in self.all_commands:
+ raise CommandRegistrationError(command.name)
+
+ self.all_commands[command.name] = command
+ for alias in command.aliases:
+ if alias in self.all_commands:
+ self.remove_command(command.name)
+ raise CommandRegistrationError(alias, alias_conflict=True)
+ self.all_commands[alias] = command
+
+ def remove_command(self, name):
+ """Remove a :class:`.Command` from the internal list
+ of commands.
+
+ This could also be used as a way to remove aliases.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the command to remove.
+
+ Returns
+ --------
+ Optional[:class:`.Command`]
+ The command that was removed. If the name is not valid then
+ ``None`` is returned instead.
+ """
+ command = self.all_commands.pop(name, None)
+
+ # does not exist
+ if command is None:
+ return None
+
+ if name in command.aliases:
+ # we're removing an alias so we don't want to remove the rest
+ return command
+
+ # we're not removing the alias so let's delete the rest of them.
+ for alias in command.aliases:
+ cmd = self.all_commands.pop(alias, None)
+ # in the case of a CommandRegistrationError, an alias might conflict
+ # with an already existing command. If this is the case, we want to
+ # make sure the pre-existing command is not removed.
+ if cmd not in (None, command):
+ self.all_commands[alias] = cmd
+ return command
+
+ def walk_commands(self):
+ """An iterator that recursively walks through all commands and subcommands.
+
+ .. versionchanged:: 1.4
+ Duplicates due to aliases are no longer returned
+
+ Yields
+ ------
+ Union[:class:`.Command`, :class:`.Group`]
+ A command or group from the internal list of commands.
+ """
+ for command in self.commands:
+ yield command
+ if isinstance(command, GroupMixin):
+ yield from command.walk_commands()
+
+ def get_command(self, name):
+ """Get a :class:`.Command` from the internal list
+ of commands.
+
+ This could also be used as a way to get aliases.
+
+ The name could be fully qualified (e.g. ``'foo bar'``) will get
+ the subcommand ``bar`` of the group command ``foo``. If a
+ subcommand is not found then ``None`` is returned just as usual.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name of the command to get.
+
+ Returns
+ --------
+ Optional[:class:`Command`]
+ The command that was requested. If not found, returns ``None``.
+ """
+
+ # fast path, no space in name.
+ if ' ' not in name:
+ return self.all_commands.get(name)
+
+ names = name.split()
+ if not names:
+ return None
+ obj = self.all_commands.get(names[0])
+ if not isinstance(obj, GroupMixin):
+ return obj
+
+ for name in names[1:]:
+ try:
+ obj = obj.all_commands[name]
+ except (AttributeError, KeyError):
+ return None
+
+ return obj
+
+ def command(self, *args, **kwargs):
+ """A shortcut decorator that invokes :func:`.command` and adds it to
+ the internal command list via :meth:`~.GroupMixin.add_command`.
+
+ Returns
+ --------
+ Callable[..., :class:`Command`]
+ A decorator that converts the provided method into a Command, adds it to the bot, then returns it.
+ """
+ def decorator(func):
+ kwargs.setdefault('parent', self)
+ result = command(*args, **kwargs)(func)
+ self.add_command(result)
+ return result
+
+ return decorator
+
+ def group(self, *args, **kwargs):
+ """A shortcut decorator that invokes :func:`.group` and adds it to
+ the internal command list via :meth:`~.GroupMixin.add_command`.
+
+ Returns
+ --------
+ Callable[..., :class:`Group`]
+ A decorator that converts the provided method into a Group, adds it to the bot, then returns it.
+ """
+ def decorator(func):
+ kwargs.setdefault('parent', self)
+ result = group(*args, **kwargs)(func)
+ self.add_command(result)
+ return result
+
+ return decorator
+
+class Group(GroupMixin, Command):
+ """A class that implements a grouping protocol for commands to be
+ executed as subcommands.
+
+ This class is a subclass of :class:`.Command` and thus all options
+ valid in :class:`.Command` are valid in here as well.
+
+ Attributes
+ -----------
+ invoke_without_command: :class:`bool`
+ Indicates if the group callback should begin parsing and
+ invocation only if no subcommand was found. Useful for
+ making it an error handling function to tell the user that
+ no subcommand was found or to have different functionality
+ in case no subcommand was found. If this is ``False``, then
+ the group callback will always be invoked first. This means
+ that the checks and the parsing dictated by its parameters
+ will be executed. Defaults to ``False``.
+ case_insensitive: :class:`bool`
+ Indicates if the group's commands should be case insensitive.
+ Defaults to ``False``.
+ """
+ def __init__(self, *args, **attrs):
+ self.invoke_without_command = attrs.pop('invoke_without_command', False)
+ super().__init__(*args, **attrs)
+
+ def copy(self):
+ """Creates a copy of this :class:`Group`.
+
+ Returns
+ --------
+ :class:`Group`
+ A new instance of this group.
+ """
+ ret = super().copy()
+ for cmd in self.commands:
+ ret.add_command(cmd.copy())
+ return ret
+
+ async def invoke(self, ctx):
+ ctx.invoked_subcommand = None
+ ctx.subcommand_passed = None
+ early_invoke = not self.invoke_without_command
+ if early_invoke:
+ await self.prepare(ctx)
+
+ view = ctx.view
+ previous = view.index
+ view.skip_ws()
+ trigger = view.get_word()
+
+ if trigger:
+ ctx.subcommand_passed = trigger
+ ctx.invoked_subcommand = self.all_commands.get(trigger, None)
+
+ if early_invoke:
+ injected = hooked_wrapped_callback(self, ctx, self.callback)
+ await injected(*ctx.args, **ctx.kwargs)
+
+ ctx.invoked_parents.append(ctx.invoked_with)
+
+ if trigger and ctx.invoked_subcommand:
+ ctx.invoked_with = trigger
+ await ctx.invoked_subcommand.invoke(ctx)
+ elif not early_invoke:
+ # undo the trigger parsing
+ view.index = previous
+ view.previous = previous
+ await super().invoke(ctx)
+
+ async def reinvoke(self, ctx, *, call_hooks=False):
+ ctx.invoked_subcommand = None
+ early_invoke = not self.invoke_without_command
+ if early_invoke:
+ ctx.command = self
+ await self._parse_arguments(ctx)
+
+ if call_hooks:
+ await self.call_before_hooks(ctx)
+
+ view = ctx.view
+ previous = view.index
+ view.skip_ws()
+ trigger = view.get_word()
+
+ if trigger:
+ ctx.subcommand_passed = trigger
+ ctx.invoked_subcommand = self.all_commands.get(trigger, None)
+
+ if early_invoke:
+ try:
+ await self.callback(*ctx.args, **ctx.kwargs)
+ except:
+ ctx.command_failed = True
+ raise
+ finally:
+ if call_hooks:
+ await self.call_after_hooks(ctx)
+
+ ctx.invoked_parents.append(ctx.invoked_with)
+
+ if trigger and ctx.invoked_subcommand:
+ ctx.invoked_with = trigger
+ await ctx.invoked_subcommand.reinvoke(ctx, call_hooks=call_hooks)
+ elif not early_invoke:
+ # undo the trigger parsing
+ view.index = previous
+ view.previous = previous
+ await super().reinvoke(ctx, call_hooks=call_hooks)
+
+# Decorators
+
+def command(name=None, cls=None, **attrs):
+ """A decorator that transforms a function into a :class:`.Command`
+ or if called with :func:`.group`, :class:`.Group`.
+
+ By default the ``help`` attribute is received automatically from the
+ docstring of the function and is cleaned up with the use of
+ ``inspect.cleandoc``. If the docstring is ``bytes``, then it is decoded
+ into :class:`str` using utf-8 encoding.
+
+ All checks added using the :func:`.check` & co. decorators are added into
+ the function. There is no way to supply your own checks through this
+ decorator.
+
+ Parameters
+ -----------
+ name: :class:`str`
+ The name to create the command with. By default this uses the
+ function name unchanged.
+ cls
+ The class to construct with. By default this is :class:`.Command`.
+ You usually do not change this.
+ attrs
+ Keyword arguments to pass into the construction of the class denoted
+ by ``cls``.
+
+ Raises
+ -------
+ TypeError
+ If the function is not a coroutine or is already a command.
+ """
+ if cls is None:
+ cls = Command
+
+ def decorator(func):
+ if isinstance(func, Command):
+ raise TypeError('Callback is already a command.')
+ return cls(func, name=name, **attrs)
+
+ return decorator
+
+def group(name=None, **attrs):
+ """A decorator that transforms a function into a :class:`.Group`.
+
+ This is similar to the :func:`.command` decorator but the ``cls``
+ parameter is set to :class:`Group` by default.
+
+ .. versionchanged:: 1.1
+ The ``cls`` parameter can now be passed.
+ """
+
+ attrs.setdefault('cls', Group)
+ return command(name=name, **attrs)
+
+def check(predicate):
+ r"""A decorator that adds a check to the :class:`.Command` or its
+ subclasses. These checks could be accessed via :attr:`.Command.checks`.
+
+ These checks should be predicates that take in a single parameter taking
+ a :class:`.Context`. If the check returns a ``False``\-like value then
+ during invocation a :exc:`.CheckFailure` exception is raised and sent to
+ the :func:`.on_command_error` event.
+
+ If an exception should be thrown in the predicate then it should be a
+ subclass of :exc:`.CommandError`. Any exception not subclassed from it
+ will be propagated while those subclassed will be sent to
+ :func:`.on_command_error`.
+
+ A special attribute named ``predicate`` is bound to the value
+ returned by this decorator to retrieve the predicate passed to the
+ decorator. This allows the following introspection and chaining to be done:
+
+ .. code-block:: python3
+
+ def owner_or_permissions(**perms):
+ original = commands.has_permissions(**perms).predicate
+ async def extended_check(ctx):
+ if ctx.guild is None:
+ return False
+ return ctx.guild.owner_id == ctx.author.id or await original(ctx)
+ return commands.check(extended_check)
+
+ .. note::
+
+ The function returned by ``predicate`` is **always** a coroutine,
+ even if the original function was not a coroutine.
+
+ .. versionchanged:: 1.3
+ The ``predicate`` attribute was added.
+
+ Examples
+ ---------
+
+ Creating a basic check to see if the command invoker is you.
+
+ .. code-block:: python3
+
+ def check_if_it_is_me(ctx):
+ return ctx.message.author.id == 85309593344815104
+
+ @bot.command()
+ @commands.check(check_if_it_is_me)
+ async def only_for_me(ctx):
+ await ctx.send('I know you!')
+
+ Transforming common checks into its own decorator:
+
+ .. code-block:: python3
+
+ def is_me():
+ def predicate(ctx):
+ return ctx.message.author.id == 85309593344815104
+ return commands.check(predicate)
+
+ @bot.command()
+ @is_me()
+ async def only_me(ctx):
+ await ctx.send('Only you!')
+
+ Parameters
+ -----------
+ predicate: Callable[[:class:`Context`], :class:`bool`]
+ The predicate to check if the command should be invoked.
+ """
+
+ def decorator(func):
+ if isinstance(func, Command):
+ func.checks.append(predicate)
+ else:
+ if not hasattr(func, '__commands_checks__'):
+ func.__commands_checks__ = []
+
+ func.__commands_checks__.append(predicate)
+
+ return func
+
+ if inspect.iscoroutinefunction(predicate):
+ decorator.predicate = predicate
+ else:
+ @functools.wraps(predicate)
+ async def wrapper(ctx):
+ return predicate(ctx)
+ decorator.predicate = wrapper
+
+ return decorator
+
+def check_any(*checks):
+ r"""A :func:`check` that is added that checks if any of the checks passed
+ will pass, i.e. using logical OR.
+
+ If all checks fail then :exc:`.CheckAnyFailure` is raised to signal the failure.
+ It inherits from :exc:`.CheckFailure`.
+
+ .. note::
+
+ The ``predicate`` attribute for this function **is** a coroutine.
+
+ .. versionadded:: 1.3
+
+ Parameters
+ ------------
+ \*checks: Callable[[:class:`Context`], :class:`bool`]
+ An argument list of checks that have been decorated with
+ the :func:`check` decorator.
+
+ Raises
+ -------
+ TypeError
+ A check passed has not been decorated with the :func:`check`
+ decorator.
+
+ Examples
+ ---------
+
+ Creating a basic check to see if it's the bot owner or
+ the server owner:
+
+ .. code-block:: python3
+
+ def is_guild_owner():
+ def predicate(ctx):
+ return ctx.guild is not None and ctx.guild.owner_id == ctx.author.id
+ return commands.check(predicate)
+
+ @bot.command()
+ @commands.check_any(commands.is_owner(), is_guild_owner())
+ async def only_for_owners(ctx):
+ await ctx.send('Hello mister owner!')
+ """
+
+ unwrapped = []
+ for wrapped in checks:
+ try:
+ pred = wrapped.predicate
+ except AttributeError:
+ raise TypeError('%r must be wrapped by commands.check decorator' % wrapped) from None
+ else:
+ unwrapped.append(pred)
+
+ async def predicate(ctx):
+ errors = []
+ for func in unwrapped:
+ try:
+ value = await func(ctx)
+ except CheckFailure as e:
+ errors.append(e)
+ else:
+ if value:
+ return True
+ # if we're here, all checks failed
+ raise CheckAnyFailure(unwrapped, errors)
+
+ return check(predicate)
+
+def has_role(item):
+ """A :func:`.check` that is added that checks if the member invoking the
+ command has the role specified via the name or ID specified.
+
+ If a string is specified, you must give the exact name of the role, including
+ caps and spelling.
+
+ If an integer is specified, you must give the exact snowflake ID of the role.
+
+ If the message is invoked in a private message context then the check will
+ return ``False``.
+
+ This check raises one of two special exceptions, :exc:`.MissingRole` if the user
+ is missing a role, or :exc:`.NoPrivateMessage` if it is used in a private message.
+ Both inherit from :exc:`.CheckFailure`.
+
+ .. versionchanged:: 1.1
+
+ Raise :exc:`.MissingRole` or :exc:`.NoPrivateMessage`
+ instead of generic :exc:`.CheckFailure`
+
+ Parameters
+ -----------
+ item: Union[:class:`int`, :class:`str`]
+ The name or ID of the role to check.
+ """
+
+ def predicate(ctx):
+ if not isinstance(ctx.channel, discord.abc.GuildChannel):
+ raise NoPrivateMessage()
+
+ if isinstance(item, int):
+ role = discord.utils.get(ctx.author.roles, id=item)
+ else:
+ role = discord.utils.get(ctx.author.roles, name=item)
+ if role is None:
+ raise MissingRole(item)
+ return True
+
+ return check(predicate)
+
+def has_any_role(*items):
+ r"""A :func:`.check` that is added that checks if the member invoking the
+ command has **any** of the roles specified. This means that if they have
+ one out of the three roles specified, then this check will return `True`.
+
+ Similar to :func:`.has_role`\, the names or IDs passed in must be exact.
+
+ This check raises one of two special exceptions, :exc:`.MissingAnyRole` if the user
+ is missing all roles, or :exc:`.NoPrivateMessage` if it is used in a private message.
+ Both inherit from :exc:`.CheckFailure`.
+
+ .. versionchanged:: 1.1
+
+ Raise :exc:`.MissingAnyRole` or :exc:`.NoPrivateMessage`
+ instead of generic :exc:`.CheckFailure`
+
+ Parameters
+ -----------
+ items: List[Union[:class:`str`, :class:`int`]]
+ An argument list of names or IDs to check that the member has roles wise.
+
+ Example
+ --------
+
+ .. code-block:: python3
+
+ @bot.command()
+ @commands.has_any_role('Library Devs', 'Moderators', 492212595072434186)
+ async def cool(ctx):
+ await ctx.send('You are cool indeed')
+ """
+ def predicate(ctx):
+ if not isinstance(ctx.channel, discord.abc.GuildChannel):
+ raise NoPrivateMessage()
+
+ getter = functools.partial(discord.utils.get, ctx.author.roles)
+ if any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items):
+ return True
+ raise MissingAnyRole(items)
+
+ return check(predicate)
+
+def bot_has_role(item):
+ """Similar to :func:`.has_role` except checks if the bot itself has the
+ role.
+
+ This check raises one of two special exceptions, :exc:`.BotMissingRole` if the bot
+ is missing the role, or :exc:`.NoPrivateMessage` if it is used in a private message.
+ Both inherit from :exc:`.CheckFailure`.
+
+ .. versionchanged:: 1.1
+
+ Raise :exc:`.BotMissingRole` or :exc:`.NoPrivateMessage`
+ instead of generic :exc:`.CheckFailure`
+ """
+
+ def predicate(ctx):
+ ch = ctx.channel
+ if not isinstance(ch, discord.abc.GuildChannel):
+ raise NoPrivateMessage()
+
+ me = ch.guild.me
+ if isinstance(item, int):
+ role = discord.utils.get(me.roles, id=item)
+ else:
+ role = discord.utils.get(me.roles, name=item)
+ if role is None:
+ raise BotMissingRole(item)
+ return True
+ return check(predicate)
+
+def bot_has_any_role(*items):
+ """Similar to :func:`.has_any_role` except checks if the bot itself has
+ any of the roles listed.
+
+ This check raises one of two special exceptions, :exc:`.BotMissingAnyRole` if the bot
+ is missing all roles, or :exc:`.NoPrivateMessage` if it is used in a private message.
+ Both inherit from :exc:`.CheckFailure`.
+
+ .. versionchanged:: 1.1
+
+ Raise :exc:`.BotMissingAnyRole` or :exc:`.NoPrivateMessage`
+ instead of generic checkfailure
+ """
+ def predicate(ctx):
+ ch = ctx.channel
+ if not isinstance(ch, discord.abc.GuildChannel):
+ raise NoPrivateMessage()
+
+ me = ch.guild.me
+ getter = functools.partial(discord.utils.get, me.roles)
+ if any(getter(id=item) is not None if isinstance(item, int) else getter(name=item) is not None for item in items):
+ return True
+ raise BotMissingAnyRole(items)
+ return check(predicate)
+
+def has_permissions(**perms):
+ """A :func:`.check` that is added that checks if the member has all of
+ the permissions necessary.
+
+ Note that this check operates on the current channel permissions, not the
+ guild wide permissions.
+
+ The permissions passed in must be exactly like the properties shown under
+ :class:`.discord.Permissions`.
+
+ This check raises a special exception, :exc:`.MissingPermissions`
+ that is inherited from :exc:`.CheckFailure`.
+
+ Parameters
+ ------------
+ perms
+ An argument list of permissions to check for.
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ @bot.command()
+ @commands.has_permissions(manage_messages=True)
+ async def test(ctx):
+ await ctx.send('You can manage messages.')
+
+ """
+
+ invalid = set(perms) - set(discord.Permissions.VALID_FLAGS)
+ if invalid:
+ raise TypeError('Invalid permission(s): %s' % (', '.join(invalid)))
+
+ def predicate(ctx):
+ ch = ctx.channel
+ permissions = ch.permissions_for(ctx.author)
+
+ missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value]
+
+ if not missing:
+ return True
+
+ raise MissingPermissions(missing)
+
+ return check(predicate)
+
+def bot_has_permissions(**perms):
+ """Similar to :func:`.has_permissions` except checks if the bot itself has
+ the permissions listed.
+
+ This check raises a special exception, :exc:`.BotMissingPermissions`
+ that is inherited from :exc:`.CheckFailure`.
+ """
+
+ invalid = set(perms) - set(discord.Permissions.VALID_FLAGS)
+ if invalid:
+ raise TypeError('Invalid permission(s): %s' % (', '.join(invalid)))
+
+ def predicate(ctx):
+ guild = ctx.guild
+ me = guild.me if guild is not None else ctx.bot.user
+ permissions = ctx.channel.permissions_for(me)
+
+ missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value]
+
+ if not missing:
+ return True
+
+ raise BotMissingPermissions(missing)
+
+ return check(predicate)
+
+def has_guild_permissions(**perms):
+ """Similar to :func:`.has_permissions`, but operates on guild wide
+ permissions instead of the current channel permissions.
+
+ If this check is called in a DM context, it will raise an
+ exception, :exc:`.NoPrivateMessage`.
+
+ .. versionadded:: 1.3
+ """
+
+ invalid = set(perms) - set(discord.Permissions.VALID_FLAGS)
+ if invalid:
+ raise TypeError('Invalid permission(s): %s' % (', '.join(invalid)))
+
+ def predicate(ctx):
+ if not ctx.guild:
+ raise NoPrivateMessage
+
+ permissions = ctx.author.guild_permissions
+ missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value]
+
+ if not missing:
+ return True
+
+ raise MissingPermissions(missing)
+
+ return check(predicate)
+
+def bot_has_guild_permissions(**perms):
+ """Similar to :func:`.has_guild_permissions`, but checks the bot
+ members guild permissions.
+
+ .. versionadded:: 1.3
+ """
+
+ invalid = set(perms) - set(discord.Permissions.VALID_FLAGS)
+ if invalid:
+ raise TypeError('Invalid permission(s): %s' % (', '.join(invalid)))
+
+ def predicate(ctx):
+ if not ctx.guild:
+ raise NoPrivateMessage
+
+ permissions = ctx.me.guild_permissions
+ missing = [perm for perm, value in perms.items() if getattr(permissions, perm) != value]
+
+ if not missing:
+ return True
+
+ raise BotMissingPermissions(missing)
+
+ return check(predicate)
+
+def dm_only():
+ """A :func:`.check` that indicates this command must only be used in a
+ DM context. Only private messages are allowed when
+ using the command.
+
+ This check raises a special exception, :exc:`.PrivateMessageOnly`
+ that is inherited from :exc:`.CheckFailure`.
+
+ .. versionadded:: 1.1
+ """
+
+ def predicate(ctx):
+ if ctx.guild is not None:
+ raise PrivateMessageOnly()
+ return True
+
+ return check(predicate)
+
+def guild_only():
+ """A :func:`.check` that indicates this command must only be used in a
+ guild context only. Basically, no private messages are allowed when
+ using the command.
+
+ This check raises a special exception, :exc:`.NoPrivateMessage`
+ that is inherited from :exc:`.CheckFailure`.
+ """
+
+ def predicate(ctx):
+ if ctx.guild is None:
+ raise NoPrivateMessage()
+ return True
+
+ return check(predicate)
+
+def is_owner():
+ """A :func:`.check` that checks if the person invoking this command is the
+ owner of the bot.
+
+ This is powered by :meth:`.Bot.is_owner`.
+
+ This check raises a special exception, :exc:`.NotOwner` that is derived
+ from :exc:`.CheckFailure`.
+ """
+
+ async def predicate(ctx):
+ if not await ctx.bot.is_owner(ctx.author):
+ raise NotOwner('You do not own this bot.')
+ return True
+
+ return check(predicate)
+
+def is_nsfw():
+ """A :func:`.check` that checks if the channel is a NSFW channel.
+
+ This check raises a special exception, :exc:`.NSFWChannelRequired`
+ that is derived from :exc:`.CheckFailure`.
+
+ .. versionchanged:: 1.1
+
+ Raise :exc:`.NSFWChannelRequired` instead of generic :exc:`.CheckFailure`.
+ DM channels will also now pass this check.
+ """
+ def pred(ctx):
+ ch = ctx.channel
+ if ctx.guild is None or (isinstance(ch, discord.TextChannel) and ch.is_nsfw()):
+ return True
+ raise NSFWChannelRequired(ch)
+ return check(pred)
+
+def cooldown(rate, per, type=BucketType.default):
+ """A decorator that adds a cooldown to a :class:`.Command`
+
+ A cooldown allows a command to only be used a specific amount
+ of times in a specific time frame. These cooldowns can be based
+ either on a per-guild, per-channel, per-user, per-role or global basis.
+ Denoted by the third argument of ``type`` which must be of enum
+ type :class:`.BucketType`.
+
+ If a cooldown is triggered, then :exc:`.CommandOnCooldown` is triggered in
+ :func:`.on_command_error` and the local error handler.
+
+ A command can only have a single cooldown.
+
+ Parameters
+ ------------
+ rate: :class:`int`
+ The number of times a command can be used before triggering a cooldown.
+ per: :class:`float`
+ The amount of seconds to wait for a cooldown when it's been triggered.
+ type: Union[:class:`.BucketType`, Callable[[:class:`.Message`], Any]]
+ The type of cooldown to have. If callable, should return a key for the mapping.
+
+ .. versionchanged:: 1.7
+ Callables are now supported for custom bucket types.
+ """
+
+ def decorator(func):
+ if isinstance(func, Command):
+ func._buckets = CooldownMapping(Cooldown(rate, per, type))
+ else:
+ func.__commands_cooldown__ = Cooldown(rate, per, type)
+ return func
+ return decorator
+
+def max_concurrency(number, per=BucketType.default, *, wait=False):
+ """A decorator that adds a maximum concurrency to a :class:`.Command` or its subclasses.
+
+ This enables you to only allow a certain number of command invocations at the same time,
+ for example if a command takes too long or if only one user can use it at a time. This
+ differs from a cooldown in that there is no set waiting period or token bucket -- only
+ a set number of people can run the command.
+
+ .. versionadded:: 1.3
+
+ Parameters
+ -------------
+ number: :class:`int`
+ The maximum number of invocations of this command that can be running at the same time.
+ per: :class:`.BucketType`
+ The bucket that this concurrency is based on, e.g. ``BucketType.guild`` would allow
+ it to be used up to ``number`` times per guild.
+ wait: :class:`bool`
+ Whether the command should wait for the queue to be over. If this is set to ``False``
+ then instead of waiting until the command can run again, the command raises
+ :exc:`.MaxConcurrencyReached` to its error handler. If this is set to ``True``
+ then the command waits until it can be executed.
+ """
+
+ def decorator(func):
+ value = MaxConcurrency(number, per=per, wait=wait)
+ if isinstance(func, Command):
+ func._max_concurrency = value
+ else:
+ func.__commands_max_concurrency__ = value
+ return func
+ return decorator
+
+def before_invoke(coro):
+ """A decorator that registers a coroutine as a pre-invoke hook.
+
+ This allows you to refer to one before invoke hook for several commands that
+ do not have to be within the same cog.
+
+ .. versionadded:: 1.4
+
+ Example
+ ---------
+
+ .. code-block:: python3
+
+ async def record_usage(ctx):
+ print(ctx.author, 'used', ctx.command, 'at', ctx.message.created_at)
+
+ @bot.command()
+ @commands.before_invoke(record_usage)
+ async def who(ctx): # Output: used who at