diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6769e21
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,160 @@
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+*$py.class
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+build/
+develop-eggs/
+dist/
+downloads/
+eggs/
+.eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+wheels/
+share/python-wheels/
+*.egg-info/
+.installed.cfg
+*.egg
+MANIFEST
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.nox/
+.coverage
+.coverage.*
+.cache
+nosetests.xml
+coverage.xml
+*.cover
+*.py,cover
+.hypothesis/
+.pytest_cache/
+cover/
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+local_settings.py
+db.sqlite3
+db.sqlite3-journal
+
+# Flask stuff:
+instance/
+.webassets-cache
+
+# Scrapy stuff:
+.scrapy
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+.pybuilder/
+target/
+
+# Jupyter Notebook
+.ipynb_checkpoints
+
+# IPython
+profile_default/
+ipython_config.py
+
+# pyenv
+# For a library or package, you might want to ignore these files since the code is
+# intended to run in multiple environments; otherwise, check them in:
+# .python-version
+
+# pipenv
+# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
+# However, in case of collaboration, if having platform-specific dependencies or dependencies
+# having no cross-platform support, pipenv may install dependencies that don't work, or not
+# install all needed dependencies.
+#Pipfile.lock
+
+# poetry
+# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
+# This is especially recommended for binary packages to ensure reproducibility, and is more
+# commonly ignored for libraries.
+# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
+#poetry.lock
+
+# pdm
+# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
+#pdm.lock
+# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
+# in version control.
+# https://pdm.fming.dev/#use-with-ide
+.pdm.toml
+
+# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
+__pypackages__/
+
+# Celery stuff
+celerybeat-schedule
+celerybeat.pid
+
+# SageMath parsed files
+*.sage.py
+
+# Environments
+.env
+.venv
+env/
+venv/
+ENV/
+env.bak/
+venv.bak/
+
+# Spyder project settings
+.spyderproject
+.spyproject
+
+# Rope project settings
+.ropeproject
+
+# mkdocs documentation
+/site
+
+# mypy
+.mypy_cache/
+.dmypy.json
+dmypy.json
+
+# Pyre type checker
+.pyre/
+
+# pytype static type analyzer
+.pytype/
+
+# Cython debug symbols
+cython_debug/
+
+# PyCharm
+# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
+# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
+# and can be added to the global gitignore or merged into this file. For a more nuclear
+# option (not recommended) you can uncomment the following to ignore the entire idea folder.
+#.idea/
\ No newline at end of file
diff --git a/.venv/bin/activate b/.venv/bin/activate
index b8a3313..9d5eb0d 100644
--- a/.venv/bin/activate
+++ b/.venv/bin/activate
@@ -39,10 +39,10 @@ deactivate nondestructive
if [ "${OSTYPE:-}" = "cygwin" ] || [ "${OSTYPE:-}" = "msys" ] ; then
# transform D:\path\to\venv to /d/path/to/venv on MSYS
# and to /cygdrive/d/path/to/venv on Cygwin
- export VIRTUAL_ENV=$(cygpath "/home/rpetrovich/code/Misc/.venv")
+ export VIRTUAL_ENV=$(cygpath "/home/rpetrovich/code/miscellaneous/.venv")
else
# use the path as-is
- export VIRTUAL_ENV="/home/rpetrovich/code/Misc/.venv"
+ export VIRTUAL_ENV="/home/rpetrovich/code/miscellaneous/.venv"
fi
_OLD_VIRTUAL_PATH="$PATH"
diff --git a/.venv/bin/activate.csh b/.venv/bin/activate.csh
index 36652e1..edba1f3 100644
--- a/.venv/bin/activate.csh
+++ b/.venv/bin/activate.csh
@@ -9,7 +9,7 @@ alias deactivate 'test $?_OLD_VIRTUAL_PATH != 0 && setenv PATH "$_OLD_VIRTUAL_PA
# Unset irrelevant variables.
deactivate nondestructive
-setenv VIRTUAL_ENV "/home/rpetrovich/code/Misc/.venv"
+setenv VIRTUAL_ENV "/home/rpetrovich/code/miscellaneous/.venv"
set _OLD_VIRTUAL_PATH="$PATH"
setenv PATH "$VIRTUAL_ENV/bin:$PATH"
diff --git a/.venv/bin/activate.fish b/.venv/bin/activate.fish
index 6215454..3c2f55c 100644
--- a/.venv/bin/activate.fish
+++ b/.venv/bin/activate.fish
@@ -33,7 +33,7 @@ end
# Unset irrelevant variables.
deactivate nondestructive
-set -gx VIRTUAL_ENV "/home/rpetrovich/code/Misc/.venv"
+set -gx VIRTUAL_ENV "/home/rpetrovich/code/miscellaneous/.venv"
set -gx _OLD_VIRTUAL_PATH $PATH
set -gx PATH "$VIRTUAL_ENV/bin" $PATH
diff --git a/.venv/bin/normalizer b/.venv/bin/normalizer
deleted file mode 100755
index d749250..0000000
--- a/.venv/bin/normalizer
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/home/rpetrovich/code/Misc/.venv/bin/python
-# -*- coding: utf-8 -*-
-import re
-import sys
-from charset_normalizer.cli import cli_detect
-if __name__ == '__main__':
- sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
- sys.exit(cli_detect())
diff --git a/.venv/bin/pip b/.venv/bin/pip
index 67bfcbe..a67c04d 100755
--- a/.venv/bin/pip
+++ b/.venv/bin/pip
@@ -1,4 +1,4 @@
-#!/home/rpetrovich/code/Misc/.venv/bin/python
+#!/home/rpetrovich/code/miscellaneous/.venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
diff --git a/.venv/bin/pip3 b/.venv/bin/pip3
index 67bfcbe..a67c04d 100755
--- a/.venv/bin/pip3
+++ b/.venv/bin/pip3
@@ -1,4 +1,4 @@
-#!/home/rpetrovich/code/Misc/.venv/bin/python
+#!/home/rpetrovich/code/miscellaneous/.venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
diff --git a/.venv/bin/pip3.12 b/.venv/bin/pip3.12
index 67bfcbe..a67c04d 100755
--- a/.venv/bin/pip3.12
+++ b/.venv/bin/pip3.12
@@ -1,4 +1,4 @@
-#!/home/rpetrovich/code/Misc/.venv/bin/python
+#!/home/rpetrovich/code/miscellaneous/.venv/bin/python
# -*- coding: utf-8 -*-
import re
import sys
diff --git a/.venv/bin/python b/.venv/bin/python
index f140426..acd4152 120000
--- a/.venv/bin/python
+++ b/.venv/bin/python
@@ -1 +1 @@
-/bin/python
\ No newline at end of file
+/usr/bin/python
\ No newline at end of file
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/LICENSE b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/LICENSE
deleted file mode 100644
index 62b076c..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/LICENSE
+++ /dev/null
@@ -1,20 +0,0 @@
-This package contains a modified version of ca-bundle.crt:
-
-ca-bundle.crt -- Bundle of CA Root Certificates
-
-This is a bundle of X.509 certificates of public Certificate Authorities
-(CA). These were automatically extracted from Mozilla's root certificates
-file (certdata.txt). This file can be found in the mozilla source tree:
-https://hg.mozilla.org/mozilla-central/file/tip/security/nss/lib/ckfw/builtins/certdata.txt
-It contains the certificates in PEM format and therefore
-can be directly used with curl / libcurl / php_curl, or with
-an Apache+mod_ssl webserver for SSL client authentication.
-Just configure this file as the SSLCACertificateFile.#
-
-***** BEGIN LICENSE BLOCK *****
-This Source Code Form is subject to the terms of the Mozilla Public License,
-v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain
-one at http://mozilla.org/MPL/2.0/.
-
-***** END LICENSE BLOCK *****
-@(#) $RCSfile: certdata.txt,v $ $Revision: 1.80 $ $Date: 2011/11/03 15:11:58 $
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/METADATA b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/METADATA
deleted file mode 100644
index 5b357f5..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/METADATA
+++ /dev/null
@@ -1,67 +0,0 @@
-Metadata-Version: 2.1
-Name: certifi
-Version: 2024.7.4
-Summary: Python package for providing Mozilla's CA Bundle.
-Home-page: https://github.com/certifi/python-certifi
-Author: Kenneth Reitz
-Author-email: me@kennethreitz.com
-License: MPL-2.0
-Project-URL: Source, https://github.com/certifi/python-certifi
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: Mozilla Public License 2.0 (MPL 2.0)
-Classifier: Natural Language :: English
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Requires-Python: >=3.6
-License-File: LICENSE
-
-Certifi: Python SSL Certificates
-================================
-
-Certifi provides Mozilla's carefully curated collection of Root Certificates for
-validating the trustworthiness of SSL certificates while verifying the identity
-of TLS hosts. It has been extracted from the `Requests`_ project.
-
-Installation
-------------
-
-``certifi`` is available on PyPI. Simply install it with ``pip``::
-
- $ pip install certifi
-
-Usage
------
-
-To reference the installed certificate authority (CA) bundle, you can use the
-built-in function::
-
- >>> import certifi
-
- >>> certifi.where()
- '/usr/local/lib/python3.7/site-packages/certifi/cacert.pem'
-
-Or from the command line::
-
- $ python -m certifi
- /usr/local/lib/python3.7/site-packages/certifi/cacert.pem
-
-Enjoy!
-
-.. _`Requests`: https://requests.readthedocs.io/en/master/
-
-Addition/Removal of Certificates
---------------------------------
-
-Certifi does not support any addition/removal or other modification of the
-CA trust store content. This project is intended to provide a reliable and
-highly portable root of trust to python deployments. Look to upstream projects
-for methods to use alternate trust.
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/RECORD b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/RECORD
deleted file mode 100644
index fea659e..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/RECORD
+++ /dev/null
@@ -1,14 +0,0 @@
-certifi-2024.7.4.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-certifi-2024.7.4.dist-info/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989
-certifi-2024.7.4.dist-info/METADATA,sha256=L9_EuPoQQvHFzxu03_ctaEZxhEty7inz569jGWjlLGo,2221
-certifi-2024.7.4.dist-info/RECORD,,
-certifi-2024.7.4.dist-info/WHEEL,sha256=y4mX-SOX4fYIkonsAGA5N0Oy-8_gI4FXw5HNI1xqvWg,91
-certifi-2024.7.4.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8
-certifi/__init__.py,sha256=LHXz7E80YJYBzCBv6ZyidQ5-ciYSkSebpY2E5OM0l7o,94
-certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243
-certifi/__pycache__/__init__.cpython-312.pyc,,
-certifi/__pycache__/__main__.cpython-312.pyc,,
-certifi/__pycache__/core.cpython-312.pyc,,
-certifi/cacert.pem,sha256=SIupYGAr8HzGP073rsEIaS_sQYIPwzKKjj894DgUmu4,291528
-certifi/core.py,sha256=qRDDFyXVJwTB_EmoGppaXU_R9qCZvhl-EzxPMuV3nTA,4426
-certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/WHEEL
deleted file mode 100644
index 564c672..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: setuptools (70.2.0)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/top_level.txt b/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/top_level.txt
deleted file mode 100644
index 963eac5..0000000
--- a/.venv/lib/python3.12/site-packages/certifi-2024.7.4.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-certifi
diff --git a/.venv/lib/python3.12/site-packages/certifi/__init__.py b/.venv/lib/python3.12/site-packages/certifi/__init__.py
deleted file mode 100644
index d321f1b..0000000
--- a/.venv/lib/python3.12/site-packages/certifi/__init__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from .core import contents, where
-
-__all__ = ["contents", "where"]
-__version__ = "2024.07.04"
diff --git a/.venv/lib/python3.12/site-packages/certifi/__main__.py b/.venv/lib/python3.12/site-packages/certifi/__main__.py
deleted file mode 100644
index 8945b5d..0000000
--- a/.venv/lib/python3.12/site-packages/certifi/__main__.py
+++ /dev/null
@@ -1,12 +0,0 @@
-import argparse
-
-from certifi import contents, where
-
-parser = argparse.ArgumentParser()
-parser.add_argument("-c", "--contents", action="store_true")
-args = parser.parse_args()
-
-if args.contents:
- print(contents())
-else:
- print(where())
diff --git a/.venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index b599de7..0000000
Binary files a/.venv/lib/python3.12/site-packages/certifi/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc
deleted file mode 100644
index f3b6643..0000000
Binary files a/.venv/lib/python3.12/site-packages/certifi/__pycache__/__main__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc b/.venv/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc
deleted file mode 100644
index 0fdf9e9..0000000
Binary files a/.venv/lib/python3.12/site-packages/certifi/__pycache__/core.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/certifi/cacert.pem b/.venv/lib/python3.12/site-packages/certifi/cacert.pem
deleted file mode 100644
index a658158..0000000
--- a/.venv/lib/python3.12/site-packages/certifi/cacert.pem
+++ /dev/null
@@ -1,4798 +0,0 @@
-
-# Issuer: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Subject: CN=GlobalSign Root CA O=GlobalSign nv-sa OU=Root CA
-# Label: "GlobalSign Root CA"
-# Serial: 4835703278459707669005204
-# MD5 Fingerprint: 3e:45:52:15:09:51:92:e1:b7:5d:37:9f:b1:87:29:8a
-# SHA1 Fingerprint: b1:bc:96:8b:d4:f4:9d:62:2a:a8:9a:81:f2:15:01:52:a4:1d:82:9c
-# SHA256 Fingerprint: eb:d4:10:40:e4:bb:3e:c7:42:c9:e3:81:d3:1e:f2:a4:1a:48:b6:68:5c:96:e7:ce:f3:c1:df:6c:d4:33:1c:99
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
-aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
-jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
-xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
-1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
-snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
-U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
-AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
-yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
-38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
-AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
-DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
-HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Subject: CN=Entrust.net Certification Authority (2048) O=Entrust.net OU=www.entrust.net/CPS_2048 incorp. by ref. (limits liab.)/(c) 1999 Entrust.net Limited
-# Label: "Entrust.net Premium 2048 Secure Server CA"
-# Serial: 946069240
-# MD5 Fingerprint: ee:29:31:bc:32:7e:9a:e6:e8:b5:f7:51:b4:34:71:90
-# SHA1 Fingerprint: 50:30:06:09:1d:97:d4:f5:ae:39:f7:cb:e7:92:7d:7d:65:2d:34:31
-# SHA256 Fingerprint: 6d:c4:71:72:e0:1c:bc:b0:bf:62:58:0d:89:5f:e2:b8:ac:9a:d4:f8:73:80:1e:0c:10:b9:c8:37:d2:1e:b1:77
------BEGIN CERTIFICATE-----
-MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
-RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
-bmNvcnAuIGJ5IHJlZi4gKGxpbWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5
-IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNVBAMTKkVudHJ1c3QubmV0IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQxNzUwNTFaFw0yOTA3
-MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3d3d3
-LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxp
-YWIuKTElMCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEG
-A1UEAxMqRW50cnVzdC5uZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgp
-MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArU1LqRKGsuqjIAcVFmQq
-K0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOLGp18EzoOH1u3Hs/lJBQe
-sYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSrhRSGlVuX
-MlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVT
-XTzWnLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/
-HoZdenoVve8AjhUiVBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH
-4QIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJKoZIhvcNAQEFBQADggEBADub
-j1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPyT/4xmf3IDExo
-U8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf
-zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5b
-u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
-bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
-fF6adulZkMV8gzURZVE=
------END CERTIFICATE-----
-
-# Issuer: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Subject: CN=Baltimore CyberTrust Root O=Baltimore OU=CyberTrust
-# Label: "Baltimore CyberTrust Root"
-# Serial: 33554617
-# MD5 Fingerprint: ac:b6:94:a5:9c:17:e0:d7:91:52:9b:b1:97:06:a6:e4
-# SHA1 Fingerprint: d4:de:20:d0:5e:66:fc:53:fe:1a:50:88:2c:78:db:28:52:ca:e4:74
-# SHA256 Fingerprint: 16:af:57:a9:f6:76:b0:ab:12:60:95:aa:5e:ba:de:f2:2a:b3:11:19:d6:44:ac:95:cd:4b:93:db:f3:f2:6a:eb
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
-RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
-VQQDExlCYWx0aW1vcmUgQ3liZXJUcnVzdCBSb290MB4XDTAwMDUxMjE4NDYwMFoX
-DTI1MDUxMjIzNTkwMFowWjELMAkGA1UEBhMCSUUxEjAQBgNVBAoTCUJhbHRpbW9y
-ZTETMBEGA1UECxMKQ3liZXJUcnVzdDEiMCAGA1UEAxMZQmFsdGltb3JlIEN5YmVy
-VHJ1c3QgUm9vdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKMEuyKr
-mD1X6CZymrV51Cni4eiVgLGw41uOKymaZN+hXe2wCQVt2yguzmKiYv60iNoS6zjr
-IZ3AQSsBUnuId9Mcj8e6uYi1agnnc+gRQKfRzMpijS3ljwumUNKoUMMo6vWrJYeK
-mpYcqWe4PwzV9/lSEy/CG9VwcPCPwBLKBsua4dnKM3p31vjsufFoREJIE9LAwqSu
-XmD+tqYF/LTdB1kC1FkYmGP1pWPgkAx9XbIGevOF6uvUA65ehD5f/xXtabz5OTZy
-dc93Uk3zyZAsuT3lySNTPx8kmCFcB5kpvcY67Oduhjprl3RjM71oGDHweI12v/ye
-jl0qhqdNkNwnGjkCAwEAAaNFMEMwHQYDVR0OBBYEFOWdWTCCR1jMrPoIVDaGezq1
-BE3wMBIGA1UdEwEB/wQIMAYBAf8CAQMwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3
-DQEBBQUAA4IBAQCFDF2O5G9RaEIFoN27TyclhAO992T9Ldcw46QQF+vaKSm2eT92
-9hkTI7gQCvlYpNRhcL0EYWoSihfVCr3FvDB81ukMJY2GQE/szKN+OMY3EU/t3Wgx
-jkzSswF07r51XgdIGn9w/xZchMB5hbgF/X++ZRGjD8ACtPhSNzkE1akxehi/oCr0
-Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
-ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
-R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Subject: CN=Entrust Root Certification Authority O=Entrust, Inc. OU=www.entrust.net/CPS is incorporated by reference/(c) 2006 Entrust, Inc.
-# Label: "Entrust Root Certification Authority"
-# Serial: 1164660820
-# MD5 Fingerprint: d6:a5:c3:ed:5d:dd:3e:00:c1:3d:87:92:1f:1d:3f:e4
-# SHA1 Fingerprint: b3:1e:b1:b7:40:e3:6c:84:02:da:dc:37:d4:4d:f5:d4:67:49:52:f9
-# SHA256 Fingerprint: 73:c1:76:43:4f:1b:c6:d5:ad:f4:5b:0e:76:e7:27:28:7c:8d:e5:76:16:c1:e6:e6:14:1a:2b:2c:bc:7d:8e:4c
------BEGIN CERTIFICATE-----
-MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
-VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
-Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
-KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
-NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
-NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
-ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
-BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
-Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
-4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
-KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
-rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
-94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
-sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
-gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
-kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
-vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
-A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
-O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
-AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
-9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
-eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
-0vdXcDazv/wor3ElhVsT/h5/WrQ8
------END CERTIFICATE-----
-
-# Issuer: CN=AAA Certificate Services O=Comodo CA Limited
-# Subject: CN=AAA Certificate Services O=Comodo CA Limited
-# Label: "Comodo AAA Services root"
-# Serial: 1
-# MD5 Fingerprint: 49:79:04:b0:eb:87:19:ac:47:b0:bc:11:51:9b:74:d0
-# SHA1 Fingerprint: d1:eb:23:a4:6d:17:d6:8f:d9:25:64:c2:f1:f1:60:17:64:d8:e3:49
-# SHA256 Fingerprint: d7:a7:a0:fb:5d:7e:27:31:d7:71:e9:48:4e:bc:de:f7:1d:5f:0c:3e:0a:29:48:78:2b:c8:3e:e0:ea:69:9e:f4
------BEGIN CERTIFICATE-----
-MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
-MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
-GAYDVQQKDBFDb21vZG8gQ0EgTGltaXRlZDEhMB8GA1UEAwwYQUFBIENlcnRpZmlj
-YXRlIFNlcnZpY2VzMB4XDTA0MDEwMTAwMDAwMFoXDTI4MTIzMTIzNTk1OVowezEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgMEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BwwHU2FsZm9yZDEaMBgGA1UECgwRQ29tb2RvIENBIExpbWl0ZWQxITAfBgNVBAMM
-GEFBQSBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczCCASIwDQYJKoZIhvcNAQEBBQADggEP
-ADCCAQoCggEBAL5AnfRu4ep2hxxNRUSOvkbIgwadwSr+GB+O5AL686tdUIoWMQua
-BtDFcCLNSS1UY8y2bmhGC1Pqy0wkwLxyTurxFa70VJoSCsN6sjNg4tqJVfMiWPPe
-3M/vg4aijJRPn2jymJBGhCfHdr/jzDUsi14HZGWCwEiwqJH5YZ92IFCokcdmtet4
-YgNW8IoaE+oxox6gmf049vYnMlhvB/VruPsUK6+3qszWY19zjNoFmag4qMsXeDZR
-rOme9Hg6jc8P2ULimAyrL58OAd7vn5lJ8S3frHRNG5i1R8XlKdH5kBjHYpy+g8cm
-ez6KJcfA3Z3mNWgQIJ2P2N7Sw4ScDV7oL8kCAwEAAaOBwDCBvTAdBgNVHQ4EFgQU
-oBEKIz6W8Qfs4q8p74Klf9AwpLQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQF
-MAMBAf8wewYDVR0fBHQwcjA4oDagNIYyaHR0cDovL2NybC5jb21vZG9jYS5jb20v
-QUFBQ2VydGlmaWNhdGVTZXJ2aWNlcy5jcmwwNqA0oDKGMGh0dHA6Ly9jcmwuY29t
-b2RvLm5ldC9BQUFDZXJ0aWZpY2F0ZVNlcnZpY2VzLmNybDANBgkqhkiG9w0BAQUF
-AAOCAQEACFb8AvCb6P+k+tZ7xkSAzk/ExfYAWMymtrwUSWgEdujm7l3sAg9g1o1Q
-GE8mTgHj5rCl7r+8dFRBv/38ErjHT1r0iWAFf2C3BUrz9vHCv8S5dIa2LX1rzNLz
-Rt0vxuBqw8M0Ayx9lt1awg6nCpnBBYurDC/zXDrPbDdVCYfeU0BsWO/8tqtlbgT2
-G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
-l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
-smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
------END CERTIFICATE-----
-
-# Issuer: CN=QuoVadis Root CA 2 O=QuoVadis Limited
-# Subject: CN=QuoVadis Root CA 2 O=QuoVadis Limited
-# Label: "QuoVadis Root CA 2"
-# Serial: 1289
-# MD5 Fingerprint: 5e:39:7b:dd:f8:ba:ec:82:e9:ac:62:ba:0c:54:00:2b
-# SHA1 Fingerprint: ca:3a:fb:cf:12:40:36:4b:44:b2:16:20:88:80:48:39:19:93:7c:f7
-# SHA256 Fingerprint: 85:a0:dd:7d:d7:20:ad:b7:ff:05:f8:3d:54:2b:20:9d:c7:ff:45:28:f7:d6:77:b1:83:89:fe:a5:e5:c4:9e:86
------BEGIN CERTIFICATE-----
-MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
-GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
-b3QgQ0EgMjAeFw0wNjExMjQxODI3MDBaFw0zMTExMjQxODIzMzNaMEUxCzAJBgNV
-BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
-YWRpcyBSb290IENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCa
-GMpLlA0ALa8DKYrwD4HIrkwZhR0In6spRIXzL4GtMh6QRr+jhiYaHv5+HBg6XJxg
-Fyo6dIMzMH1hVBHL7avg5tKifvVrbxi3Cgst/ek+7wrGsxDp3MJGF/hd/aTa/55J
-WpzmM+Yklvc/ulsrHHo1wtZn/qtmUIttKGAr79dgw8eTvI02kfN/+NsRE8Scd3bB
-rrcCaoF6qUWD4gXmuVbBlDePSHFjIuwXZQeVikvfj8ZaCuWw419eaxGrDPmF60Tp
-+ARz8un+XJiM9XOva7R+zdRcAitMOeGylZUtQofX1bOQQ7dsE/He3fbE+Ik/0XX1
-ksOR1YqI0JDs3G3eicJlcZaLDQP9nL9bFqyS2+r+eXyt66/3FsvbzSUr5R/7mp/i
-Ucw6UwxI5g69ybR2BlLmEROFcmMDBOAENisgGQLodKcftslWZvB1JdxnwQ5hYIiz
-PtGo/KPaHbDRsSNU30R2be1B2MGyIrZTHN81Hdyhdyox5C315eXbyOD/5YDXC2Og
-/zOhD7osFRXql7PSorW+8oyWHhqPHWykYTe5hnMz15eWniN9gqRMgeKh0bpnX5UH
-oycR7hYQe7xFSkyyBNKr79X9DFHOUGoIMfmR2gyPZFwDwzqLID9ujWc9Otb+fVuI
-yV77zGHcizN300QyNQliBJIWENieJ0f7OyHj+OsdWwIDAQABo4GwMIGtMA8GA1Ud
-EwEB/wQFMAMBAf8wCwYDVR0PBAQDAgEGMB0GA1UdDgQWBBQahGK8SEwzJQTU7tD2
-A8QZRtGUazBuBgNVHSMEZzBlgBQahGK8SEwzJQTU7tD2A8QZRtGUa6FJpEcwRTEL
-MAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMT
-ElF1b1ZhZGlzIFJvb3QgQ0EgMoICBQkwDQYJKoZIhvcNAQEFBQADggIBAD4KFk2f
-BluornFdLwUvZ+YTRYPENvbzwCYMDbVHZF34tHLJRqUDGCdViXh9duqWNIAXINzn
-g/iN/Ae42l9NLmeyhP3ZRPx3UIHmfLTJDQtyU/h2BwdBR5YM++CCJpNVjP4iH2Bl
-fF/nJrP3MpCYUNQ3cVX2kiF495V5+vgtJodmVjB3pjd4M1IQWK4/YY7yarHvGH5K
-WWPKjaJW1acvvFYfzznB4vsKqBUsfU16Y8Zsl0Q80m/DShcK+JDSV6IZUaUtl0Ha
-B0+pUNqQjZRG4T7wlP0QADj1O+hA4bRuVhogzG9Yje0uRY/W6ZM/57Es3zrWIozc
-hLsib9D45MY56QSIPMO661V6bYCZJPVsAfv4l7CUW+v90m/xd2gNNWQjrLhVoQPR
-TUIZ3Ph1WVaj+ahJefivDrkRoHy3au000LYmYjgahwz46P0u05B/B5EqHdZ+XIWD
-mbA4CD/pXvk1B+TJYm5Xf6dQlfe6yJvmjqIBxdZmv3lh8zwc4bmCXF2gw+nYSL0Z
-ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
-4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
-8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
------END CERTIFICATE-----
-
-# Issuer: CN=QuoVadis Root CA 3 O=QuoVadis Limited
-# Subject: CN=QuoVadis Root CA 3 O=QuoVadis Limited
-# Label: "QuoVadis Root CA 3"
-# Serial: 1478
-# MD5 Fingerprint: 31:85:3c:62:94:97:63:b9:aa:fd:89:4e:af:6f:e0:cf
-# SHA1 Fingerprint: 1f:49:14:f7:d8:74:95:1d:dd:ae:02:c0:be:fd:3a:2d:82:75:51:85
-# SHA256 Fingerprint: 18:f1:fc:7f:20:5d:f8:ad:dd:eb:7f:e0:07:dd:57:e3:af:37:5a:9c:4d:8d:73:54:6b:f4:f1:fe:d1:e1:8d:35
------BEGIN CERTIFICATE-----
-MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
-GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
-b3QgQ0EgMzAeFw0wNjExMjQxOTExMjNaFw0zMTExMjQxOTA2NDRaMEUxCzAJBgNV
-BAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBMaW1pdGVkMRswGQYDVQQDExJRdW9W
-YWRpcyBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDM
-V0IWVJzmmNPTTe7+7cefQzlKZbPoFog02w1ZkXTPkrgEQK0CSzGrvI2RaNggDhoB
-4hp7Thdd4oq3P5kazethq8Jlph+3t723j/z9cI8LoGe+AaJZz3HmDyl2/7FWeUUr
-H556VOijKTVopAFPD6QuN+8bv+OPEKhyq1hX51SGyMnzW9os2l2ObjyjPtr7guXd
-8lyyBTNvijbO0BNO/79KDDRMpsMhvVAEVeuxu537RR5kFd5VAYwCdrXLoT9Cabwv
-vWhDFlaJKjdhkf2mrk7AyxRllDdLkgbvBNDInIjbC3uBr7E9KsRlOni27tyAsdLT
-mZw67mtaa7ONt9XOnMK+pUsvFrGeaDsGb659n/je7Mwpp5ijJUMv7/FfJuGITfhe
-btfZFG4ZM2mnO4SJk8RTVROhUXhA+LjJou57ulJCg54U7QVSWllWp5f8nT8KKdjc
-T5EOE7zelaTfi5m+rJsziO+1ga8bxiJTyPbH7pcUsMV8eFLI8M5ud2CEpukqdiDt
-WAEXMJPpGovgc2PZapKUSU60rUqFxKMiMPwJ7Wgic6aIDFUhWMXhOp8q3crhkODZ
-c6tsgLjoC2SToJyMGf+z0gzskSaHirOi4XCPLArlzW1oUevaPwV/izLmE1xr/l9A
-4iLItLRkT9a6fUg+qGkM17uGcclzuD87nSVL2v9A6wIDAQABo4IBlTCCAZEwDwYD
-VR0TAQH/BAUwAwEB/zCB4QYDVR0gBIHZMIHWMIHTBgkrBgEEAb5YAAMwgcUwgZMG
-CCsGAQUFBwICMIGGGoGDQW55IHVzZSBvZiB0aGlzIENlcnRpZmljYXRlIGNvbnN0
-aXR1dGVzIGFjY2VwdGFuY2Ugb2YgdGhlIFF1b1ZhZGlzIFJvb3QgQ0EgMyBDZXJ0
-aWZpY2F0ZSBQb2xpY3kgLyBDZXJ0aWZpY2F0aW9uIFByYWN0aWNlIFN0YXRlbWVu
-dC4wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucXVvdmFkaXNnbG9iYWwuY29tL2Nw
-czALBgNVHQ8EBAMCAQYwHQYDVR0OBBYEFPLAE+CCQz777i9nMpY1XNu4ywLQMG4G
-A1UdIwRnMGWAFPLAE+CCQz777i9nMpY1XNu4ywLQoUmkRzBFMQswCQYDVQQGEwJC
-TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDEbMBkGA1UEAxMSUXVvVmFkaXMg
-Um9vdCBDQSAzggIFxjANBgkqhkiG9w0BAQUFAAOCAgEAT62gLEz6wPJv92ZVqyM0
-7ucp2sNbtrCD2dDQ4iH782CnO11gUyeim/YIIirnv6By5ZwkajGxkHon24QRiSem
-d1o417+shvzuXYO8BsbRd2sPbSQvS3pspweWyuOEn62Iix2rFo1bZhfZFvSLgNLd
-+LJ2w/w4E6oM3kJpK27zPOuAJ9v1pkQNn1pVWQvVDVJIxa6f8i+AxeoyUDUSly7B
-4f/xI4hROJ/yZlZ25w9Rl6VSDE1JUZU2Pb+iSwwQHYaZTKrzchGT5Or2m9qoXadN
-t54CrnMAyNojA+j56hl0YgCUyyIgvpSnWbWCar6ZeXqp8kokUvd0/bpO5qgdAm6x
-DYBEwa7TIzdfu4V8K5Iu6H6li92Z4b8nby1dqnuH/grdS/yO9SbkbnBCbjPsMZ57
-k8HkyWkaPcBrTiJt7qtYTcbQQcEr6k8Sh17rRdhs9ZgC06DYVYoGmRmioHfRMJ6s
-zHXug/WwYjnPbFfiTNKRCw51KBuav/0aQ/HKd/s7j2G4aSgWQgRecCocIdiP4b0j
-Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
-mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
-4SVhM7JZG+Ju1zdXtg2pEto=
------END CERTIFICATE-----
-
-# Issuer: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Subject: CN=XRamp Global Certification Authority O=XRamp Security Services Inc OU=www.xrampsecurity.com
-# Label: "XRamp Global CA Root"
-# Serial: 107108908803651509692980124233745014957
-# MD5 Fingerprint: a1:0b:44:b3:ca:10:d8:00:6e:9d:0f:d8:0f:92:0a:d1
-# SHA1 Fingerprint: b8:01:86:d1:eb:9c:86:a5:41:04:cf:30:54:f3:4c:52:b7:e5:58:c6
-# SHA256 Fingerprint: ce:cd:dc:90:50:99:d8:da:df:c5:b1:d2:09:b7:37:cb:e2:c1:8c:fb:2c:10:c0:ff:0b:cf:0d:32:86:fc:1a:a2
------BEGIN CERTIFICATE-----
-MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
-gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
-MCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2VydmljZXMgSW5jMS0wKwYDVQQDEyRY
-UmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQxMTAxMTcx
-NDA0WhcNMzUwMTAxMDUzNzE5WjCBgjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3
-dy54cmFtcHNlY3VyaXR5LmNvbTEkMCIGA1UEChMbWFJhbXAgU2VjdXJpdHkgU2Vy
-dmljZXMgSW5jMS0wKwYDVQQDEyRYUmFtcCBHbG9iYWwgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCYJB69FbS6
-38eMpSe2OAtp87ZOqCwuIR1cRN8hXX4jdP5efrRKt6atH67gBhbim1vZZ3RrXYCP
-KZ2GG9mcDZhtdhAoWORlsH9KmHmf4MMxfoArtYzAQDsRhtDLooY2YKTVMIJt2W7Q
-DxIEM5dfT2Fa8OT5kavnHTu86M/0ay00fOJIYRyO82FEzG+gSqmUsE3a56k0enI4
-qEHMPJQRfevIpoy3hsvKMzvZPTeL+3o+hiznc9cKV6xkmxnr9A8ECIqsAxcZZPRa
-JSKNNCyy9mgdEm3Tih4U2sSPpuIjhdV6Db1q4Ons7Be7QhtnqiXtRYMh/MHJfNVi
-PvryxS3T/dRlAgMBAAGjgZ8wgZwwEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0P
-BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMZPoj0GY4QJnM5i5ASs
-jVy16bYbMDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly9jcmwueHJhbXBzZWN1cml0
-eS5jb20vWEdDQS5jcmwwEAYJKwYBBAGCNxUBBAMCAQEwDQYJKoZIhvcNAQEFBQAD
-ggEBAJEVOQMBG2f7Shz5CmBbodpNl2L5JFMn14JkTpAuw0kbK5rc/Kh4ZzXxHfAR
-vbdI4xD2Dd8/0sm2qlWkSLoC295ZLhVbO50WfUfXN+pfTXYSNrsf16GBBEYgoyxt
-qZ4Bfj8pzgCT3/3JknOJiWSe5yvkHJEs0rnOfc5vMZnT5r7SHpDwCRR5XCOrTdLa
-IR9NmXmd4c8nnxCbHIgNsIpkQTG4DmyQJKSbXHGPurt+HBvbaoAPIbzp26a3QPSy
-i6mx5O+aGtA9aZnuqCij4Tyz8LIRnM98QObd50N9otg6tamN8jSZxNQQ4Qb9CYQQ
-O+7ETPTsJ3xCwnR8gooJybQDJbw=
------END CERTIFICATE-----
-
-# Issuer: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Subject: O=The Go Daddy Group, Inc. OU=Go Daddy Class 2 Certification Authority
-# Label: "Go Daddy Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 91:de:06:25:ab:da:fd:32:17:0c:bb:25:17:2a:84:67
-# SHA1 Fingerprint: 27:96:ba:e6:3f:18:01:e2:77:26:1b:a0:d7:77:70:02:8f:20:ee:e4
-# SHA256 Fingerprint: c3:84:6b:f2:4b:9e:93:ca:64:27:4c:0e:c6:7c:1e:cc:5e:02:4f:fc:ac:d2:d7:40:19:35:0e:81:fe:54:6a:e4
------BEGIN CERTIFICATE-----
-MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
-MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
-YWRkeSBDbGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA0MDYyOTE3
-MDYyMFoXDTM0MDYyOTE3MDYyMFowYzELMAkGA1UEBhMCVVMxITAfBgNVBAoTGFRo
-ZSBHbyBEYWRkeSBHcm91cCwgSW5jLjExMC8GA1UECxMoR28gRGFkZHkgQ2xhc3Mg
-MiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASAwDQYJKoZIhvcNAQEBBQADggEN
-ADCCAQgCggEBAN6d1+pXGEmhW+vXX0iG6r7d/+TvZxz0ZWizV3GgXne77ZtJ6XCA
-PVYYYwhv2vLM0D9/AlQiVBDYsoHUwHU9S3/Hd8M+eKsaA7Ugay9qK7HFiH7Eux6w
-wdhFJ2+qN1j3hybX2C32qRe3H3I2TqYXP2WYktsqbl2i/ojgC95/5Y0V4evLOtXi
-EqITLdiOr18SPaAIBQi2XKVlOARFmR6jYGB0xUGlcmIbYsUfb18aQr4CUWWoriMY
-avx4A6lNf4DD+qta/KFApMoZFv6yyO9ecw3ud72a9nmYvLEHZ6IVDd2gWMZEewo+
-YihfukEHU1jPEX44dMX4/7VpkI+EdOqXG68CAQOjgcAwgb0wHQYDVR0OBBYEFNLE
-sNKR1EwRcbNhyz2h/t2oatTjMIGNBgNVHSMEgYUwgYKAFNLEsNKR1EwRcbNhyz2h
-/t2oatTjoWekZTBjMQswCQYDVQQGEwJVUzEhMB8GA1UEChMYVGhlIEdvIERhZGR5
-IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBEYWRkeSBDbGFzcyAyIENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQEFBQAD
-ggEBADJL87LKPpH8EsahB4yOd6AzBhRckB4Y9wimPQoZ+YeAEW5p5JYXMP80kWNy
-OO7MHAGjHZQopDH2esRU1/blMVgDoszOYtuURXO1v0XJJLXVggKtI3lpjbi2Tc7P
-TMozI+gciKqdi0FuFskg5YmezTvacPd+mSYgFFQlq25zheabIZ0KbIIOqPjCDPoQ
-HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
-dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
-ReYNnyicsbkqWletNw+vHX/bvZ8=
------END CERTIFICATE-----
-
-# Issuer: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Subject: O=Starfield Technologies, Inc. OU=Starfield Class 2 Certification Authority
-# Label: "Starfield Class 2 CA"
-# Serial: 0
-# MD5 Fingerprint: 32:4a:4b:bb:c8:63:69:9b:be:74:9a:c6:dd:1d:46:24
-# SHA1 Fingerprint: ad:7e:1c:28:b0:64:ef:8f:60:03:40:20:14:c3:d0:e3:37:0e:b5:8a
-# SHA256 Fingerprint: 14:65:fa:20:53:97:b8:76:fa:a6:f0:a9:95:8e:55:90:e4:0f:cc:7f:aa:4f:b7:c2:c8:67:75:21:fb:5f:b6:58
------BEGIN CERTIFICATE-----
-MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
-MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
-U3RhcmZpZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDQw
-NjI5MTczOTE2WhcNMzQwNjI5MTczOTE2WjBoMQswCQYDVQQGEwJVUzElMCMGA1UE
-ChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMpU3RhcmZp
-ZWxkIENsYXNzIDIgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggEgMA0GCSqGSIb3
-DQEBAQUAA4IBDQAwggEIAoIBAQC3Msj+6XGmBIWtDBFk385N78gDGIc/oav7PKaf
-8MOh2tTYbitTkPskpD6E8J7oX+zlJ0T1KKY/e97gKvDIr1MvnsoFAZMej2YcOadN
-+lq2cwQlZut3f+dZxkqZJRRU6ybH838Z1TBwj6+wRir/resp7defqgSHo9T5iaU0
-X9tDkYI22WY8sbi5gv2cOj4QyDvvBmVmepsZGD3/cVE8MC5fvj13c7JdBmzDI1aa
-K4UmkhynArPkPw2vCHmCuDY96pzTNbO8acr1zJ3o/WSNF4Azbl5KXZnJHoe0nRrA
-1W4TNSNe35tfPe/W93bC6j67eA0cQmdrBNj41tpvi/JEoAGrAgEDo4HFMIHCMB0G
-A1UdDgQWBBS/X7fRzt0fhvRbVazc1xDCDqmI5zCBkgYDVR0jBIGKMIGHgBS/X7fR
-zt0fhvRbVazc1xDCDqmI56FspGowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0
-YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBD
-bGFzcyAyIENlcnRpZmljYXRpb24gQXV0aG9yaXR5ggEAMAwGA1UdEwQFMAMBAf8w
-DQYJKoZIhvcNAQEFBQADggEBAAWdP4id0ckaVaGsafPzWdqbAYcaT1epoXkJKtv3
-L7IezMdeatiDh6GX70k1PncGQVhiv45YuApnP+yz3SFmH8lU+nLMPUxA2IGvd56D
-eruix/U0F47ZEUD0/CwqTRV/p2JdLiXTAAsgGh1o+Re49L2L7ShZ3U0WixeDyLJl
-xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
-VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
-WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Assured ID Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Assured ID Root CA"
-# Serial: 17154717934120587862167794914071425081
-# MD5 Fingerprint: 87:ce:0b:7b:2a:0e:49:00:e1:58:71:9b:37:a8:93:72
-# SHA1 Fingerprint: 05:63:b8:63:0d:62:d7:5a:bb:c8:ab:1e:4b:df:b5:a8:99:b2:4d:43
-# SHA256 Fingerprint: 3e:90:99:b5:01:5e:8f:48:6c:00:bc:ea:9d:11:1e:e7:21:fa:ba:35:5a:89:bc:f1:df:69:56:1e:3d:c6:32:5c
------BEGIN CERTIFICATE-----
-MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
-b3QgQ0EwHhcNMDYxMTEwMDAwMDAwWhcNMzExMTEwMDAwMDAwWjBlMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
-cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgQ0EwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCtDhXO5EOAXLGH87dg+XESpa7c
-JpSIqvTO9SA5KFhgDPiA2qkVlTJhPLWxKISKityfCgyDF3qPkKyK53lTXDGEKvYP
-mDI2dsze3Tyoou9q+yHyUmHfnyDXH+Kx2f4YZNISW1/5WBg1vEfNoTb5a3/UsDg+
-wRvDjDPZ2C8Y/igPs6eD1sNuRMBhNZYW/lmci3Zt1/GiSw0r/wty2p5g0I6QNcZ4
-VYcgoc/lbQrISXwxmDNsIumH0DJaoroTghHtORedmTpyoeb6pNnVFzF1roV9Iq4/
-AUaG9ih5yLHa5FcXxH4cDrC0kqZWs72yl+2qp/C3xag/lRbQ/6GW6whfGHdPAgMB
-AAGjYzBhMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
-BBRF66Kv9JLLgjEtUYunpyGd823IDzAfBgNVHSMEGDAWgBRF66Kv9JLLgjEtUYun
-pyGd823IDzANBgkqhkiG9w0BAQUFAAOCAQEAog683+Lt8ONyc3pklL/3cmbYMuRC
-dWKuh+vy1dneVrOfzM4UKLkNl2BcEkxY5NM9g0lFWJc1aRqoR+pWxnmrEthngYTf
-fwk8lOa4JiwgvT2zKIn3X/8i4peEH+ll74fg38FnSbNd67IJKusm7Xi+fT8r87cm
-NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
-H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
-+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Global Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Global Root CA"
-# Serial: 10944719598952040374951832963794454346
-# MD5 Fingerprint: 79:e4:a9:84:0d:7d:3a:96:d7:c0:4f:e2:43:4c:89:2e
-# SHA1 Fingerprint: a8:98:5d:3a:65:e5:e5:c4:b2:d7:d6:6d:40:c6:dd:2f:b1:9c:54:36
-# SHA256 Fingerprint: 43:48:a0:e9:44:4c:78:cb:26:5e:05:8d:5e:89:44:b4:d8:4f:96:62:bd:26:db:25:7f:89:34:a4:43:c7:01:61
------BEGIN CERTIFICATE-----
-MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
-QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
-b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
-CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
-nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
-43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
-T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
-gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
-BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
-TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
-DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
-hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
-06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
-PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
-YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
-CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert High Assurance EV Root CA O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert High Assurance EV Root CA"
-# Serial: 3553400076410547919724730734378100087
-# MD5 Fingerprint: d4:74:de:57:5c:39:b2:d3:9c:85:83:c5:c0:65:49:8a
-# SHA1 Fingerprint: 5f:b7:ee:06:33:e2:59:db:ad:0c:4c:9a:e6:d3:8f:1a:61:c7:dc:25
-# SHA256 Fingerprint: 74:31:e5:f4:c3:c1:ce:46:90:77:4f:0b:61:e0:54:40:88:3b:a9:a0:1e:d0:0b:a6:ab:d7:80:6e:d3:b1:18:cf
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSswKQYDVQQDEyJEaWdpQ2VydCBIaWdoIEFzc3VyYW5j
-ZSBFViBSb290IENBMB4XDTA2MTExMDAwMDAwMFoXDTMxMTExMDAwMDAwMFowbDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDERpZ2lDZXJ0IEluYzEZMBcGA1UECxMQd3d3
-LmRpZ2ljZXJ0LmNvbTErMCkGA1UEAxMiRGlnaUNlcnQgSGlnaCBBc3N1cmFuY2Ug
-RVYgUm9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAMbM5XPm
-+9S75S0tMqbf5YE/yc0lSbZxKsPVlDRnogocsF9ppkCxxLeyj9CYpKlBWTrT3JTW
-PNt0OKRKzE0lgvdKpVMSOO7zSW1xkX5jtqumX8OkhPhPYlG++MXs2ziS4wblCJEM
-xChBVfvLWokVfnHoNb9Ncgk9vjo4UFt3MRuNs8ckRZqnrG0AFFoEt7oT61EKmEFB
-Ik5lYYeBQVCmeVyJ3hlKV9Uu5l0cUyx+mM0aBhakaHPQNAQTXKFx01p8VdteZOE3
-hzBWBOURtCmAEvF5OYiiAhF8J2a3iLd48soKqDirCmTCv2ZdlYTBoSUeh10aUAsg
-EsxBu24LUTi4S8sCAwEAAaNjMGEwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFLE+w2kD+L9HAdSYJhoIAu9jZCvDMB8GA1UdIwQYMBaA
-FLE+w2kD+L9HAdSYJhoIAu9jZCvDMA0GCSqGSIb3DQEBBQUAA4IBAQAcGgaX3Nec
-nzyIZgYIVyHbIUf4KmeqvxgydkAQV8GK83rZEWWONfqe/EW1ntlMMUu4kehDLI6z
-eM7b41N5cdblIZQB2lWHmiRk9opmzN6cN82oNLFpmyPInngiK3BD41VHMWEZ71jF
-hS9OMPagMRYjyOfiZRYzy78aG6A9+MpeizGLYAiJLQwGXFK3xPkKmNEVX58Svnw2
-Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
-vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
-+OkuE6N36B9K
------END CERTIFICATE-----
-
-# Issuer: CN=SwissSign Gold CA - G2 O=SwissSign AG
-# Subject: CN=SwissSign Gold CA - G2 O=SwissSign AG
-# Label: "SwissSign Gold CA - G2"
-# Serial: 13492815561806991280
-# MD5 Fingerprint: 24:77:d9:a8:91:d1:3b:fa:88:2d:c2:ff:f8:cd:33:93
-# SHA1 Fingerprint: d8:c5:38:8a:b7:30:1b:1b:6e:d4:7a:e6:45:25:3a:6f:9f:1a:27:61
-# SHA256 Fingerprint: 62:dd:0b:e9:b9:f5:0a:16:3e:a0:f8:e7:5c:05:3b:1e:ca:57:ea:55:c8:68:8f:64:7c:68:81:f2:c8:35:7b:95
------BEGIN CERTIFICATE-----
-MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
-BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
-biBHb2xkIENBIC0gRzIwHhcNMDYxMDI1MDgzMDM1WhcNMzYxMDI1MDgzMDM1WjBF
-MQswCQYDVQQGEwJDSDEVMBMGA1UEChMMU3dpc3NTaWduIEFHMR8wHQYDVQQDExZT
-d2lzc1NpZ24gR29sZCBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
-CgKCAgEAr+TufoskDhJuqVAtFkQ7kpJcyrhdhJJCEyq8ZVeCQD5XJM1QiyUqt2/8
-76LQwB8CJEoTlo8jE+YoWACjR8cGp4QjK7u9lit/VcyLwVcfDmJlD909Vopz2q5+
-bbqBHH5CjCA12UNNhPqE21Is8w4ndwtrvxEvcnifLtg+5hg3Wipy+dpikJKVyh+c
-6bM8K8vzARO/Ws/BtQpgvd21mWRTuKCWs2/iJneRjOBiEAKfNA+k1ZIzUd6+jbqE
-emA8atufK+ze3gE/bk3lUIbLtK/tREDFylqM2tIrfKjuvqblCqoOpd8FUrdVxyJd
-MmqXl2MT28nbeTZ7hTpKxVKJ+STnnXepgv9VHKVxaSvRAiTysybUa9oEVeXBCsdt
-MDeQKuSeFDNeFhdVxVu1yzSJkvGdJo+hB9TGsnhQ2wwMC3wLjEHXuendjIj3o02y
-MszYF9rNt85mndT9Xv+9lz4pded+p2JYryU0pUHHPbwNUMoDAw8IWh+Vc3hiv69y
-FGkOpeUDDniOJihC8AcLYiAQZzlG+qkDzAQ4embvIIO1jEpWjpEA/I5cgt6IoMPi
-aG59je883WX0XaxR7ySArqpWl2/5rX3aYT+YdzylkbYcjCbaZaIJbcHiVOO5ykxM
-gI93e2CaHt+28kgeDrpOVG2Y4OGiGqJ3UM/EY5LsRxmd6+ZrzsECAwEAAaOBrDCB
-qTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUWyV7
-lqRlUX64OfPAeGZe6Drn8O4wHwYDVR0jBBgwFoAUWyV7lqRlUX64OfPAeGZe6Drn
-8O4wRgYDVR0gBD8wPTA7BglghXQBWQECAQEwLjAsBggrBgEFBQcCARYgaHR0cDov
-L3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIBACe6
-45R88a7A3hfm5djV9VSwg/S7zV4Fe0+fdWavPOhWfvxyeDgD2StiGwC5+OlgzczO
-UYrHUDFu4Up+GC9pWbY9ZIEr44OE5iKHjn3g7gKZYbge9LgriBIWhMIxkziWMaa5
-O1M/wySTVltpkuzFwbs4AOPsF6m43Md8AYOfMke6UiI0HTJ6CVanfCU2qT1L2sCC
-bwq7EsiHSycR+R4tx5M/nttfJmtS2S6K8RTGRI0Vqbe/vd6mGu6uLftIdxf+u+yv
-GPUqUfA5hJeVbG4bwyvEdGB5JbAKJ9/fXtI5z0V9QkvfsywexcZdylU6oJxpmo/a
-77KwPJ+HbBIrZXAVUjEaJM9vMSNQH4xPjyPDdEFjHFWoFN0+4FFQz/EbMFYOkrCC
-hdiDyyJkvC24JdVUorgG6q2SpCSgwYa1ShNqR88uC1aVVMvOmttqtKay20EIhid3
-92qgQmwLOM7XdVAyksLfKzAiSNDVQTglXaTpXZ/GlHXQRf0wl0OPkKsKx4ZzYEpp
-Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
-ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
-Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
------END CERTIFICATE-----
-
-# Issuer: CN=SwissSign Silver CA - G2 O=SwissSign AG
-# Subject: CN=SwissSign Silver CA - G2 O=SwissSign AG
-# Label: "SwissSign Silver CA - G2"
-# Serial: 5700383053117599563
-# MD5 Fingerprint: e0:06:a1:c9:7d:cf:c9:fc:0d:c0:56:75:96:d8:62:13
-# SHA1 Fingerprint: 9b:aa:e5:9f:56:ee:21:cb:43:5a:be:25:93:df:a7:f0:40:d1:1d:cb
-# SHA256 Fingerprint: be:6c:4d:a2:bb:b9:ba:59:b6:f3:93:97:68:37:42:46:c3:c0:05:99:3f:a9:8f:02:0d:1d:ed:be:d4:8a:81:d5
------BEGIN CERTIFICATE-----
-MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
-BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
-IFNpbHZlciBDQSAtIEcyMB4XDTA2MTAyNTA4MzI0NloXDTM2MTAyNTA4MzI0Nlow
-RzELMAkGA1UEBhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMY
-U3dpc3NTaWduIFNpbHZlciBDQSAtIEcyMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A
-MIICCgKCAgEAxPGHf9N4Mfc4yfjDmUO8x/e8N+dOcbpLj6VzHVxumK4DV644N0Mv
-Fz0fyM5oEMF4rhkDKxD6LHmD9ui5aLlV8gREpzn5/ASLHvGiTSf5YXu6t+WiE7br
-YT7QbNHm+/pe7R20nqA1W6GSy/BJkv6FCgU+5tkL4k+73JU3/JHpMjUi0R86TieF
-nbAVlDLaYQ1HTWBCrpJH6INaUFjpiou5XaHc3ZlKHzZnu0jkg7Y360g6rw9njxcH
-6ATK72oxh9TAtvmUcXtnZLi2kUpCe2UuMGoM9ZDulebyzYLs2aFK7PayS+VFheZt
-eJMELpyCbTapxDFkH4aDCyr0NQp4yVXPQbBH6TCfmb5hqAaEuSh6XzjZG6k4sIN/
-c8HDO0gqgg8hm7jMqDXDhBuDsz6+pJVpATqJAHgE2cn0mRmrVn5bi4Y5FZGkECwJ
-MoBgs5PAKrYYC51+jUnyEEp/+dVGLxmSo5mnJqy7jDzmDrxHB9xzUfFwZC8I+bRH
-HTBsROopN4WSaGa8gzj+ezku01DwH/teYLappvonQfGbGHLy9YR0SslnxFSuSGTf
-jNFusB3hB48IHpmccelM2KX3RxIfdNFRnobzwqIjQAtz20um53MGjMGg6cFZrEb6
-5i/4z3GcRm25xBWNOHkDRUjvxF3XCO6HOSKGsg0PWEP3calILv3q1h8CAwEAAaOB
-rDCBqTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
-F6DNweRBtjpbO8tFnb0cwpj6hlgwHwYDVR0jBBgwFoAUF6DNweRBtjpbO8tFnb0c
-wpj6hlgwRgYDVR0gBD8wPTA7BglghXQBWQEDAQEwLjAsBggrBgEFBQcCARYgaHR0
-cDovL3JlcG9zaXRvcnkuc3dpc3NzaWduLmNvbS8wDQYJKoZIhvcNAQEFBQADggIB
-AHPGgeAn0i0P4JUw4ppBf1AsX19iYamGamkYDHRJ1l2E6kFSGG9YrVBWIGrGvShp
-WJHckRE1qTodvBqlYJ7YH39FkWnZfrt4csEGDyrOj4VwYaygzQu4OSlWhDJOhrs9
-xCrZ1x9y7v5RoSJBsXECYxqCsGKrXlcSH9/L3XWgwF15kIwb4FDm3jH+mHtwX6WQ
-2K34ArZv02DdQEsixT2tOnqfGhpHkXkzuoLcMmkDlm4fS/Bx/uNncqCxv1yL5PqZ
-IseEuRuNI5c/7SXgz2W79WEE790eslpBIlqhn10s6FvJbakMDHiqYMZWjwFaDGi8
-aRl5xB9+lwW/xekkUV7U1UtT7dkjWjYDZaPBA61BMPNGG4WQr2W11bHkFlt4dR2X
-em1ZqSqPe97Dh4kQmUlzeMg9vVE1dCrV8X5pGyq7O70luJpaPXJhkGaH7gzWTdQR
-dAtq/gsD/KNVV4n+SsuuWxcFyPKNIzFTONItaj+CuY0IavdeQXRuwxF+B6wpYJE/
-OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
-hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
-tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
------END CERTIFICATE-----
-
-# Issuer: CN=SecureTrust CA O=SecureTrust Corporation
-# Subject: CN=SecureTrust CA O=SecureTrust Corporation
-# Label: "SecureTrust CA"
-# Serial: 17199774589125277788362757014266862032
-# MD5 Fingerprint: dc:32:c3:a7:6d:25:57:c7:68:09:9d:ea:2d:a9:a2:d1
-# SHA1 Fingerprint: 87:82:c6:c3:04:35:3b:cf:d2:96:92:d2:59:3e:7d:44:d9:34:ff:11
-# SHA256 Fingerprint: f1:c1:b5:0a:e5:a2:0d:d8:03:0e:c9:f6:bc:24:82:3d:d3:67:b5:25:57:59:b4:e7:1b:61:fc:e9:f7:37:5d:73
------BEGIN CERTIFICATE-----
-MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
-MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
-FzAVBgNVBAMTDlNlY3VyZVRydXN0IENBMB4XDTA2MTEwNzE5MzExOFoXDTI5MTIz
-MTE5NDA1NVowSDELMAkGA1UEBhMCVVMxIDAeBgNVBAoTF1NlY3VyZVRydXN0IENv
-cnBvcmF0aW9uMRcwFQYDVQQDEw5TZWN1cmVUcnVzdCBDQTCCASIwDQYJKoZIhvcN
-AQEBBQADggEPADCCAQoCggEBAKukgeWVzfX2FI7CT8rU4niVWJxB4Q2ZQCQXOZEz
-Zum+4YOvYlyJ0fwkW2Gz4BERQRwdbvC4u/jep4G6pkjGnx29vo6pQT64lO0pGtSO
-0gMdA+9tDWccV9cGrcrI9f4Or2YlSASWC12juhbDCE/RRvgUXPLIXgGZbf2IzIao
-wW8xQmxSPmjL8xk037uHGFaAJsTQ3MBv396gwpEWoGQRS0S8Hvbn+mPeZqx2pHGj
-7DaUaHp3pLHnDi+BeuK1cobvomuL8A/b01k/unK8RCSc43Oz969XL0Imnal0ugBS
-8kvNU3xHCzaFDmapCJcWNFfBZveA4+1wVMeT4C4oFVmHursCAwEAAaOBnTCBmjAT
-BgkrBgEEAYI3FAIEBh4EAEMAQTALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB
-/zAdBgNVHQ4EFgQUQjK2FvoE/f5dS3rD/fdMQB1aQ68wNAYDVR0fBC0wKzApoCeg
-JYYjaHR0cDovL2NybC5zZWN1cmV0cnVzdC5jb20vU1RDQS5jcmwwEAYJKwYBBAGC
-NxUBBAMCAQAwDQYJKoZIhvcNAQEFBQADggEBADDtT0rhWDpSclu1pqNlGKa7UTt3
-6Z3q059c4EVlew3KW+JwULKUBRSuSceNQQcSc5R+DCMh/bwQf2AQWnL1mA6s7Ll/
-3XpvXdMc9P+IBWlCqQVxyLesJugutIxq/3HcuLHfmbx8IVQr5Fiiu1cprp6poxkm
-D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
-CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
-3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
------END CERTIFICATE-----
-
-# Issuer: CN=Secure Global CA O=SecureTrust Corporation
-# Subject: CN=Secure Global CA O=SecureTrust Corporation
-# Label: "Secure Global CA"
-# Serial: 9751836167731051554232119481456978597
-# MD5 Fingerprint: cf:f4:27:0d:d4:ed:dc:65:16:49:6d:3d:da:bf:6e:de
-# SHA1 Fingerprint: 3a:44:73:5a:e5:81:90:1f:24:86:61:46:1e:3b:9c:c4:5f:f5:3a:1b
-# SHA256 Fingerprint: 42:00:f5:04:3a:c8:59:0e:bb:52:7d:20:9e:d1:50:30:29:fb:cb:d4:1c:a1:b5:06:ec:27:f1:5a:de:7d:ac:69
------BEGIN CERTIFICATE-----
-MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
-MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
-GTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwHhcNMDYxMTA3MTk0MjI4WhcNMjkx
-MjMxMTk1MjA2WjBKMQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3Qg
-Q29ycG9yYXRpb24xGTAXBgNVBAMTEFNlY3VyZSBHbG9iYWwgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCvNS7YrGxVaQZx5RNoJLNP2MwhR/jxYDiJ
-iQPpvepeRlMJ3Fz1Wuj3RSoC6zFh1ykzTM7HfAo3fg+6MpjhHZevj8fcyTiW89sa
-/FHtaMbQbqR8JNGuQsiWUGMu4P51/pinX0kuleM5M2SOHqRfkNJnPLLZ/kG5VacJ
-jnIFHovdRIWCQtBJwB1g8NEXLJXr9qXBkqPFwqcIYA1gBBCWeZ4WNOaptvolRTnI
-HmX5k/Wq8VLcmZg9pYYaDDUz+kulBAYVHDGA76oYa8J719rO+TMg1fW9ajMtgQT7
-sFzUnKPiXB3jqUJ1XnvUd+85VLrJChgbEplJL4hL/VBi0XPnj3pDAgMBAAGjgZ0w
-gZowEwYJKwYBBAGCNxQCBAYeBABDAEEwCwYDVR0PBAQDAgGGMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFK9EBMJBfkiD2045AuzshHrmzsmkMDQGA1UdHwQtMCsw
-KaAnoCWGI2h0dHA6Ly9jcmwuc2VjdXJldHJ1c3QuY29tL1NHQ0EuY3JsMBAGCSsG
-AQQBgjcVAQQDAgEAMA0GCSqGSIb3DQEBBQUAA4IBAQBjGghAfaReUw132HquHw0L
-URYD7xh8yOOvaliTFGCRsoTciE6+OYo68+aCiV0BN7OrJKQVDpI1WkpEXk5X+nXO
-H0jOZvQ8QCaSmGwb7iRGDBezUqXbpZGRzzfTb+cnCDpOGR86p1hcF895P4vkp9Mm
-I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
-iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
-f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO Certification Authority O=COMODO CA Limited
-# Label: "COMODO Certification Authority"
-# Serial: 104350513648249232941998508985834464573
-# MD5 Fingerprint: 5c:48:dc:f7:42:72:ec:56:94:6d:1c:cc:71:35:80:75
-# SHA1 Fingerprint: 66:31:bf:9e:f7:4f:9e:b6:c9:d5:a6:0c:ba:6a:be:d1:f7:bd:ef:7b
-# SHA256 Fingerprint: 0c:2c:d6:3d:f7:80:6f:a3:99:ed:e8:09:11:6b:57:5b:f8:79:89:f0:65:18:f9:80:8c:86:05:03:17:8b:af:66
------BEGIN CERTIFICATE-----
-MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
-gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxJzAlBgNV
-BAMTHkNPTU9ETyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEyMDEwMDAw
-MDBaFw0yOTEyMzEyMzU5NTlaMIGBMQswCQYDVQQGEwJHQjEbMBkGA1UECBMSR3Jl
-YXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHEwdTYWxmb3JkMRowGAYDVQQKExFDT01P
-RE8gQ0EgTGltaXRlZDEnMCUGA1UEAxMeQ09NT0RPIENlcnRpZmljYXRpb24gQXV0
-aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0ECLi3LjkRv3
-UcEbVASY06m/weaKXTuH+7uIzg3jLz8GlvCiKVCZrts7oVewdFFxze1CkU1B/qnI
-2GqGd0S7WWaXUF601CxwRM/aN5VCaTwwxHGzUvAhTaHYujl8HJ6jJJ3ygxaYqhZ8
-Q5sVW7euNJH+1GImGEaaP+vB+fGQV+useg2L23IwambV4EajcNxo2f8ESIl33rXp
-+2dtQem8Ob0y2WIC8bGoPW43nOIv4tOiJovGuFVDiOEjPqXSJDlqR6sA1KGzqSX+
-DT+nHbrTUcELpNqsOO9VUCQFZUaTNE8tja3G1CEZ0o7KBWFxB3NH5YoZEr0ETc5O
-nKVIrLsm9wIDAQABo4GOMIGLMB0GA1UdDgQWBBQLWOWLxkwVN6RAqTCpIb5HNlpW
-/zAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zBJBgNVHR8EQjBAMD6g
-PKA6hjhodHRwOi8vY3JsLmNvbW9kb2NhLmNvbS9DT01PRE9DZXJ0aWZpY2F0aW9u
-QXV0aG9yaXR5LmNybDANBgkqhkiG9w0BAQUFAAOCAQEAPpiem/Yb6dc5t3iuHXIY
-SdOH5EOC6z/JqvWote9VfCFSZfnVDeFs9D6Mk3ORLgLETgdxb8CPOGEIqB6BCsAv
-IC9Bi5HcSEW88cbeunZrM8gALTFGTO3nnc+IlP8zwFboJIYmuNg4ON8qa90SzMc/
-RxdMosIGlgnW2/4/PEZB31jiVg88O8EckzXZOFKs7sjsLjBOlDW0JB9LeGna8gI4
-zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
-BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
-ZQ==
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO ECC Certification Authority O=COMODO CA Limited
-# Label: "COMODO ECC Certification Authority"
-# Serial: 41578283867086692638256921589707938090
-# MD5 Fingerprint: 7c:62:ff:74:9d:31:53:5e:68:4a:d5:78:aa:1e:bf:23
-# SHA1 Fingerprint: 9f:74:4e:9f:2b:4d:ba:ec:0f:31:2c:50:b6:56:3b:8e:2d:93:c3:11
-# SHA256 Fingerprint: 17:93:92:7a:06:14:54:97:89:ad:ce:2f:8f:34:f7:f0:b6:6d:0f:3a:e3:a3:b8:4d:21:ec:15:db:ba:4f:ad:c7
------BEGIN CERTIFICATE-----
-MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
-MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
-BxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMT
-IkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwMzA2MDAw
-MDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdy
-ZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09N
-T0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBFQ0MgQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQDR3svdcmCFYX7deSR
-FtSrYpn1PlILBs5BAH+X4QokPB0BBO490o0JlwzgdeT6+3eKKvUDYEs2ixYjFq0J
-cfRK9ChQtP6IHG4/bC8vCVlbpVsLM5niwz2J+Wos77LTBumjQjBAMB0GA1UdDgQW
-BBR1cacZSBm8nZ3qQUfflMRId5nTeTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
-fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
-GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
------END CERTIFICATE-----
-
-# Issuer: CN=Certigna O=Dhimyotis
-# Subject: CN=Certigna O=Dhimyotis
-# Label: "Certigna"
-# Serial: 18364802974209362175
-# MD5 Fingerprint: ab:57:a6:5b:7d:42:82:19:b5:d8:58:26:28:5e:fd:ff
-# SHA1 Fingerprint: b1:2e:13:63:45:86:a4:6f:1a:b2:60:68:37:58:2d:c4:ac:fd:94:97
-# SHA256 Fingerprint: e3:b6:a2:db:2e:d7:ce:48:84:2f:7a:c5:32:41:c7:b7:1d:54:14:4b:fb:40:c1:1f:3f:1d:0b:42:f5:ee:a1:2d
------BEGIN CERTIFICATE-----
-MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
-BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
-DTA3MDYyOTE1MTMwNVoXDTI3MDYyOTE1MTMwNVowNDELMAkGA1UEBhMCRlIxEjAQ
-BgNVBAoMCURoaW15b3RpczERMA8GA1UEAwwIQ2VydGlnbmEwggEiMA0GCSqGSIb3
-DQEBAQUAA4IBDwAwggEKAoIBAQDIaPHJ1tazNHUmgh7stL7qXOEm7RFHYeGifBZ4
-QCHkYJ5ayGPhxLGWkv8YbWkj4Sti993iNi+RB7lIzw7sebYs5zRLcAglozyHGxny
-gQcPOJAZ0xH+hrTy0V4eHpbNgGzOOzGTtvKg0KmVEn2lmsxryIRWijOp5yIVUxbw
-zBfsV1/pogqYCd7jX5xv3EjjhQsVWqa6n6xI4wmy9/Qy3l40vhx4XUJbzg4ij02Q
-130yGLMLLGq/jj8UEYkgDncUtT2UCIf3JR7VsmAA7G8qKCVuKj4YYxclPz5EIBb2
-JsglrgVKtOdjLPOMFlN+XPsRGgjBRmKfIrjxwo1p3Po6WAbfAgMBAAGjgbwwgbkw
-DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUGu3+QTmQtCRZvgHyUtVF9lo53BEw
-ZAYDVR0jBF0wW4AUGu3+QTmQtCRZvgHyUtVF9lo53BGhOKQ2MDQxCzAJBgNVBAYT
-AkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hggkA/tzj
-AQ/JSP8wDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIABzANBgkqhkiG
-9w0BAQUFAAOCAQEAhQMeknH2Qq/ho2Ge6/PAD/Kl1NqV5ta+aDY9fm4fTIrv0Q8h
-bV6lUmPOEvjvKtpv6zf+EwLHyzs+ImvaYS5/1HI93TDhHkxAGYwP15zRgzB7mFnc
-fca5DClMoTOi62c6ZYTTluLtdkVwj7Ur3vkj1kluPBS1xp81HlDQwY9qcEQCYsuu
-HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w
-t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
-WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
------END CERTIFICATE-----
-
-# Issuer: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority
-# Subject: O=Chunghwa Telecom Co., Ltd. OU=ePKI Root Certification Authority
-# Label: "ePKI Root Certification Authority"
-# Serial: 28956088682735189655030529057352760477
-# MD5 Fingerprint: 1b:2e:00:ca:26:06:90:3d:ad:fe:6f:15:68:d3:6b:b3
-# SHA1 Fingerprint: 67:65:0d:f1:7e:8e:7e:5b:82:40:a4:f4:56:4b:cf:e2:3d:69:c6:f0
-# SHA256 Fingerprint: c0:a6:f4:dc:63:a2:4b:fd:cf:54:ef:2a:6a:08:2a:0a:72:de:35:80:3e:2f:f5:ff:52:7a:e5:d8:72:06:df:d5
------BEGIN CERTIFICATE-----
-MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
-MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
-ZC4xKjAoBgNVBAsMIWVQS0kgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAe
-Fw0wNDEyMjAwMjMxMjdaFw0zNDEyMjAwMjMxMjdaMF4xCzAJBgNVBAYTAlRXMSMw
-IQYDVQQKDBpDaHVuZ2h3YSBUZWxlY29tIENvLiwgTHRkLjEqMCgGA1UECwwhZVBL
-SSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEA4SUP7o3biDN1Z82tH306Tm2d0y8U82N0ywEhajfqhFAH
-SyZbCUNsIZ5qyNUD9WBpj8zwIuQf5/dqIjG3LBXy4P4AakP/h2XGtRrBp0xtInAh
-ijHyl3SJCRImHJ7K2RKilTza6We/CKBk49ZCt0Xvl/T29de1ShUCWH2YWEtgvM3X
-DZoTM1PRYfl61dd4s5oz9wCGzh1NlDivqOx4UXCKXBCDUSH3ET00hl7lSM2XgYI1
-TBnsZfZrxQWh7kcT1rMhJ5QQCtkkO7q+RBNGMD+XPNjX12ruOzjjK9SXDrkb5wdJ
-fzcq+Xd4z1TtW0ado4AOkUPB1ltfFLqfpo0kR0BZv3I4sjZsN/+Z0V0OWQqraffA
-sgRFelQArr5T9rXn4fg8ozHSqf4hUmTFpmfwdQcGlBSBVcYn5AGPF8Fqcde+S/uU
-WH1+ETOxQvdibBjWzwloPn9s9h6PYq2lY9sJpx8iQkEeb5mKPtf5P0B6ebClAZLS
-nT0IFaUQAS2zMnaolQ2zepr7BxB4EW/hj8e6DyUadCrlHJhBmd8hh+iVBmoKs2pH
-dmX2Os+PYhcZewoozRrSgx4hxyy/vv9haLdnG7t4TY3OZ+XkwY63I2binZB1NJip
-NiuKmpS5nezMirH4JYlcWrYvjB9teSSnUmjDhDXiZo1jDiVN1Rmy5nk3pyKdVDEC
-AwEAAaNqMGgwHQYDVR0OBBYEFB4M97Zn8uGSJglFwFU5Lnc/QkqiMAwGA1UdEwQF
-MAMBAf8wOQYEZyoHAAQxMC8wLQIBADAJBgUrDgMCGgUAMAcGBWcqAwAABBRFsMLH
-ClZ87lt4DJX5GFPBphzYEDANBgkqhkiG9w0BAQUFAAOCAgEACbODU1kBPpVJufGB
-uvl2ICO1J2B01GqZNF5sAFPZn/KmsSQHRGoqxqWOeBLoR9lYGxMqXnmbnwoqZ6Yl
-PwZpVnPDimZI+ymBV3QGypzqKOg4ZyYr8dW1P2WT+DZdjo2NQCCHGervJ8A9tDkP
-JXtoUHRVnAxZfVo9QZQlUgjgRywVMRnVvwdVxrsStZf0X4OFunHB2WyBEXYKCrC/
-gpf36j36+uwtqSiUO1bd0lEursC9CBWMd1I0ltabrNMdjmEPNXubrjlpC2JgQCA2
-j6/7Nu4tCEoduL+bXPjqpRugc6bY+G7gMwRfaKonh+3ZwZCc7b3jajWvY9+rGNm6
-5ulK6lCKD2GTHuItGeIwlDWSXQ62B68ZgI9HkFFLLk3dheLSClIKF5r8GrBQAuUB
-o2M3IUxExJtRmREOc5wGj1QupyheRDmHVi03vYVElOEMSyycw5KFNGHLD7ibSkNS
-/jQ6fbjpKdx2qcgw+BRxgMYeNkh0IkFch4LoGHGLQYlE535YW6i4jRPpp2zDR+2z
-Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
-W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
-hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
------END CERTIFICATE-----
-
-# Issuer: O=certSIGN OU=certSIGN ROOT CA
-# Subject: O=certSIGN OU=certSIGN ROOT CA
-# Label: "certSIGN ROOT CA"
-# Serial: 35210227249154
-# MD5 Fingerprint: 18:98:c0:d6:e9:3a:fc:f9:b0:f5:0c:f7:4b:01:44:17
-# SHA1 Fingerprint: fa:b7:ee:36:97:26:62:fb:2d:b0:2a:f6:bf:03:fd:e8:7c:4b:2f:9b
-# SHA256 Fingerprint: ea:a9:62:c4:fa:4a:6b:af:eb:e4:15:19:6d:35:1c:cd:88:8d:4f:53:f3:fa:8a:e6:d7:c4:66:a9:4e:60:42:bb
------BEGIN CERTIFICATE-----
-MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
-AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
-QTAeFw0wNjA3MDQxNzIwMDRaFw0zMTA3MDQxNzIwMDRaMDsxCzAJBgNVBAYTAlJP
-MREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBDQTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALczuX7IJUqOtdu0KBuqV5Do
-0SLTZLrTk+jUrIZhQGpgV2hUhE28alQCBf/fm5oqrl0Hj0rDKH/v+yv6efHHrfAQ
-UySQi2bJqIirr1qjAOm+ukbuW3N7LBeCgV5iLKECZbO9xSsAfsT8AzNXDe3i+s5d
-RdY4zTW2ssHQnIFKquSyAVwdj1+ZxLGt24gh65AIgoDzMKND5pCCrlUoSe1b16kQ
-OA7+j0xbm0bqQfWwCHTD0IgztnzXdN/chNFDDnU5oSVAKOp4yw4sLjmdjItuFhwv
-JoIQ4uNllAoEwF73XVv4EOLQunpL+943AAAaWyjj0pxzPjKHmKHJUS/X3qwzs08C
-AwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAcYwHQYDVR0O
-BBYEFOCMm9slSbPxfIbWskKHC9BroNnkMA0GCSqGSIb3DQEBBQUAA4IBAQA+0hyJ
-LjX8+HXd5n9liPRyTMks1zJO890ZeUe9jjtbkw9QSSQTaxQGcu8J06Gh40CEyecY
-MnQ8SG4Pn0vU9x7Tk4ZkVJdjclDVVc/6IJMCopvDI5NOFlV2oHB5bc0hH88vLbwZ
-44gx+FkagQnIl6Z0x2DEW8xXjrJ1/RsCCdtZb3KTafcxQdaIOL+Hsr0Wefmq5L6I
-Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw
-i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
-9u6wWk5JRFRYX0KD
------END CERTIFICATE-----
-
-# Issuer: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services)
-# Subject: CN=NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny O=NetLock Kft. OU=Tan\xfas\xedtv\xe1nykiad\xf3k (Certification Services)
-# Label: "NetLock Arany (Class Gold) F\u0151tan\xfas\xedtv\xe1ny"
-# Serial: 80544274841616
-# MD5 Fingerprint: c5:a1:b7:ff:73:dd:d6:d7:34:32:18:df:fc:3c:ad:88
-# SHA1 Fingerprint: 06:08:3f:59:3f:15:a1:04:a0:69:a4:6b:a9:03:d0:06:b7:97:09:91
-# SHA256 Fingerprint: 6c:61:da:c3:a2:de:f0:31:50:6b:e0:36:d2:a6:fe:40:19:94:fb:d1:3d:f9:c8:d4:66:59:92:74:c4:46:ec:98
------BEGIN CERTIFICATE-----
-MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
-EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
-MDUGA1UECwwuVGFuw7pzw610dsOhbnlraWFkw7NrIChDZXJ0aWZpY2F0aW9uIFNl
-cnZpY2VzKTE1MDMGA1UEAwwsTmV0TG9jayBBcmFueSAoQ2xhc3MgR29sZCkgRsWR
-dGFuw7pzw610dsOhbnkwHhcNMDgxMjExMTUwODIxWhcNMjgxMjA2MTUwODIxWjCB
-pzELMAkGA1UEBhMCSFUxETAPBgNVBAcMCEJ1ZGFwZXN0MRUwEwYDVQQKDAxOZXRM
-b2NrIEtmdC4xNzA1BgNVBAsMLlRhbsO6c8OtdHbDoW55a2lhZMOzayAoQ2VydGlm
-aWNhdGlvbiBTZXJ2aWNlcykxNTAzBgNVBAMMLE5ldExvY2sgQXJhbnkgKENsYXNz
-IEdvbGQpIEbFkXRhbsO6c8OtdHbDoW55MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAxCRec75LbRTDofTjl5Bu0jBFHjzuZ9lk4BqKf8owyoPjIMHj9DrT
-lF8afFttvzBPhCf2nx9JvMaZCpDyD/V/Q4Q3Y1GLeqVw/HpYzY6b7cNGbIRwXdrz
-AZAj/E4wqX7hJ2Pn7WQ8oLjJM2P+FpD/sLj916jAwJRDC7bVWaaeVtAkH3B5r9s5
-VA1lddkVQZQBr17s9o3x/61k/iCa11zr/qYfCGSji3ZVrR47KGAuhyXoqq8fxmRG
-ILdwfzzeSNuWU7c5d+Qa4scWhHaXWy+7GRWF+GmF9ZmnqfI0p6m2pgP8b4Y9VHx2
-BJtr+UBdADTHLpl1neWIA6pN+APSQnbAGwIDAKiLo0UwQzASBgNVHRMBAf8ECDAG
-AQH/AgEEMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUzPpnk/C2uNClwB7zU/2M
-U9+D15YwDQYJKoZIhvcNAQELBQADggEBAKt/7hwWqZw8UQCgwBEIBaeZ5m8BiFRh
-bvG5GK1Krf6BQCOUL/t1fC8oS2IkgYIL9WHxHG64YTjrgfpioTtaYtOUZcTh5m2C
-+C8lcLIhJsFyUR+MLMOEkMNaj7rP9KdlpeuY0fsFskZ1FSNqb4VjMIDw1Z4fKRzC
-bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F
-uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
-XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
------END CERTIFICATE-----
-
-# Issuer: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
-# Subject: CN=SecureSign RootCA11 O=Japan Certification Services, Inc.
-# Label: "SecureSign RootCA11"
-# Serial: 1
-# MD5 Fingerprint: b7:52:74:e2:92:b4:80:93:f2:75:e4:cc:d7:f2:ea:26
-# SHA1 Fingerprint: 3b:c4:9f:48:f8:f3:73:a0:9c:1e:bd:f8:5b:b1:c3:65:c7:d8:11:b3
-# SHA256 Fingerprint: bf:0f:ee:fb:9e:3a:58:1a:d5:f9:e9:db:75:89:98:57:43:d2:61:08:5c:4d:31:4f:6f:5d:72:59:aa:42:16:12
------BEGIN CERTIFICATE-----
-MIIDbTCCAlWgAwIBAgIBATANBgkqhkiG9w0BAQUFADBYMQswCQYDVQQGEwJKUDEr
-MCkGA1UEChMiSmFwYW4gQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcywgSW5jLjEcMBoG
-A1UEAxMTU2VjdXJlU2lnbiBSb290Q0ExMTAeFw0wOTA0MDgwNDU2NDdaFw0yOTA0
-MDgwNDU2NDdaMFgxCzAJBgNVBAYTAkpQMSswKQYDVQQKEyJKYXBhbiBDZXJ0aWZp
-Y2F0aW9uIFNlcnZpY2VzLCBJbmMuMRwwGgYDVQQDExNTZWN1cmVTaWduIFJvb3RD
-QTExMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA/XeqpRyQBTvLTJsz
-i1oURaTnkBbR31fSIRCkF/3frNYfp+TbfPfs37gD2pRY/V1yfIw/XwFndBWW4wI8
-h9uuywGOwvNmxoVF9ALGOrVisq/6nL+k5tSAMJjzDbaTj6nU2DbysPyKyiyhFTOV
-MdrAG/LuYpmGYz+/3ZMqg6h2uRMft85OQoWPIucuGvKVCbIFtUROd6EgvanyTgp9
-UK31BQ1FT0Zx/Sg+U/sE2C3XZR1KG/rPO7AxmjVuyIsG0wCR8pQIZUyxNAYAeoni
-8McDWc/V1uinMrPmmECGxc0nEovMe863ETxiYAcjPitAbpSACW22s293bzUIUPsC
-h8U+iQIDAQABo0IwQDAdBgNVHQ4EFgQUW/hNT7KlhtQ60vFjmqC+CfZXt94wDgYD
-VR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEB
-AKChOBZmLqdWHyGcBvod7bkixTgm2E5P7KN/ed5GIaGHd48HCJqypMWvDzKYC3xm
-KbabfSVSSUOrTC4rbnpwrxYO4wJs+0LmGJ1F2FXI6Dvd5+H0LgscNFxsWEr7jIhQ
-X5Ucv+2rIrVls4W6ng+4reV6G4pQOh29Dbx7VFALuUKvVaAYga1lme++5Jy/xIWr
-QbJUb9wlze144o4MjQlJ3WN7WmmWAiGovVJZ6X01y8hSyn+B/tlr0/cR7SXf+Of5
-pPpyl4RTDaXQMhhRdlkUbA/r7F+AjHVDg8OFmP9Mni0N5HeDk061lgeLKBObjBmN
-QSdJQO7e5iNEOdyhIta6A/I=
------END CERTIFICATE-----
-
-# Issuer: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
-# Subject: CN=Microsec e-Szigno Root CA 2009 O=Microsec Ltd.
-# Label: "Microsec e-Szigno Root CA 2009"
-# Serial: 14014712776195784473
-# MD5 Fingerprint: f8:49:f4:03:bc:44:2d:83:be:48:69:7d:29:64:fc:b1
-# SHA1 Fingerprint: 89:df:74:fe:5c:f4:0f:4a:80:f9:e3:37:7d:54:da:91:e1:01:31:8e
-# SHA256 Fingerprint: 3c:5f:81:fe:a5:fa:b8:2c:64:bf:a2:ea:ec:af:cd:e8:e0:77:fc:86:20:a7:ca:e5:37:16:3d:f3:6e:db:f3:78
------BEGIN CERTIFICATE-----
-MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
-VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
-ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3ppZ25vIFJvb3QgQ0EgMjAwOTEfMB0G
-CSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5odTAeFw0wOTA2MTYxMTMwMThaFw0y
-OTEyMzAxMTMwMThaMIGCMQswCQYDVQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3Qx
-FjAUBgNVBAoMDU1pY3Jvc2VjIEx0ZC4xJzAlBgNVBAMMHk1pY3Jvc2VjIGUtU3pp
-Z25vIFJvb3QgQ0EgMjAwOTEfMB0GCSqGSIb3DQEJARYQaW5mb0BlLXN6aWduby5o
-dTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOn4j/NjrdqG2KfgQvvP
-kd6mJviZpWNwrZuuyjNAfW2WbqEORO7hE52UQlKavXWFdCyoDh2Tthi3jCyoz/tc
-cbna7P7ofo/kLx2yqHWH2Leh5TvPmUpG0IMZfcChEhyVbUr02MelTTMuhTlAdX4U
-fIASmFDHQWe4oIBhVKZsTh/gnQ4H6cm6M+f+wFUoLAKApxn1ntxVUwOXewdI/5n7
-N4okxFnMUBBjjqqpGrCEGob5X7uxUG6k0QrM1XF+H6cbfPVTbiJfyyvm1HxdrtbC
-xkzlBQHZ7Vf8wSN5/PrIJIOV87VqUQHQd9bpEqH5GoP7ghu5sJf0dgYzQ0mg/wu1
-+rUCAwEAAaOBgDB+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
-A1UdDgQWBBTLD8bfQkPMPcu1SCOhGnqmKrs0aDAfBgNVHSMEGDAWgBTLD8bfQkPM
-Pcu1SCOhGnqmKrs0aDAbBgNVHREEFDASgRBpbmZvQGUtc3ppZ25vLmh1MA0GCSqG
-SIb3DQEBCwUAA4IBAQDJ0Q5eLtXMs3w+y/w9/w0olZMEyL/azXm4Q5DwpL7v8u8h
-mLzU1F0G9u5C7DBsoKqpyvGvivo/C3NqPuouQH4frlRheesuCDfXI/OMn74dseGk
-ddug4lQUsbocKaQY9hK6ohQU4zE1yED/t+AFdlfBHFny+L/k7SViXITwfn4fs775
-tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
-2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t
-HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R3
-# Label: "GlobalSign Root CA - R3"
-# Serial: 4835703278459759426209954
-# MD5 Fingerprint: c5:df:b8:49:ca:05:13:55:ee:2d:ba:1a:c3:3e:b0:28
-# SHA1 Fingerprint: d6:9b:56:11:48:f0:1c:77:c5:45:78:c1:09:26:df:5b:85:69:76:ad
-# SHA256 Fingerprint: cb:b5:22:d7:b7:f1:27:ad:6a:01:13:86:5b:df:1c:d4:10:2e:7d:07:59:af:63:5a:7c:f4:72:0d:c9:63:c5:3b
------BEGIN CERTIFICATE-----
-MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
-A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
-Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDkwMzE4MTAwMDAwWhcNMjkwMzE4
-MTAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMzETMBEG
-A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAMwldpB5BngiFvXAg7aEyiie/QV2EcWtiHL8
-RgJDx7KKnQRfJMsuS+FggkbhUqsMgUdwbN1k0ev1LKMPgj0MK66X17YUhhB5uzsT
-gHeMCOFJ0mpiLx9e+pZo34knlTifBtc+ycsmWQ1z3rDI6SYOgxXG71uL0gRgykmm
-KPZpO/bLyCiR5Z2KYVc3rHQU3HTgOu5yLy6c+9C7v/U9AOEGM+iCK65TpjoWc4zd
-QQ4gOsC0p6Hpsk+QLjJg6VfLuQSSaGjlOCZgdbKfd/+RFO+uIEn8rUAVSNECMWEZ
-XriX7613t2Saer9fwRPvm2L7DWzgVGkWqQPabumDk3F2xmmFghcCAwEAAaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI/wS3+o
-LkUkrk1Q+mOai97i3Ru8MA0GCSqGSIb3DQEBCwUAA4IBAQBLQNvAUKr+yAzv95ZU
-RUm7lgAJQayzE4aGKAczymvmdLm6AC2upArT9fHxD4q/c2dKg8dEe3jgr25sbwMp
-jjM5RcOO5LlXbKr8EpbsU8Yt5CRsuZRj+9xTaGdWPoO4zzUhw8lo/s7awlOqzJCK
-6fBdRoyV3XpYKBovHd7NADdBj+1EbddTKJd+82cEHhXXipa0095MJ6RMG3NzdvQX
-mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
-Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
-WD9f
------END CERTIFICATE-----
-
-# Issuer: CN=Izenpe.com O=IZENPE S.A.
-# Subject: CN=Izenpe.com O=IZENPE S.A.
-# Label: "Izenpe.com"
-# Serial: 917563065490389241595536686991402621
-# MD5 Fingerprint: a6:b0:cd:85:80:da:5c:50:34:a3:39:90:2f:55:67:73
-# SHA1 Fingerprint: 2f:78:3d:25:52:18:a7:4a:65:39:71:b5:2c:a2:9c:45:15:6f:e9:19
-# SHA256 Fingerprint: 25:30:cc:8e:98:32:15:02:ba:d9:6f:9b:1f:ba:1b:09:9e:2d:29:9e:0f:45:48:bb:91:4f:36:3b:c0:d4:53:1f
------BEGIN CERTIFICATE-----
-MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
-MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
-ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
-VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
-b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
-scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
-xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
-LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
-uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
-yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
-JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
-rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
-BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
-hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
-QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
-HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
-Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
-QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
-BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
-MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
-A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
-laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
-awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
-JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
-LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
-VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
-LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
-UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
-QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
-naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
-QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
------END CERTIFICATE-----
-
-# Issuer: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Subject: CN=Go Daddy Root Certificate Authority - G2 O=GoDaddy.com, Inc.
-# Label: "Go Daddy Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 80:3a:bc:22:c1:e6:fb:8d:9b:3b:27:4a:32:1b:9a:01
-# SHA1 Fingerprint: 47:be:ab:c9:22:ea:e8:0e:78:78:34:62:a7:9f:45:c2:54:fd:e6:8b
-# SHA256 Fingerprint: 45:14:0b:32:47:eb:9c:c8:c5:b4:f0:d7:b5:30:91:f7:32:92:08:9e:6e:5a:63:e2:74:9d:d3:ac:a9:19:8e:da
------BEGIN CERTIFICATE-----
-MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
-EUdvRGFkZHkuY29tLCBJbmMuMTEwLwYDVQQDEyhHbyBEYWRkeSBSb290IENlcnRp
-ZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAwMFoXDTM3MTIzMTIz
-NTk1OVowgYMxCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6b25hMRMwEQYDVQQH
-EwpTY290dHNkYWxlMRowGAYDVQQKExFHb0RhZGR5LmNvbSwgSW5jLjExMC8GA1UE
-AxMoR28gRGFkZHkgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIw
-DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL9xYgjx+lk09xvJGKP3gElY6SKD
-E6bFIEMBO4Tx5oVJnyfq9oQbTqC023CYxzIBsQU+B07u9PpPL1kwIuerGVZr4oAH
-/PMWdYA5UXvl+TW2dE6pjYIT5LY/qQOD+qK+ihVqf94Lw7YZFAXK6sOoBJQ7Rnwy
-DfMAZiLIjWltNowRGLfTshxgtDj6AozO091GB94KPutdfMh8+7ArU6SSYmlRJQVh
-GkSBjCypQ5Yj36w6gZoOKcUcqeldHraenjAKOc7xiID7S13MMuyFYkMlNAJWJwGR
-tDtwKj9useiciAF9n9T521NtYJ2/LOdYq7hfRvzOxBsDPAnrSTFcaUaz4EcCAwEA
-AaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
-FDqahQcQZyi27/a9BUFuIMGU2g/eMA0GCSqGSIb3DQEBCwUAA4IBAQCZ21151fmX
-WWcDYfF+OwYxdS2hII5PZYe096acvNjpL9DbWu7PdIxztDhC2gV7+AJ1uP2lsdeu
-9tfeE8tTEH6KRtGX+rcuKxGrkLAngPnon1rpN5+r5N9ss4UXnT3ZJE95kTXWXwTr
-gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
-2GTzLH4U/ALqn83/B2gX2yKQOC16jdFU8WnjXzPKej17CuPKf1855eJ1usV2GDPO
-LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
-4uJEvlz36hz1
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: d6:39:81:c6:52:7e:96:69:fc:fc:ca:66:ed:05:f2:96
-# SHA1 Fingerprint: b5:1c:06:7c:ee:2b:0c:3d:f8:55:ab:2d:92:f4:fe:39:d4:e7:0f:0e
-# SHA256 Fingerprint: 2c:e1:cb:0b:f9:d2:f9:e1:02:99:3f:be:21:51:52:c3:b2:dd:0c:ab:de:1c:68:e5:31:9b:83:91:54:db:b7:f5
------BEGIN CERTIFICATE-----
-MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAMTKVN0YXJmaWVs
-ZCBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5MDkwMTAwMDAw
-MFoXDTM3MTIzMTIzNTk1OVowgY8xCzAJBgNVBAYTAlVTMRAwDgYDVQQIEwdBcml6
-b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFyZmllbGQgVGVj
-aG5vbG9naWVzLCBJbmMuMTIwMAYDVQQDEylTdGFyZmllbGQgUm9vdCBDZXJ0aWZp
-Y2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAL3twQP89o/8ArFvW59I2Z154qK3A2FWGMNHttfKPTUuiUP3oWmb3ooa/RMg
-nLRJdzIpVv257IzdIvpy3Cdhl+72WoTsbhm5iSzchFvVdPtrX8WJpRBSiUZV9Lh1
-HOZ/5FSuS/hVclcCGfgXcVnrHigHdMWdSL5stPSksPNkN3mSwOxGXn/hbVNMYq/N
-Hwtjuzqd+/x5AJhhdM8mgkBj87JyahkNmcrUDnXMN/uLicFZ8WJ/X7NfZTD4p7dN
-dloedl40wOiWVpmKs/B/pM293DIxfJHP4F8R+GuqSVzRmZTRouNjWwl2tVZi4Ut0
-HZbUJtQIBFnQmA4O5t78w+wfkPECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAO
-BgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFHwMMh+n2TB/xH1oo2Kooc6rB1snMA0G
-CSqGSIb3DQEBCwUAA4IBAQARWfolTwNvlJk7mh+ChTnUdgWUXuEok21iXQnCoKjU
-sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
-4jd/IroAow57UvtruzvE03lRTs2Q9GcHGcg8RnoNAX3FWOdt5oUwF5okxBDgBPfg
-8n/Uqgr/Qh037ZTlZFkSIHc40zI+OIF1lnP6aI+xy84fxez6nH7PfrHxBy22/L/K
-pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
-mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
------END CERTIFICATE-----
-
-# Issuer: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Subject: CN=Starfield Services Root Certificate Authority - G2 O=Starfield Technologies, Inc.
-# Label: "Starfield Services Root Certificate Authority - G2"
-# Serial: 0
-# MD5 Fingerprint: 17:35:74:af:7b:61:1c:eb:f4:f9:3c:e2:ee:40:f9:a2
-# SHA1 Fingerprint: 92:5a:8f:8d:2c:6d:04:e0:66:5f:59:6a:ff:22:d8:63:e8:25:6f:3f
-# SHA256 Fingerprint: 56:8d:69:05:a2:c8:87:08:a4:b3:02:51:90:ed:cf:ed:b1:97:4a:60:6a:13:c6:e5:29:0f:cb:2a:e6:3e:da:b5
------BEGIN CERTIFICATE-----
-MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
-EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
-HFN0YXJmaWVsZCBUZWNobm9sb2dpZXMsIEluYy4xOzA5BgNVBAMTMlN0YXJmaWVs
-ZCBTZXJ2aWNlcyBSb290IENlcnRpZmljYXRlIEF1dGhvcml0eSAtIEcyMB4XDTA5
-MDkwMTAwMDAwMFoXDTM3MTIzMTIzNTk1OVowgZgxCzAJBgNVBAYTAlVTMRAwDgYD
-VQQIEwdBcml6b25hMRMwEQYDVQQHEwpTY290dHNkYWxlMSUwIwYDVQQKExxTdGFy
-ZmllbGQgVGVjaG5vbG9naWVzLCBJbmMuMTswOQYDVQQDEzJTdGFyZmllbGQgU2Vy
-dmljZXMgUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkgLSBHMjCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBANUMOsQq+U7i9b4Zl1+OiFOxHz/Lz58gE20p
-OsgPfTz3a3Y4Y9k2YKibXlwAgLIvWX/2h/klQ4bnaRtSmpDhcePYLQ1Ob/bISdm2
-8xpWriu2dBTrz/sm4xq6HZYuajtYlIlHVv8loJNwU4PahHQUw2eeBGg6345AWh1K
-Ts9DkTvnVtYAcMtS7nt9rjrnvDH5RfbCYM8TWQIrgMw0R9+53pBlbQLPLJGmpufe
-hRhJfGZOozptqbXuNC66DQO4M99H67FrjSXZm86B0UVGMpZwh94CDklDhbZsc7tk
-6mFBrMnUVN+HL8cisibMn1lUaJ/8viovxFUcdUBgF4UCVTmLfwUCAwEAAaNCMEAw
-DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFJxfAN+q
-AdcwKziIorhtSpzyEZGDMA0GCSqGSIb3DQEBCwUAA4IBAQBLNqaEd2ndOxmfZyMI
-bw5hyf2E3F/YNoHN2BtBLZ9g3ccaaNnRbobhiCPPE95Dz+I0swSdHynVv/heyNXB
-ve6SbzJ08pGCL72CQnqtKrcgfU28elUSwhXqvfdqlS5sdJ/PHLTyxQGjhdByPq1z
-qwubdQxtRbeOlKyWN7Wg0I8VRw7j6IPdj/3vQQF3zCepYoUz8jcI73HPdwbeyBkd
-iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
-0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
-sSi6
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Commercial O=AffirmTrust
-# Subject: CN=AffirmTrust Commercial O=AffirmTrust
-# Label: "AffirmTrust Commercial"
-# Serial: 8608355977964138876
-# MD5 Fingerprint: 82:92:ba:5b:ef:cd:8a:6f:a6:3d:55:f9:84:f6:d6:b7
-# SHA1 Fingerprint: f9:b5:b6:32:45:5f:9c:be:ec:57:5f:80:dc:e9:6e:2c:c7:b2:78:b7
-# SHA256 Fingerprint: 03:76:ab:1d:54:c5:f9:80:3c:e4:b2:e2:01:a0:ee:7e:ef:7b:57:b6:36:e8:a9:3c:9b:8d:48:60:c9:6f:5f:a7
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBDb21tZXJjaWFsMB4XDTEwMDEyOTE0MDYwNloXDTMwMTIzMTE0MDYwNlowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBDb21tZXJjaWFsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEA9htPZwcroRX1BiLLHwGy43NFBkRJLLtJJRTWzsO3qyxPxkEylFf6EqdbDuKP
-Hx6GGaeqtS25Xw2Kwq+FNXkyLbscYjfysVtKPcrNcV/pQr6U6Mje+SJIZMblq8Yr
-ba0F8PrVC8+a5fBQpIs7R6UjW3p6+DM/uO+Zl+MgwdYoic+U+7lF7eNAFxHUdPAL
-MeIrJmqbTFeurCA+ukV6BfO9m2kVrn1OIGPENXY6BwLJN/3HR+7o8XYdcxXyl6S1
-yHp52UKqK39c/s4mT6NmgTWvRLpUHhwwMmWd5jyTXlBOeuM61G7MGvv50jeuJCqr
-VwMiKA1JdX+3KNp1v47j3A55MQIDAQABo0IwQDAdBgNVHQ4EFgQUnZPGU4teyq8/
-nx4P5ZmVvCT2lI8wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQELBQADggEBAFis9AQOzcAN/wr91LoWXym9e2iZWEnStB03TX8nfUYG
-XUPGhi4+c7ImfU+TqbbEKpqrIZcUsd6M06uJFdhrJNTxFq7YpFzUf1GO7RgBsZNj
-vbz4YYCanrHOQnDiqX0GJX0nof5v7LMeJNrjS1UaADs1tDvZ110w/YETifLCBivt
-Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
-N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
-nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Networking O=AffirmTrust
-# Subject: CN=AffirmTrust Networking O=AffirmTrust
-# Label: "AffirmTrust Networking"
-# Serial: 8957382827206547757
-# MD5 Fingerprint: 42:65:ca:be:01:9a:9a:4c:a9:8c:41:49:cd:c0:d5:7f
-# SHA1 Fingerprint: 29:36:21:02:8b:20:ed:02:f5:66:c5:32:d1:d6:ed:90:9f:45:00:2f
-# SHA256 Fingerprint: 0a:81:ec:5a:92:97:77:f1:45:90:4a:f3:8d:5d:50:9f:66:b5:e2:c5:8f:cd:b5:31:05:8b:0e:17:f3:f0:b4:1b
------BEGIN CERTIFICATE-----
-MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
-dCBOZXR3b3JraW5nMB4XDTEwMDEyOTE0MDgyNFoXDTMwMTIzMTE0MDgyNFowRDEL
-MAkGA1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZp
-cm1UcnVzdCBOZXR3b3JraW5nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAtITMMxcua5Rsa2FSoOujz3mUTOWUgJnLVWREZY9nZOIG41w3SfYvm4SEHi3y
-YJ0wTsyEheIszx6e/jarM3c1RNg1lho9Nuh6DtjVR6FqaYvZ/Ls6rnla1fTWcbua
-kCNrmreIdIcMHl+5ni36q1Mr3Lt2PpNMCAiMHqIjHNRqrSK6mQEubWXLviRmVSRL
-QESxG9fhwoXA3hA/Pe24/PHxI1Pcv2WXb9n5QHGNfb2V1M6+oF4nI979ptAmDgAp
-6zxG8D1gvz9Q0twmQVGeFDdCBKNwV6gbh+0t+nvujArjqWaJGctB+d1ENmHP4ndG
-yH329JKBNv3bNPFyfvMMFr20FQIDAQABo0IwQDAdBgNVHQ4EFgQUBx/S55zawm6i
-QLSwelAQUHTEyL0wDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwDQYJ
-KoZIhvcNAQEFBQADggEBAIlXshZ6qML91tmbmzTCnLQyFE2npN/svqe++EPbkTfO
-tDIuUFUaNU52Q3Eg75N3ThVwLofDwR1t3Mu1J9QsVtFSUzpE0nPIxBsFZVpikpzu
-QY0x2+c06lkh1QF612S4ZDnNye2v7UsDSKegmQGA3GWjNq5lWUhPgkvIZfFXHeVZ
-Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
-olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
-x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium O=AffirmTrust
-# Subject: CN=AffirmTrust Premium O=AffirmTrust
-# Label: "AffirmTrust Premium"
-# Serial: 7893706540734352110
-# MD5 Fingerprint: c4:5d:0e:48:b6:ac:28:30:4e:0a:bc:f9:38:16:87:57
-# SHA1 Fingerprint: d8:a6:33:2c:e0:03:6f:b1:85:f6:63:4f:7d:6a:06:65:26:32:28:27
-# SHA256 Fingerprint: 70:a7:3f:7f:37:6b:60:07:42:48:90:45:34:b1:14:82:d5:bf:0e:69:8e:cc:49:8d:f5:25:77:eb:f2:e9:3b:9a
------BEGIN CERTIFICATE-----
-MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
-BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
-dCBQcmVtaXVtMB4XDTEwMDEyOTE0MTAzNloXDTQwMTIzMTE0MTAzNlowQTELMAkG
-A1UEBhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1U
-cnVzdCBQcmVtaXVtMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxBLf
-qV/+Qd3d9Z+K4/as4Tx4mrzY8H96oDMq3I0gW64tb+eT2TZwamjPjlGjhVtnBKAQ
-JG9dKILBl1fYSCkTtuG+kU3fhQxTGJoeJKJPj/CihQvL9Cl/0qRY7iZNyaqoe5rZ
-+jjeRFcV5fiMyNlI4g0WJx0eyIOFJbe6qlVBzAMiSy2RjYvmia9mx+n/K+k8rNrS
-s8PhaJyJ+HoAVt70VZVs+7pk3WKL3wt3MutizCaam7uqYoNMtAZ6MMgpv+0GTZe5
-HMQxK9VfvFMSF5yZVylmd2EhMQcuJUmdGPLu8ytxjLW6OQdJd/zvLpKQBY0tL3d7
-70O/Nbua2Plzpyzy0FfuKE4mX4+QaAkvuPjcBukumj5Rp9EixAqnOEhss/n/fauG
-V+O61oV4d7pD6kh/9ti+I20ev9E2bFhc8e6kGVQa9QPSdubhjL08s9NIS+LI+H+S
-qHZGnEJlPqQewQcDWkYtuJfzt9WyVSHvutxMAJf7FJUnM7/oQ0dG0giZFmA7mn7S
-5u046uwBHjxIVkkJx0w3AJ6IDsBz4W9m6XJHMD4Q5QsDyZpCAGzFlH5hxIrff4Ia
-C1nEWTJ3s7xgaVY5/bQGeyzWZDbZvUjthB9+pSKPKrhC9IK31FOQeE4tGv2Bb0TX
-OwF0lkLgAOIua+rF7nKsu7/+6qqo+Nz2snmKtmcCAwEAAaNCMEAwHQYDVR0OBBYE
-FJ3AZ6YMItkm9UWrpmVSESfYRaxjMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
-BAQDAgEGMA0GCSqGSIb3DQEBDAUAA4ICAQCzV00QYk465KzquByvMiPIs0laUZx2
-KI15qldGF9X1Uva3ROgIRL8YhNILgM3FEv0AVQVhh0HctSSePMTYyPtwni94loMg
-Nt58D2kTiKV1NpgIpsbfrM7jWNa3Pt668+s0QNiigfV4Py/VpfzZotReBA4Xrf5B
-8OWycvpEgjNC6C1Y91aMYj+6QrCcDFx+LmUmXFNPALJ4fqENmS2NuB2OosSw/WDQ
-MKSOyARiqcTtNd56l+0OOF6SL5Nwpamcb6d9Ex1+xghIsV5n61EIJenmJWtSKZGc
-0jlzCFfemQa0W50QBuHCAKi4HEoCChTQwUHK+4w1IX2COPKpVJEZNZOUbWo6xbLQ
-u4mGk+ibyQ86p3q4ofB4Rvr8Ny/lioTz3/4E2aFooC8k4gmVBtWVyuEklut89pMF
-u+1z6S3RdTnX5yTb2E5fQ4+e0BQ5v1VwSJlXMbSc7kqYA5YwH2AG7hsj/oFgIxpH
-YoWlzBk0gG+zrBrjn/B7SK3VAdlntqlyk+otZrWyuOQ9PLLvTIzq6we/qzWaVYa8
-GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
-RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
-KeC2uAloGRwYQw==
------END CERTIFICATE-----
-
-# Issuer: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Subject: CN=AffirmTrust Premium ECC O=AffirmTrust
-# Label: "AffirmTrust Premium ECC"
-# Serial: 8401224907861490260
-# MD5 Fingerprint: 64:b0:09:55:cf:b1:d5:99:e2:be:13:ab:a6:5d:ea:4d
-# SHA1 Fingerprint: b8:23:6b:00:2f:1d:16:86:53:01:55:6c:11:a4:37:ca:eb:ff:c3:bb
-# SHA256 Fingerprint: bd:71:fd:f6:da:97:e4:cf:62:d1:64:7a:dd:25:81:b0:7d:79:ad:f8:39:7e:b4:ec:ba:9c:5e:84:88:82:14:23
------BEGIN CERTIFICATE-----
-MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
-VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
-cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
-BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
-VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
-0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
-ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
-A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
-aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
-flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority
-# Subject: CN=Certum Trusted Network CA O=Unizeto Technologies S.A. OU=Certum Certification Authority
-# Label: "Certum Trusted Network CA"
-# Serial: 279744
-# MD5 Fingerprint: d5:e9:81:40:c5:18:69:fc:46:2c:89:75:62:0f:aa:78
-# SHA1 Fingerprint: 07:e0:32:e0:20:b7:2c:3f:19:2f:06:28:a2:59:3a:19:a7:0f:06:9e
-# SHA256 Fingerprint: 5c:58:46:8d:55:f5:8e:49:7e:74:39:82:d2:b5:00:10:b6:d1:65:37:4a:cf:83:a7:d4:a3:2d:b7:68:c4:40:8e
------BEGIN CERTIFICATE-----
-MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
-MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
-ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
-cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
-WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
-Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
-IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
-UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
-TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
-BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
-kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
-AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
-HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
-sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
-I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
-J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
-VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
-03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
------END CERTIFICATE-----
-
-# Issuer: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
-# Subject: CN=TWCA Root Certification Authority O=TAIWAN-CA OU=Root CA
-# Label: "TWCA Root Certification Authority"
-# Serial: 1
-# MD5 Fingerprint: aa:08:8f:f6:f9:7b:b7:f2:b1:a7:1e:9b:ea:ea:bd:79
-# SHA1 Fingerprint: cf:9e:87:6d:d3:eb:fc:42:26:97:a3:b5:a3:7a:a0:76:a9:06:23:48
-# SHA256 Fingerprint: bf:d8:8f:e1:10:1c:41:ae:3e:80:1b:f8:be:56:35:0e:e9:ba:d1:a6:b9:bd:51:5e:dc:5c:6d:5b:87:11:ac:44
------BEGIN CERTIFICATE-----
-MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES
-MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU
-V0NBIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMDgwODI4MDcyNDMz
-WhcNMzAxMjMxMTU1OTU5WjBfMQswCQYDVQQGEwJUVzESMBAGA1UECgwJVEFJV0FO
-LUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFUV0NBIFJvb3QgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIB
-AQCwfnK4pAOU5qfeCTiRShFAh6d8WWQUe7UREN3+v9XAu1bihSX0NXIP+FPQQeFE
-AcK0HMMxQhZHhTMidrIKbw/lJVBPhYa+v5guEGcevhEFhgWQxFnQfHgQsIBct+HH
-K3XLfJ+utdGdIzdjp9xCoi2SBBtQwXu4PhvJVgSLL1KbralW6cH/ralYhzC2gfeX
-RfwZVzsrb+RH9JlF/h3x+JejiB03HFyP4HYlmlD4oFT/RJB2I9IyxsOrBr/8+7/z
-rX2SYgJbKdM1o5OaQ2RgXbL6Mv87BK9NQGr5x+PvI/1ry+UPizgN7gr8/g+YnzAx
-3WxSZfmLgb4i4RxYA7qRG4kHAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqOFsmjd6LWvJPelSDGRjjCDWmujANBgkq
-hkiG9w0BAQUFAAOCAQEAPNV3PdrfibqHDAhUaiBQkr6wQT25JmSDCi/oQMCXKCeC
-MErJk/9q56YAf4lCmtYR5VPOL8zy2gXE/uJQxDqGfczafhAJO5I1KlOy/usrBdls
-XebQ79NqZp4VKIV66IIArB6nCWlWQtNoURi+VJq/REG6Sb4gumlc7rh3zc5sH62D
-lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
-aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
-YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
------END CERTIFICATE-----
-
-# Issuer: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2
-# Subject: O=SECOM Trust Systems CO.,LTD. OU=Security Communication RootCA2
-# Label: "Security Communication RootCA2"
-# Serial: 0
-# MD5 Fingerprint: 6c:39:7d:a4:0e:55:59:b2:3f:d6:41:b1:12:50:de:43
-# SHA1 Fingerprint: 5f:3b:8c:f2:f8:10:b3:7d:78:b4:ce:ec:19:19:c3:73:34:b9:c7:74
-# SHA256 Fingerprint: 51:3b:2c:ec:b8:10:d4:cd:e5:dd:85:39:1a:df:c6:c2:dd:60:d8:7b:b7:36:d2:b5:21:48:4a:a4:7a:0e:be:f6
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
-MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
-U2VjdXJpdHkgQ29tbXVuaWNhdGlvbiBSb290Q0EyMB4XDTA5MDUyOTA1MDAzOVoX
-DTI5MDUyOTA1MDAzOVowXTELMAkGA1UEBhMCSlAxJTAjBgNVBAoTHFNFQ09NIFRy
-dXN0IFN5c3RlbXMgQ08uLExURC4xJzAlBgNVBAsTHlNlY3VyaXR5IENvbW11bmlj
-YXRpb24gUm9vdENBMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAV
-OVKxUrO6xVmCxF1SrjpDZYBLx/KWvNs2l9amZIyoXvDjChz335c9S672XewhtUGr
-zbl+dp+++T42NKA7wfYxEUV0kz1XgMX5iZnK5atq1LXaQZAQwdbWQonCv/Q4EpVM
-VAX3NuRFg3sUZdbcDE3R3n4MqzvEFb46VqZab3ZpUql6ucjrappdUtAtCms1FgkQ
-hNBqyjoGADdH5H5XTz+L62e4iKrFvlNVspHEfbmwhRkGeC7bYRr6hfVKkaHnFtWO
-ojnflLhwHyg/i/xAXmODPIMqGplrz95Zajv8bxbXH/1KEOtOghY6rCcMU/Gt1SSw
-awNQwS08Ft1ENCcadfsCAwEAAaNCMEAwHQYDVR0OBBYEFAqFqXdlBZh8QIH4D5cs
-OPEK7DzPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3
-DQEBCwUAA4IBAQBMOqNErLlFsceTfsgLCkLfZOoc7llsCLqJX2rKSpWeeo8HxdpF
-coJxDjrSzG+ntKEju/Ykn8sX/oymzsLS28yN/HH8AynBbF0zX2S2ZTuJbxh2ePXc
-okgfGT+Ok+vx+hfuzU7jBBJV1uXk3fs+BXziHV7Gp7yXT2g69ekuCkO2r1dcYmh8
-t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
-1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
-SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
------END CERTIFICATE-----
-
-# Issuer: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
-# Subject: CN=Actalis Authentication Root CA O=Actalis S.p.A./03358520967
-# Label: "Actalis Authentication Root CA"
-# Serial: 6271844772424770508
-# MD5 Fingerprint: 69:c1:0d:4f:07:a3:1b:c3:fe:56:3d:04:bc:11:f6:a6
-# SHA1 Fingerprint: f3:73:b3:87:06:5a:28:84:8a:f2:f3:4a:ce:19:2b:dd:c7:8e:9c:ac
-# SHA256 Fingerprint: 55:92:60:84:ec:96:3a:64:b9:6e:2a:be:01:ce:0b:a8:6a:64:fb:fe:bc:c7:aa:b5:af:c1:55:b3:7f:d7:60:66
------BEGIN CERTIFICATE-----
-MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
-BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
-MzM1ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290
-IENBMB4XDTExMDkyMjExMjIwMloXDTMwMDkyMjExMjIwMlowazELMAkGA1UEBhMC
-SVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8wMzM1
-ODUyMDk2NzEnMCUGA1UEAwweQWN0YWxpcyBBdXRoZW50aWNhdGlvbiBSb290IENB
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAp8bEpSmkLO/lGMWwUKNv
-UTufClrJwkg4CsIcoBh/kbWHuUA/3R1oHwiD1S0eiKD4j1aPbZkCkpAW1V8IbInX
-4ay8IMKx4INRimlNAJZaby/ARH6jDuSRzVju3PvHHkVH3Se5CAGfpiEd9UEtL0z9
-KK3giq0itFZljoZUj5NDKd45RnijMCO6zfB9E1fAXdKDa0hMxKufgFpbOr3JpyI/
-gCczWw63igxdBzcIy2zSekciRDXFzMwujt0q7bd9Zg1fYVEiVRvjRuPjPdA1Yprb
-rxTIW6HMiRvhMCb8oJsfgadHHwTrozmSBp+Z07/T6k9QnBn+locePGX2oxgkg4YQ
-51Q+qDp2JE+BIcXjDwL4k5RHILv+1A7TaLndxHqEguNTVHnd25zS8gebLra8Pu2F
-be8lEfKXGkJh90qX6IuxEAf6ZYGyojnP9zz/GPvG8VqLWeICrHuS0E4UT1lF9gxe
-KF+w6D9Fz8+vm2/7hNN3WpVvrJSEnu68wEqPSpP4RCHiMUVhUE4Q2OM1fEwZtN4F
-v6MGn8i1zeQf1xcGDXqVdFUNaBr8EBtiZJ1t4JWgw5QHVw0U5r0F+7if5t+L4sbn
-fpb2U8WANFAoWPASUHEXMLrmeGO89LKtmyuy/uE5jF66CyCU3nuDuP/jVo23Eek7
-jPKxwV2dpAtMK9myGPW1n0sCAwEAAaNjMGEwHQYDVR0OBBYEFFLYiDrIn3hm7Ynz
-ezhwlMkCAjbQMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUUtiIOsifeGbt
-ifN7OHCUyQICNtAwDgYDVR0PAQH/BAQDAgEGMA0GCSqGSIb3DQEBCwUAA4ICAQAL
-e3KHwGCmSUyIWOYdiPcUZEim2FgKDk8TNd81HdTtBjHIgT5q1d07GjLukD0R0i70
-jsNjLiNmsGe+b7bAEzlgqqI0JZN1Ut6nna0Oh4lScWoWPBkdg/iaKWW+9D+a2fDz
-WochcYBNy+A4mz+7+uAwTc+G02UQGRjRlwKxK3JCaKygvU5a2hi/a5iB0P2avl4V
-SM0RFbnAKVy06Ij3Pjaut2L9HmLecHgQHEhb2rykOLpn7VU+Xlff1ANATIGk0k9j
-pwlCCRT8AKnCgHNPLsBA2RF7SOp6AsDT6ygBJlh0wcBzIm2Tlf05fbsq4/aC4yyX
-X04fkZT6/iyj2HYauE2yOE+b+h1IYHkm4vP9qdCa6HCPSXrW5b0KDtst842/6+Ok
-fcvHlXHo2qN8xcL4dJIEG4aspCJTQLas/kx2z/uUMsA1n3Y/buWQbqCmJqK4LL7R
-K4X9p2jIugErsWx0Hbhzlefut8cl8ABMALJ+tguLHPPAUJ4lueAI3jZm/zel0btU
-ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
-LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
-LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
------END CERTIFICATE-----
-
-# Issuer: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
-# Subject: CN=Buypass Class 2 Root CA O=Buypass AS-983163327
-# Label: "Buypass Class 2 Root CA"
-# Serial: 2
-# MD5 Fingerprint: 46:a7:d2:fe:45:fb:64:5a:a8:59:90:9b:78:44:9b:29
-# SHA1 Fingerprint: 49:0a:75:74:de:87:0a:47:fe:58:ee:f6:c7:6b:eb:c6:0b:12:40:99
-# SHA256 Fingerprint: 9a:11:40:25:19:7c:5b:b9:5d:94:e6:3d:55:cd:43:79:08:47:b6:46:b2:3c:df:11:ad:a4:a0:0e:ff:15:fb:48
------BEGIN CERTIFICATE-----
-MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
-MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
-Q2xhc3MgMiBSb290IENBMB4XDTEwMTAyNjA4MzgwM1oXDTQwMTAyNjA4MzgwM1ow
-TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
-HgYDVQQDDBdCdXlwYXNzIENsYXNzIDIgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBANfHXvfBB9R3+0Mh9PT1aeTuMgHbo4Yf5FkNuud1g1Lr
-6hxhFUi7HQfKjK6w3Jad6sNgkoaCKHOcVgb/S2TwDCo3SbXlzwx87vFKu3MwZfPV
-L4O2fuPn9Z6rYPnT8Z2SdIrkHJasW4DptfQxh6NR/Md+oW+OU3fUl8FVM5I+GC91
-1K2GScuVr1QGbNgGE41b/+EmGVnAJLqBcXmQRFBoJJRfuLMR8SlBYaNByyM21cHx
-MlAQTn/0hpPshNOOvEu/XAFOBz3cFIqUCqTqc/sLUegTBxj6DvEr0VQVfTzh97QZ
-QmdiXnfgolXsttlpF9U6r0TtSsWe5HonfOV116rLJeffawrbD02TTqigzXsu8lkB
-arcNuAeBfos4GzjmCleZPe4h6KP1DBbdi+w0jpwqHAAVF41og9JwnxgIzRFo1clr
-Us3ERo/ctfPYV3Me6ZQ5BL/T3jjetFPsaRyifsSP5BtwrfKi+fv3FmRmaZ9JUaLi
-FRhnBkp/1Wy1TbMz4GHrXb7pmA8y1x1LPC5aAVKRCfLf6o3YBkBjqhHk/sM3nhRS
-P/TizPJhk9H9Z2vXUq6/aKtAQ6BXNVN48FP4YUIHZMbXb5tMOA1jrGKvNouicwoN
-9SG9dKpN6nIDSdvHXx1iY8f93ZHsM+71bbRuMGjeyNYmsHVee7QHIJihdjK4TWxP
-AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFMmAd+BikoL1Rpzz
-uvdMw964o605MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAU18h
-9bqwOlI5LJKwbADJ784g7wbylp7ppHR/ehb8t/W2+xUbP6umwHJdELFx7rxP462s
-A20ucS6vxOOto70MEae0/0qyexAQH6dXQbLArvQsWdZHEIjzIVEpMMpghq9Gqx3t
-OluwlN5E40EIosHsHdb9T7bWR9AUC8rmyrV7d35BH16Dx7aMOZawP5aBQW9gkOLo
-+fsicdl9sz1Gv7SEr5AcD48Saq/v7h56rgJKihcrdv6sVIkkLE8/trKnToyokZf7
-KcZ7XC25y2a2t6hbElGFtQl+Ynhw/qlqYLYdDnkM/crqJIByw5c/8nerQyIKx+u2
-DISCLIBrQYoIwOula9+ZEsuK1V6ADJHgJgg2SMX6OBE1/yWDLfJ6v9r9jv6ly0Us
-H8SIU653DtmadsWOLB2jutXsMq7Aqqz30XpN69QH4kj3Io6wpJ9qzo6ysmD0oyLQ
-I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7
-5t98biGCwWg5TbSYWGZizEqQXsP6JwSxeRV0mcy+rSDeJmAc61ZRpqPq5KM/p/9h
-3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz
-Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
------END CERTIFICATE-----
-
-# Issuer: CN=Buypass Class 3 Root CA O=Buypass AS-983163327
-# Subject: CN=Buypass Class 3 Root CA O=Buypass AS-983163327
-# Label: "Buypass Class 3 Root CA"
-# Serial: 2
-# MD5 Fingerprint: 3d:3b:18:9e:2c:64:5a:e8:d5:88:ce:0e:f9:37:c2:ec
-# SHA1 Fingerprint: da:fa:f7:fa:66:84:ec:06:8f:14:50:bd:c7:c2:81:a5:bc:a9:64:57
-# SHA256 Fingerprint: ed:f7:eb:bc:a2:7a:2a:38:4d:38:7b:7d:40:10:c6:66:e2:ed:b4:84:3e:4c:29:b4:ae:1d:5b:93:32:e6:b2:4d
------BEGIN CERTIFICATE-----
-MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
-MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
-Q2xhc3MgMyBSb290IENBMB4XDTEwMTAyNjA4Mjg1OFoXDTQwMTAyNjA4Mjg1OFow
-TjELMAkGA1UEBhMCTk8xHTAbBgNVBAoMFEJ1eXBhc3MgQVMtOTgzMTYzMzI3MSAw
-HgYDVQQDDBdCdXlwYXNzIENsYXNzIDMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEB
-BQADggIPADCCAgoCggIBAKXaCpUWUOOV8l6ddjEGMnqb8RB2uACatVI2zSRHsJ8Y
-ZLya9vrVediQYkwiL944PdbgqOkcLNt4EemOaFEVcsfzM4fkoF0LXOBXByow9c3E
-N3coTRiR5r/VUv1xLXA+58bEiuPwKAv0dpihi4dVsjoT/Lc+JzeOIuOoTyrvYLs9
-tznDDgFHmV0ST9tD+leh7fmdvhFHJlsTmKtdFoqwNxxXnUX/iJY2v7vKB3tvh2PX
-0DJq1l1sDPGzbjniazEuOQAnFN44wOwZZoYS6J1yFhNkUsepNxz9gjDthBgd9K5c
-/3ATAOux9TN6S9ZV+AWNS2mw9bMoNlwUxFFzTWsL8TQH2xc519woe2v1n/MuwU8X
-KhDzzMro6/1rqy6any2CbgTUUgGTLT2G/H783+9CHaZr77kgxve9oKeV/afmiSTY
-zIw0bOIjL9kSGiG5VZFvC5F5GQytQIgLcOJ60g7YaEi7ghM5EFjp2CoHxhLbWNvS
-O1UQRwUVZ2J+GGOmRj8JDlQyXr8NYnon74Do29lLBlo3WiXQCBJ31G8JUJc9yB3D
-34xFMFbG02SrZvPAXpacw8Tvw3xrizp5f7NJzz3iiZ+gMEuFuZyUJHmPfWupRWgP
-K9Dx2hzLabjKSWJtyNBjYt1gD1iqj6G8BaVmos8bdrKEZLFMOVLAMLrwjEsCsLa3
-AgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFEe4zf/lb+74suwv
-Tg75JbCOPGvDMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAACAj
-QTUEkMJAYmDv4jVM1z+s4jSQuKFvdvoWFqRINyzpkMLyPPgKn9iB5btb2iUspKdV
-cSQy9sgL8rxq+JOssgfCX5/bzMiKqr5qb+FJEMwx14C7u8jYog5kV+qi9cKpMRXS
-IGrs/CIBKM+GuIAeqcwRpTzyFrNHnfzSgCHEy9BHcEGhyoMZCCxt8l13nIoUE9Q2
-HJLw5QY33KbmkJs4j1xrG0aGQ0JfPgEHU1RdZX33inOhmlRaHylDFCfChQ+1iHsa
-O5S3HWCntZznKWlXWpuTekMwGwPXYshApqr8ZORK15FTAaggiG6cX0S5y2CBNOxv
-033aSF/rtJC8LakcC6wc1aJoIIAE1vyxjy+7SjENSoYc6+I2KSb12tjE8nVhz36u
-dmNKekBlk4f4HoCMhuWG1o8O/FMsYOgWYRqiPkN7zTlgVGr18okmAWiDSKIz6MkE
-kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41
-3OEMXbugUZTLfhbrES+jkkXITHHZvMmZUldGL1DPvTVp9D0VzgalLA8+9oG6lLvD
-u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
-4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=
------END CERTIFICATE-----
-
-# Issuer: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
-# Subject: CN=T-TeleSec GlobalRoot Class 3 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
-# Label: "T-TeleSec GlobalRoot Class 3"
-# Serial: 1
-# MD5 Fingerprint: ca:fb:40:a8:4e:39:92:8a:1d:fe:8e:2f:c4:27:ea:ef
-# SHA1 Fingerprint: 55:a6:72:3e:cb:f2:ec:cd:c3:23:74:70:19:9d:2a:be:11:e3:81:d1
-# SHA256 Fingerprint: fd:73:da:d3:1c:64:4f:f1:b4:3b:ef:0c:cd:da:96:71:0b:9c:d9:87:5e:ca:7e:31:70:7a:f3:e9:6d:52:2b:bd
------BEGIN CERTIFICATE-----
-MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
-KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
-BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
-YyBHbG9iYWxSb290IENsYXNzIDMwHhcNMDgxMDAxMTAyOTU2WhcNMzMxMDAxMjM1
-OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
-aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
-ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDMwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC9dZPwYiJvJK7genasfb3ZJNW4t/zN
-8ELg63iIVl6bmlQdTQyK9tPPcPRStdiTBONGhnFBSivwKixVA9ZIw+A5OO3yXDw/
-RLyTPWGrTs0NvvAgJ1gORH8EGoel15YUNpDQSXuhdfsaa3Ox+M6pCSzyU9XDFES4
-hqX2iys52qMzVNn6chr3IhUciJFrf2blw2qAsCTz34ZFiP0Zf3WHHx+xGwpzJFu5
-ZeAsVMhg02YXP+HMVDNzkQI6pn97djmiH5a2OK61yJN0HZ65tOVgnS9W0eDrXltM
-EnAMbEQgqxHY9Bn20pxSN+f6tsIxO0rUFJmtxxr1XV/6B7h8DR/Wgx6zAgMBAAGj
-QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS1
-A/d2O2GCahKqGFPrAyGUv/7OyjANBgkqhkiG9w0BAQsFAAOCAQEAVj3vlNW92nOy
-WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
-1GSFS5mvJQQeyUapl96Cshtwn5z2r3Ex3XsFpSzTucpH9sry9uetuUg/vBa3wW30
-6gmv7PO15wWeph6KU1HWk4HMdJP2udqmJQV0eVp+QD6CSyYRMG7hP0HHRwA11fXT
-91Q+gT3aSWqas+8QPebrb9HIIkfLzM8BMZLZGOMivgkeGj5asuRrDFR6fUNOuIml
-e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
-TpPDpFQUWw==
------END CERTIFICATE-----
-
-# Issuer: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH
-# Subject: CN=D-TRUST Root Class 3 CA 2 2009 O=D-Trust GmbH
-# Label: "D-TRUST Root Class 3 CA 2 2009"
-# Serial: 623603
-# MD5 Fingerprint: cd:e0:25:69:8d:47:ac:9c:89:35:90:f7:fd:51:3d:2f
-# SHA1 Fingerprint: 58:e8:ab:b0:36:15:33:fb:80:f7:9b:1b:6d:29:d3:ff:8d:5f:00:f0
-# SHA256 Fingerprint: 49:e7:a4:42:ac:f0:ea:62:87:05:00:54:b5:25:64:b6:50:e4:f4:9e:42:e3:48:d6:aa:38:e0:39:e9:57:b1:c1
------BEGIN CERTIFICATE-----
-MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
-MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
-bGFzcyAzIENBIDIgMjAwOTAeFw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NTha
-ME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMM
-HkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIwDQYJKoZIhvcNAQEB
-BQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOADER03
-UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42
-tSHKXzlABF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9R
-ySPocq60vFYJfxLLHLGvKZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsM
-lFqVlNpQmvH/pStmMaTJOKDfHR+4CS7zp+hnUquVH+BGPtikw8paxTGA6Eian5Rp
-/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUCAwEAAaOCARowggEWMA8G
-A1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ4PGEMA4G
-A1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVj
-dG9yeS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUy
-MENBJTIwMiUyMDIwMDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRl
-cmV2b2NhdGlvbmxpc3QwQ6BBoD+GPWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3Js
-L2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAwOS5jcmwwDQYJKoZIhvcNAQEL
-BQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm2H6NMLVwMeni
-acfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0
-o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4K
-zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
-PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
-Johw1+qRzT65ysCQblrGXnRl11z+o+I=
------END CERTIFICATE-----
-
-# Issuer: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH
-# Subject: CN=D-TRUST Root Class 3 CA 2 EV 2009 O=D-Trust GmbH
-# Label: "D-TRUST Root Class 3 CA 2 EV 2009"
-# Serial: 623604
-# MD5 Fingerprint: aa:c6:43:2c:5e:2d:cd:c4:34:c0:50:4f:11:02:4f:b6
-# SHA1 Fingerprint: 96:c9:1b:0b:95:b4:10:98:42:fa:d0:d8:22:79:fe:60:fa:b9:16:83
-# SHA256 Fingerprint: ee:c5:49:6b:98:8c:e9:86:25:b9:34:09:2e:ec:29:08:be:d0:b0:f3:16:c2:d4:73:0c:84:ea:f1:f3:d3:48:81
------BEGIN CERTIFICATE-----
-MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF
-MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD
-bGFzcyAzIENBIDIgRVYgMjAwOTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUw
-NDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNV
-BAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAwOTCCASIwDQYJKoZI
-hvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfSegpn
-ljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM0
-3TP1YtHhzRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6Z
-qQTMFexgaDbtCHu39b+T7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lR
-p75mpoo6Kr3HGrHhFPC+Oh25z1uxav60sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8
-HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure3511H3a6UCAwEAAaOCASQw
-ggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyvcop9Ntea
-HNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFw
-Oi8vZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xh
-c3MlMjAzJTIwQ0ElMjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1E
-RT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MEagRKBChkBodHRwOi8vd3d3LmQt
-dHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xhc3NfM19jYV8yX2V2XzIwMDku
-Y3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+PPoeUSbrh/Yp
-3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05
-nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNF
-CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
-xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
-KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
------END CERTIFICATE-----
-
-# Issuer: CN=CA Disig Root R2 O=Disig a.s.
-# Subject: CN=CA Disig Root R2 O=Disig a.s.
-# Label: "CA Disig Root R2"
-# Serial: 10572350602393338211
-# MD5 Fingerprint: 26:01:fb:d8:27:a7:17:9a:45:54:38:1a:43:01:3b:03
-# SHA1 Fingerprint: b5:61:eb:ea:a4:de:e4:25:4b:69:1a:98:a5:57:47:c2:34:c7:d9:71
-# SHA256 Fingerprint: e2:3d:4a:03:6d:7b:70:e9:f5:95:b1:42:20:79:d2:b9:1e:df:bb:1f:b6:51:a0:63:3e:aa:8a:9d:c5:f8:07:03
------BEGIN CERTIFICATE-----
-MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
-BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
-MRkwFwYDVQQDExBDQSBEaXNpZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQy
-MDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sxEzARBgNVBAcTCkJyYXRpc2xhdmEx
-EzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERpc2lnIFJvb3QgUjIw
-ggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbCw3Oe
-NcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNH
-PWSb6WiaxswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3I
-x2ymrdMxp7zo5eFm1tL7A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbe
-QTg06ov80egEFGEtQX6sx3dOy1FU+16SGBsEWmjGycT6txOgmLcRK7fWV8x8nhfR
-yyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqVg8NTEQxzHQuyRpDRQjrO
-QG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa5Beny912
-H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJ
-QfYEkoopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUD
-i/ZnWejBBhG93c+AAk9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORs
-nLMOPReisjQS1n6yqEm70XooQL6iFh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1
-rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1Ud
-DwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5uQu0wDQYJKoZI
-hvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM
-tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqf
-GopTpti72TVVsRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkb
-lvdhuDvEK7Z4bLQjb/D907JedR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka
-+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W81k/BfDxujRNt+3vrMNDcTa/F1bal
-TFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjxmHHEt38OFdAlab0i
-nSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01utI3
-gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18Dr
-G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os
-zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x
-L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL
------END CERTIFICATE-----
-
-# Issuer: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV
-# Subject: CN=ACCVRAIZ1 O=ACCV OU=PKIACCV
-# Label: "ACCVRAIZ1"
-# Serial: 6828503384748696800
-# MD5 Fingerprint: d0:a0:5a:ee:05:b6:09:94:21:a1:7d:f1:b2:29:82:02
-# SHA1 Fingerprint: 93:05:7a:88:15:c6:4f:ce:88:2f:fa:91:16:52:28:78:bc:53:64:17
-# SHA256 Fingerprint: 9a:6e:c0:12:e1:a7:da:9d:be:34:19:4d:47:8a:d7:c0:db:18:22:fb:07:1d:f1:29:81:49:6e:d1:04:38:41:13
------BEGIN CERTIFICATE-----
-MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UE
-AwwJQUNDVlJBSVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQsw
-CQYDVQQGEwJFUzAeFw0xMTA1MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQ
-BgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwHUEtJQUNDVjENMAsGA1UECgwEQUND
-VjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCb
-qau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gMjmoY
-HtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWo
-G2ioPej0RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpA
-lHPrzg5XPAOBOp0KoVdDaaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhr
-IA8wKFSVf+DuzgpmndFALW4ir50awQUZ0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/
-0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDGWuzndN9wrqODJerWx5eH
-k6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs78yM2x/47
-4KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMO
-m3WR5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpa
-cXpkatcnYGMN285J9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPl
-uUsXQA+xtrn13k/c4LOsOxFwYIRKQ26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYI
-KwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRwOi8vd3d3LmFjY3YuZXMvZmls
-ZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEuY3J0MB8GCCsG
-AQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2
-VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeT
-VfZW6oHlNsyMHj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIG
-CCsGAQUFBwICMIIBFB6CARAAQQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUA
-cgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBhAO0AegAgAGQAZQAgAGwAYQAgAEEA
-QwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUAYwBuAG8AbABvAGcA
-7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBjAHQA
-cgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAA
-QwBQAFMAIABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUA
-czAwBggrBgEFBQcCARYkaHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2Mu
-aHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRt
-aW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2MV9kZXIuY3JsMA4GA1Ud
-DwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZIhvcNAQEF
-BQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdp
-D70ER9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gU
-JyCpZET/LtZ1qmxNYEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+m
-AM/EKXMRNt6GGT6d7hmKG9Ww7Y49nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepD
-vV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJTS+xJlsndQAJxGJ3KQhfnlms
-tn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3sCPdK6jT2iWH
-7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h
-I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szA
-h1xA2syVP1XgNce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xF
-d3+YJ5oyXSrjhO7FmGYvliAd3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2H
-pPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3pEfbRD0tVNEYqi4Y7
------END CERTIFICATE-----
-
-# Issuer: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA
-# Subject: CN=TWCA Global Root CA O=TAIWAN-CA OU=Root CA
-# Label: "TWCA Global Root CA"
-# Serial: 3262
-# MD5 Fingerprint: f9:03:7e:cf:e6:9e:3c:73:7a:2a:90:07:69:ff:2b:96
-# SHA1 Fingerprint: 9c:bb:48:53:f6:a4:f6:d3:52:a4:e8:32:52:55:60:13:f5:ad:af:65
-# SHA256 Fingerprint: 59:76:90:07:f7:68:5d:0f:cd:50:87:2f:9f:95:d5:75:5a:5b:2b:45:7d:81:f3:69:2b:61:0a:98:67:2f:0e:1b
------BEGIN CERTIFICATE-----
-MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx
-EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT
-VFdDQSBHbG9iYWwgUm9vdCBDQTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5
-NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQKEwlUQUlXQU4tQ0ExEDAOBgNVBAsT
-B1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3QgQ0EwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2CnJfF
-10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz
-0ALfUPZVr2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfCh
-MBwqoJimFb3u/Rk28OKRQ4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbH
-zIh1HrtsBv+baz4X7GGqcXzGHaL3SekVtTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc
-46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1WKKD+u4ZqyPpcC1jcxkt2
-yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99sy2sbZCi
-laLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYP
-oA/pyJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQA
-BDzfuBSO6N+pjWxnkjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcE
-qYSjMq+u7msXi7Kx/mzhkIyIqJdIzshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm
-4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6gcFGn90xHNcgL
-1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn
-LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WF
-H6vPNOw/KP4M8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNo
-RI2T9GRwoD2dKAXDOXC4Ynsg/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+
-nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlglPx4mI88k1HtQJAH32RjJMtOcQWh
-15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryPA9gK8kxkRr05YuWW
-6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3mi4TW
-nsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5j
-wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz
-aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy
-KwbQBM0=
------END CERTIFICATE-----
-
-# Issuer: CN=TeliaSonera Root CA v1 O=TeliaSonera
-# Subject: CN=TeliaSonera Root CA v1 O=TeliaSonera
-# Label: "TeliaSonera Root CA v1"
-# Serial: 199041966741090107964904287217786801558
-# MD5 Fingerprint: 37:41:49:1b:18:56:9a:26:f5:ad:c2:66:fb:40:a5:4c
-# SHA1 Fingerprint: 43:13:bb:96:f1:d5:86:9b:c1:4e:6a:92:f6:cf:f6:34:69:87:82:37
-# SHA256 Fingerprint: dd:69:36:fe:21:f8:f0:77:c1:23:a1:a5:21:c1:22:24:f7:22:55:b7:3e:03:a7:26:06:93:e8:a2:4b:0f:a3:89
------BEGIN CERTIFICATE-----
-MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
-NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
-b3QgQ0EgdjEwHhcNMDcxMDE4MTIwMDUwWhcNMzIxMDE4MTIwMDUwWjA3MRQwEgYD
-VQQKDAtUZWxpYVNvbmVyYTEfMB0GA1UEAwwWVGVsaWFTb25lcmEgUm9vdCBDQSB2
-MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMK+6yfwIaPzaSZVfp3F
-VRaRXP3vIb9TgHot0pGMYzHw7CTww6XScnwQbfQ3t+XmfHnqjLWCi65ItqwA3GV1
-7CpNX8GH9SBlK4GoRz6JI5UwFpB/6FcHSOcZrr9FZ7E3GwYq/t75rH2D+1665I+X
-Z75Ljo1kB1c4VWk0Nj0TSO9P4tNmHqTPGrdeNjPUtAa9GAH9d4RQAEX1jF3oI7x+
-/jXh7VB7qTCNGdMJjmhnXb88lxhTuylixcpecsHHltTbLaC0H2kD7OriUPEMPPCs
-81Mt8Bz17Ww5OXOAFshSsCPN4D7c3TxHoLs1iuKYaIu+5b9y7tL6pe0S7fyYGKkm
-dtwoSxAgHNN/Fnct7W+A90m7UwW7XWjH1Mh1Fj+JWov3F0fUTPHSiXk+TT2YqGHe
-Oh7S+F4D4MHJHIzTjU3TlTazN19jY5szFPAtJmtTfImMMsJu7D0hADnJoWjiUIMu
-sDor8zagrC/kb2HCUQk5PotTubtn2txTuXZZNp1D5SDgPTJghSJRt8czu90VL6R4
-pgd7gUY2BIbdeTXHlSw7sKMXNeVzH7RcWe/a6hBle3rQf5+ztCo3O3CLm1u5K7fs
-slESl1MpWtTwEhDcTwK7EpIvYtQ/aUN8Ddb8WHUBiJ1YFkveupD/RwGJBmr2X7KQ
-arMCpgKIv7NHfirZ1fpoeDVNAgMBAAGjPzA9MA8GA1UdEwEB/wQFMAMBAf8wCwYD
-VR0PBAQDAgEGMB0GA1UdDgQWBBTwj1k4ALP1j5qWDNXr+nuqF+gTEjANBgkqhkiG
-9w0BAQUFAAOCAgEAvuRcYk4k9AwI//DTDGjkk0kiP0Qnb7tt3oNmzqjMDfz1mgbl
-dxSR651Be5kqhOX//CHBXfDkH1e3damhXwIm/9fH907eT/j3HEbAek9ALCI18Bmx
-0GtnLLCo4MBANzX2hFxc469CeP6nyQ1Q6g2EdvZR74NTxnr/DlZJLo961gzmJ1Tj
-TQpgcmLNkQfWpb/ImWvtxBnmq0wROMVvMeJuScg/doAmAyYp4Db29iBT4xdwNBed
-Y2gea+zDTYa4EzAvXUYNR0PVG6pZDrlcjQZIrXSHX8f8MVRBE+LHIQ6e4B4N4cB7
-Q4WQxYpYxmUKeFfyxiMPAdkgS94P+5KFdSpcc41teyWRyu5FrgZLAMzTsVlQ2jqI
-OylDRl6XK1TOU2+NSueW+r9xDkKLfP0ooNBIytrEgUy7onOTJsjrDNYmiLbAJM+7
-vVvrdX3pCI6GMyx5dwlppYn8s3CQh3aP0yK7Qs69cwsgJirQmz1wHiRszYd2qReW
-t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn
-HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
-SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
------END CERTIFICATE-----
-
-# Issuer: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
-# Subject: CN=T-TeleSec GlobalRoot Class 2 O=T-Systems Enterprise Services GmbH OU=T-Systems Trust Center
-# Label: "T-TeleSec GlobalRoot Class 2"
-# Serial: 1
-# MD5 Fingerprint: 2b:9b:9e:e4:7b:6c:1f:00:72:1a:cc:c1:77:79:df:6a
-# SHA1 Fingerprint: 59:0d:2d:7d:88:4f:40:2e:61:7e:a5:62:32:17:65:cf:17:d8:94:e9
-# SHA256 Fingerprint: 91:e2:f5:78:8d:58:10:eb:a7:ba:58:73:7d:e1:54:8a:8e:ca:cd:01:45:98:bc:0b:14:3e:04:1b:17:05:25:52
------BEGIN CERTIFICATE-----
-MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
-KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
-BgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50ZXIxJTAjBgNVBAMMHFQtVGVsZVNl
-YyBHbG9iYWxSb290IENsYXNzIDIwHhcNMDgxMDAxMTA0MDE0WhcNMzMxMDAxMjM1
-OTU5WjCBgjELMAkGA1UEBhMCREUxKzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnBy
-aXNlIFNlcnZpY2VzIEdtYkgxHzAdBgNVBAsMFlQtU3lzdGVtcyBUcnVzdCBDZW50
-ZXIxJTAjBgNVBAMMHFQtVGVsZVNlYyBHbG9iYWxSb290IENsYXNzIDIwggEiMA0G
-CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCqX9obX+hzkeXaXPSi5kfl82hVYAUd
-AqSzm1nzHoqvNK38DcLZSBnuaY/JIPwhqgcZ7bBcrGXHX+0CfHt8LRvWurmAwhiC
-FoT6ZrAIxlQjgeTNuUk/9k9uN0goOA/FvudocP05l03Sx5iRUKrERLMjfTlH6VJi
-1hKTXrcxlkIF+3anHqP1wvzpesVsqXFP6st4vGCvx9702cu+fjOlbpSD8DT6Iavq
-jnKgP6TeMFvvhk1qlVtDRKgQFRzlAVfFmPHmBiiRqiDFt1MmUUOyCxGVWOHAD3bZ
-wI18gfNycJ5v/hqO2V81xrJvNHy+SE/iWjnX2J14np+GPgNeGYtEotXHAgMBAAGj
-QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBS/
-WSA2AHmgoCJrjNXyYdK4LMuCSjANBgkqhkiG9w0BAQsFAAOCAQEAMQOiYQsfdOhy
-NsZt+U2e+iKo4YFWz827n+qrkRk4r6p8FU3ztqONpfSO9kSpp+ghla0+AGIWiPAC
-uvxhI+YzmzB6azZie60EI4RYZeLbK4rnJVM3YlNfvNoBYimipidx5joifsFvHZVw
-IEoHNN/q/xWA5brXethbdXwFeilHfkCoMRN3zUA7tFFHei4R40cR3p1m0IvVVGb6
-g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
-9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP
-BSeOE6Fuwg==
------END CERTIFICATE-----
-
-# Issuer: CN=Atos TrustedRoot 2011 O=Atos
-# Subject: CN=Atos TrustedRoot 2011 O=Atos
-# Label: "Atos TrustedRoot 2011"
-# Serial: 6643877497813316402
-# MD5 Fingerprint: ae:b9:c4:32:4b:ac:7f:5d:66:cc:77:94:bb:2a:77:56
-# SHA1 Fingerprint: 2b:b1:f5:3e:55:0c:1d:c5:f1:d4:e6:b7:6a:46:4b:55:06:02:ac:21
-# SHA256 Fingerprint: f3:56:be:a2:44:b7:a9:1e:b3:5d:53:ca:9a:d7:86:4a:ce:01:8e:2d:35:d5:f8:f9:6d:df:68:a6:f4:1a:a4:74
------BEGIN CERTIFICATE-----
-MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
-AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
-EwJERTAeFw0xMTA3MDcxNDU4MzBaFw0zMDEyMzEyMzU5NTlaMDwxHjAcBgNVBAMM
-FUF0b3MgVHJ1c3RlZFJvb3QgMjAxMTENMAsGA1UECgwEQXRvczELMAkGA1UEBhMC
-REUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCVhTuXbyo7LjvPpvMp
-Nb7PGKw+qtn4TaA+Gke5vJrf8v7MPkfoepbCJI419KkM/IL9bcFyYie96mvr54rM
-VD6QUM+A1JX76LWC1BTFtqlVJVfbsVD2sGBkWXppzwO3bw2+yj5vdHLqqjAqc2K+
-SZFhyBH+DgMq92og3AIVDV4VavzjgsG1xZ1kCWyjWZgHJ8cblithdHFsQ/H3NYkQ
-4J7sVaE3IqKHBAUsR320HLliKWYoyrfhk/WklAOZuXCFteZI6o1Q/NnezG8HDt0L
-cp2AMBYHlT8oDv3FdU9T1nSatCQujgKRz3bFmx5VdJx4IbHwLfELn8LVlhgf8FQi
-eowHAgMBAAGjfTB7MB0GA1UdDgQWBBSnpQaxLKYJYO7Rl+lwrrw7GWzbITAPBgNV
-HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFKelBrEspglg7tGX6XCuvDsZbNshMBgG
-A1UdIAQRMA8wDQYLKwYBBAGwLQMEAQEwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3
-DQEBCwUAA4IBAQAmdzTblEiGKkGdLD4GkGDEjKwLVLgfuXvTBznk+j57sj1O7Z8j
-vZfza1zv7v1Apt+hk6EKhqzvINB5Ab149xnYJDE0BAGmuhWawyfc2E8PzBhj/5kP
-DpFrdRbhIfzYJsdHt6bPWHJxfrrhTZVHO8mvbaG0weyJ9rQPOLXiZNwlz6bb65pc
-maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
-lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
-KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
------END CERTIFICATE-----
-
-# Issuer: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited
-# Subject: CN=QuoVadis Root CA 1 G3 O=QuoVadis Limited
-# Label: "QuoVadis Root CA 1 G3"
-# Serial: 687049649626669250736271037606554624078720034195
-# MD5 Fingerprint: a4:bc:5b:3f:fe:37:9a:fa:64:f0:e2:fa:05:3d:0b:ab
-# SHA1 Fingerprint: 1b:8e:ea:57:96:29:1a:c9:39:ea:b8:0a:81:1a:73:73:c0:93:79:67
-# SHA256 Fingerprint: 8a:86:6f:d1:b2:76:b5:7e:57:8e:92:1c:65:82:8a:2b:ed:58:e9:f2:f2:88:05:41:34:b7:f1:f4:bf:c9:cc:74
------BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL
-BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
-BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMSBHMzAeFw0xMjAxMTIxNzI3NDRaFw00
-MjAxMTIxNzI3NDRaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
-aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDEgRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCgvlAQjunybEC0BJyFuTHK3C3kEakEPBtV
-wedYMB0ktMPvhd6MLOHBPd+C5k+tR4ds7FtJwUrVu4/sh6x/gpqG7D0DmVIB0jWe
-rNrwU8lmPNSsAgHaJNM7qAJGr6Qc4/hzWHa39g6QDbXwz8z6+cZM5cOGMAqNF341
-68Xfuw6cwI2H44g4hWf6Pser4BOcBRiYz5P1sZK0/CPTz9XEJ0ngnjybCKOLXSoh
-4Pw5qlPafX7PGglTvF0FBM+hSo+LdoINofjSxxR3W5A2B4GbPgb6Ul5jxaYA/qXp
-UhtStZI5cgMJYr2wYBZupt0lwgNm3fME0UDiTouG9G/lg6AnhF4EwfWQvTA9xO+o
-abw4m6SkltFi2mnAAZauy8RRNOoMqv8hjlmPSlzkYZqn0ukqeI1RPToV7qJZjqlc
-3sX5kCLliEVx3ZGZbHqfPT2YfF72vhZooF6uCyP8Wg+qInYtyaEQHeTTRCOQiJ/G
-KubX9ZqzWB4vMIkIG1SitZgj7Ah3HJVdYdHLiZxfokqRmu8hqkkWCKi9YSgxyXSt
-hfbZxbGL0eUQMk1fiyA6PEkfM4VZDdvLCXVDaXP7a3F98N/ETH3Goy7IlXnLc6KO
-Tk0k+17kBL5yG6YnLUlamXrXXAkgt3+UuU/xDRxeiEIbEbfnkduebPRq34wGmAOt
-zCjvpUfzUwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQUo5fW816iEOGrRZ88F2Q87gFwnMwwDQYJKoZIhvcNAQELBQAD
-ggIBABj6W3X8PnrHX3fHyt/PX8MSxEBd1DKquGrX1RUVRpgjpeaQWxiZTOOtQqOC
-MTaIzen7xASWSIsBx40Bz1szBpZGZnQdT+3Btrm0DWHMY37XLneMlhwqI2hrhVd2
-cDMT/uFPpiN3GPoajOi9ZcnPP/TJF9zrx7zABC4tRi9pZsMbj/7sPtPKlL92CiUN
-qXsCHKnQO18LwIE6PWThv6ctTr1NxNgpxiIY0MWscgKCP6o6ojoilzHdCGPDdRS5
-YCgtW2jgFqlmgiNR9etT2DGbe+m3nUvriBbP+V04ikkwj+3x6xn0dxoxGE1nVGwv
-b2X52z3sIexe9PSLymBlVNFxZPT5pqOBMzYzcfCkeF9OrYMh3jRJjehZrJ3ydlo2
-8hP0r+AJx2EqbPfgna67hkooby7utHnNkDPDs3b69fBsnQGQ+p6Q9pxyz0fawx/k
-NSBT8lTR32GDpgLiJTjehTItXnOQUl1CxM49S+H5GYQd1aJQzEH7QRTDvdbJWqNj
-ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp
-q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt
-nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD
------END CERTIFICATE-----
-
-# Issuer: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited
-# Subject: CN=QuoVadis Root CA 2 G3 O=QuoVadis Limited
-# Label: "QuoVadis Root CA 2 G3"
-# Serial: 390156079458959257446133169266079962026824725800
-# MD5 Fingerprint: af:0c:86:6e:bf:40:2d:7f:0b:3e:12:50:ba:12:3d:06
-# SHA1 Fingerprint: 09:3c:61:f3:8b:8b:dc:7d:55:df:75:38:02:05:00:e1:25:f5:c8:36
-# SHA256 Fingerprint: 8f:e4:fb:0a:f9:3a:4d:0d:67:db:0b:eb:b2:3e:37:c7:1b:f3:25:dc:bc:dd:24:0e:a0:4d:af:58:b4:7e:18:40
------BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL
-BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
-BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00
-MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
-aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf
-qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW
-n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym
-c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+
-O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1
-o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j
-IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq
-IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz
-8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh
-vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l
-7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG
-cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD
-ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
-AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC
-roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga
-W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n
-lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE
-+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV
-csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd
-dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg
-KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM
-HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4
-WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M
------END CERTIFICATE-----
-
-# Issuer: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited
-# Subject: CN=QuoVadis Root CA 3 G3 O=QuoVadis Limited
-# Label: "QuoVadis Root CA 3 G3"
-# Serial: 268090761170461462463995952157327242137089239581
-# MD5 Fingerprint: df:7d:b9:ad:54:6f:68:a1:df:89:57:03:97:43:b0:d7
-# SHA1 Fingerprint: 48:12:bd:92:3c:a8:c4:39:06:e7:30:6d:27:96:e6:a4:cf:22:2e:7d
-# SHA256 Fingerprint: 88:ef:81:de:20:2e:b0:18:45:2e:43:f8:64:72:5c:ea:5f:bd:1f:c2:d9:d2:05:73:07:09:c5:d8:b8:69:0f:46
------BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL
-BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
-BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00
-MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
-aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR
-/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu
-FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR
-U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c
-ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR
-FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k
-A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw
-eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl
-sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp
-VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q
-A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+
-ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD
-ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
-KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI
-FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv
-oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg
-u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP
-0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf
-3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl
-8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+
-DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN
-PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/
-ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Assured ID Root G2 O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Assured ID Root G2"
-# Serial: 15385348160840213938643033620894905419
-# MD5 Fingerprint: 92:38:b9:f8:63:24:82:65:2c:57:33:e6:fe:81:8f:9d
-# SHA1 Fingerprint: a1:4b:48:d9:43:ee:0a:0e:40:90:4f:3c:e0:a4:c0:91:93:51:5d:3f
-# SHA256 Fingerprint: 7d:05:eb:b6:82:33:9f:8c:94:51:ee:09:4e:eb:fe:fa:79:53:a1:14:ed:b2:f4:49:49:45:2f:ab:7d:2f:c1:85
------BEGIN CERTIFICATE-----
-MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJv
-b3QgRzIwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQG
-EwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNl
-cnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzIwggEi
-MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDZ5ygvUj82ckmIkzTz+GoeMVSA
-n61UQbVH35ao1K+ALbkKz3X9iaV9JPrjIgwrvJUXCzO/GU1BBpAAvQxNEP4Htecc
-biJVMWWXvdMX0h5i89vqbFCMP4QMls+3ywPgym2hFEwbid3tALBSfK+RbLE4E9Hp
-EgjAALAcKxHad3A2m67OeYfcgnDmCXRwVWmvo2ifv922ebPynXApVfSr/5Vh88lA
-bx3RvpO704gqu52/clpWcTs/1PPRCv4o76Pu2ZmvA9OPYLfykqGxvYmJHzDNw6Yu
-YjOuFgJ3RFrngQo8p0Quebg/BLxcoIfhG69Rjs3sLPr4/m3wOnyqi+RnlTGNAgMB
-AAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQW
-BBTOw0q5mVXyuNtgv6l+vVa1lzan1jANBgkqhkiG9w0BAQsFAAOCAQEAyqVVjOPI
-QW5pJ6d1Ee88hjZv0p3GeDgdaZaikmkuOGybfQTUiaWxMTeKySHMq2zNixya1r9I
-0jJmwYrA8y8678Dj1JGG0VDjA9tzd29KOVPt3ibHtX2vK0LRdWLjSisCx1BL4Gni
-lmwORGYQRI+tBev4eaymG+g3NJ1TyWGqolKvSnAWhsI6yLETcDbYz+70CjTVW0z9
-B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv
-ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
-IhNzbM8m9Yop5w==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Assured ID Root G3 O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Assured ID Root G3"
-# Serial: 15459312981008553731928384953135426796
-# MD5 Fingerprint: 7c:7f:65:31:0c:81:df:8d:ba:3e:99:e2:5c:ad:6e:fb
-# SHA1 Fingerprint: f5:17:a2:4f:9a:48:c6:c9:f8:a2:00:26:9f:dc:0f:48:2c:ab:30:89
-# SHA256 Fingerprint: 7e:37:cb:8b:4c:47:09:0c:ab:36:55:1b:a6:f4:5d:b8:40:68:0f:ba:16:6a:95:2d:b1:00:71:7f:43:05:3f:c2
------BEGIN CERTIFICATE-----
-MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
-CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
-ZGlnaWNlcnQuY29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3Qg
-RzMwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBlMQswCQYDVQQGEwJV
-UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
-Y29tMSQwIgYDVQQDExtEaWdpQ2VydCBBc3N1cmVkIElEIFJvb3QgRzMwdjAQBgcq
-hkjOPQIBBgUrgQQAIgNiAAQZ57ysRGXtzbg/WPuNsVepRC0FFfLvC/8QdJ+1YlJf
-Zn4f5dwbRXkLzMZTCp2NXQLZqVneAlr2lSoOjThKiknGvMYDOAdfVdp+CW7if17Q
-RSAPWXYQ1qAk8C3eNvJsKTmjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/
-BAQDAgGGMB0GA1UdDgQWBBTL0L2p4ZgFUaFNN6KDec6NHSrkhDAKBggqhkjOPQQD
-AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY
-JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
-6pZjamVFkpUBtA==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Global Root G2 O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Global Root G2"
-# Serial: 4293743540046975378534879503202253541
-# MD5 Fingerprint: e4:a6:8a:c8:54:ac:52:42:46:0a:fd:72:48:1b:2a:44
-# SHA1 Fingerprint: df:3c:24:f9:bf:d6:66:76:1b:26:80:73:fe:06:d1:cc:8d:4f:82:a4
-# SHA256 Fingerprint: cb:3c:cb:b7:60:31:e5:e0:13:8f:8d:d3:9a:23:f9:de:47:ff:c3:5e:43:c1:14:4c:ea:27:d4:6a:5a:b1:cb:5f
------BEGIN CERTIFICATE-----
-MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBH
-MjAeFw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVT
-MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
-b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEcyMIIBIjANBgkqhkiG
-9w0BAQEFAAOCAQ8AMIIBCgKCAQEAuzfNNNx7a8myaJCtSnX/RrohCgiN9RlUyfuI
-2/Ou8jqJkTx65qsGGmvPrC3oXgkkRLpimn7Wo6h+4FR1IAWsULecYxpsMNzaHxmx
-1x7e/dfgy5SDN67sH0NO3Xss0r0upS/kqbitOtSZpLYl6ZtrAGCSYP9PIUkY92eQ
-q2EGnI/yuum06ZIya7XzV+hdG82MHauVBJVJ8zUtluNJbd134/tJS7SsVQepj5Wz
-tCO7TG1F8PapspUwtP1MVYwnSlcUfIKdzXOS0xZKBgyMUNGPHgm+F6HmIcr9g+UQ
-vIOlCsRnKPZzFBQ9RnbDhxSJITRNrw9FDKZJobq7nMWxM4MphQIDAQABo0IwQDAP
-BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAdBgNVHQ4EFgQUTiJUIBiV
-5uNu5g/6+rkS7QYXjzkwDQYJKoZIhvcNAQELBQADggEBAGBnKJRvDkhj6zHd6mcY
-1Yl9PMWLSn/pvtsrF9+wX3N3KjITOYFnQoQj8kVnNeyIv/iPsGEMNKSuIEyExtv4
-NeF22d+mQrvHRAiGfzZ0JFrabA0UWTW98kndth/Jsw1HKj2ZL7tcu7XUIOGZX1NG
-Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
-8rGOmaFvE7FBcf6IKshPECBV1/MUReXgRPTqh5Uykw7+U0b6LJ3/iyK5S9kJRaTe
-pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
-MrY=
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Global Root G3 O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Global Root G3"
-# Serial: 7089244469030293291760083333884364146
-# MD5 Fingerprint: f5:5d:a4:50:a5:fb:28:7e:1e:0f:0d:cc:96:57:56:ca
-# SHA1 Fingerprint: 7e:04:de:89:6a:3e:66:6d:00:e6:87:d3:3f:fa:d9:3b:e8:3d:34:9e
-# SHA256 Fingerprint: 31:ad:66:48:f8:10:41:38:c7:38:f3:9e:a4:32:01:33:39:3e:3a:18:cc:02:29:6e:f9:7c:2a:c9:ef:67:31:d0
------BEGIN CERTIFICATE-----
-MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
-CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
-ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe
-Fw0xMzA4MDExMjAwMDBaFw0zODAxMTUxMjAwMDBaMGExCzAJBgNVBAYTAlVTMRUw
-EwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5jb20x
-IDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IEczMHYwEAYHKoZIzj0CAQYF
-K4EEACIDYgAE3afZu4q4C/sLfyHS8L6+c/MzXRq8NOrexpu80JX28MzQC7phW1FG
-fp4tn+6OYwwX7Adw9c+ELkCDnOg/QW07rdOkFFk2eJ0DQ+4QE2xy3q6Ip6FrtUPO
-Z9wj/wMco+I+o0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBhjAd
-BgNVHQ4EFgQUs9tIpPmhxdiuNkHMEWNpYim8S8YwCgYIKoZIzj0EAwMDaAAwZQIx
-AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
-oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
-sycX
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com
-# Subject: CN=DigiCert Trusted Root G4 O=DigiCert Inc OU=www.digicert.com
-# Label: "DigiCert Trusted Root G4"
-# Serial: 7451500558977370777930084869016614236
-# MD5 Fingerprint: 78:f2:fc:aa:60:1f:2f:b4:eb:c9:37:ba:53:2e:75:49
-# SHA1 Fingerprint: dd:fb:16:cd:49:31:c9:73:a2:03:7d:3f:c8:3a:4d:7d:77:5d:05:e4
-# SHA256 Fingerprint: 55:2f:7b:dc:f1:a7:af:9e:6c:e6:72:01:7f:4f:12:ab:f7:72:40:c7:8e:76:1a:c2:03:d1:d9:d2:0a:c8:99:88
------BEGIN CERTIFICATE-----
-MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
-MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
-d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg
-RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV
-UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu
-Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y
-ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If
-xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV
-ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO
-DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ
-jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/
-CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi
-EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM
-fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY
-uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK
-chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t
-9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD
-ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2
-SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd
-+SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc
-fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa
-sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N
-cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N
-0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie
-4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI
-r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
-/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
-gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
------END CERTIFICATE-----
-
-# Issuer: CN=COMODO RSA Certification Authority O=COMODO CA Limited
-# Subject: CN=COMODO RSA Certification Authority O=COMODO CA Limited
-# Label: "COMODO RSA Certification Authority"
-# Serial: 101909084537582093308941363524873193117
-# MD5 Fingerprint: 1b:31:b0:71:40:36:cc:14:36:91:ad:c4:3e:fd:ec:18
-# SHA1 Fingerprint: af:e5:d2:44:a8:d1:19:42:30:ff:47:9f:e2:f8:97:bb:cd:7a:8c:b4
-# SHA256 Fingerprint: 52:f0:e1:c4:e5:8e:c6:29:29:1b:60:31:7f:07:46:71:b8:5d:7e:a8:0d:5b:07:27:34:63:53:4b:32:b4:02:34
------BEGIN CERTIFICATE-----
-MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
-hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
-A1UEBxMHU2FsZm9yZDEaMBgGA1UEChMRQ09NT0RPIENBIExpbWl0ZWQxKzApBgNV
-BAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMTE5
-MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBhTELMAkGA1UEBhMCR0IxGzAZBgNVBAgT
-EkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UEBxMHU2FsZm9yZDEaMBgGA1UEChMR
-Q09NT0RPIENBIExpbWl0ZWQxKzApBgNVBAMTIkNPTU9ETyBSU0EgQ2VydGlmaWNh
-dGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCR
-6FSS0gpWsawNJN3Fz0RndJkrN6N9I3AAcbxT38T6KhKPS38QVr2fcHK3YX/JSw8X
-pz3jsARh7v8Rl8f0hj4K+j5c+ZPmNHrZFGvnnLOFoIJ6dq9xkNfs/Q36nGz637CC
-9BR++b7Epi9Pf5l/tfxnQ3K9DADWietrLNPtj5gcFKt+5eNu/Nio5JIk2kNrYrhV
-/erBvGy2i/MOjZrkm2xpmfh4SDBF1a3hDTxFYPwyllEnvGfDyi62a+pGx8cgoLEf
-Zd5ICLqkTqnyg0Y3hOvozIFIQ2dOciqbXL1MGyiKXCJ7tKuY2e7gUYPDCUZObT6Z
-+pUX2nwzV0E8jVHtC7ZcryxjGt9XyD+86V3Em69FmeKjWiS0uqlWPc9vqv9JWL7w
-qP/0uK3pN/u6uPQLOvnoQ0IeidiEyxPx2bvhiWC4jChWrBQdnArncevPDt09qZah
-SL0896+1DSJMwBGB7FY79tOi4lu3sgQiUpWAk2nojkxl8ZEDLXB0AuqLZxUpaVIC
-u9ffUGpVRr+goyhhf3DQw6KqLCGqR84onAZFdr+CGCe01a60y1Dma/RMhnEw6abf
-Fobg2P9A3fvQQoh/ozM6LlweQRGBY84YcWsr7KaKtzFcOmpH4MN5WdYgGq/yapiq
-crxXStJLnbsQ/LBMQeXtHT1eKJ2czL+zUdqnR+WEUwIDAQABo0IwQDAdBgNVHQ4E
-FgQUu69+Aj36pvE8hI6t7jiY7NkyMtQwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB
-/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAArx1UaEt65Ru2yyTUEUAJNMnMvl
-wFTPoCWOAvn9sKIN9SCYPBMtrFaisNZ+EZLpLrqeLppysb0ZRGxhNaKatBYSaVqM
-4dc+pBroLwP0rmEdEBsqpIt6xf4FpuHA1sj+nq6PK7o9mfjYcwlYRm6mnPTXJ9OV
-2jeDchzTc+CiR5kDOF3VSXkAKRzH7JsgHAckaVd4sjn8OoSgtZx8jb8uk2Intzna
-FxiuvTwJaP+EmzzV1gsD41eeFPfR60/IvYcjt7ZJQ3mFXLrrkguhxuhoqEwWsRqZ
-CuhTLJK7oQkYdQxlqHvLI7cawiiFwxv/0Cti76R7CZGYZ4wUAc1oBmpjIXUDgIiK
-boHGhfKppC3n9KUkEEeDys30jXlYsQab5xoq2Z0B15R97QNKyvDb6KkBPvVWmcke
-jkk9u+UJueBPSZI9FoJAzMxZxuY67RIuaTxslbH9qh17f4a+Hg4yRvv7E491f0yL
-S0Zj/gA0QHDBw7mh3aZw4gSzQbzpgJHqZJx64SIDqZxubw5lT2yHh17zbqD5daWb
-QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
-0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
-NVOFBkpdn627G190
------END CERTIFICATE-----
-
-# Issuer: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
-# Subject: CN=USERTrust RSA Certification Authority O=The USERTRUST Network
-# Label: "USERTrust RSA Certification Authority"
-# Serial: 2645093764781058787591871645665788717
-# MD5 Fingerprint: 1b:fe:69:d1:91:b7:19:33:a3:72:a8:0f:e1:55:e5:b5
-# SHA1 Fingerprint: 2b:8f:1b:57:33:0d:bb:a2:d0:7a:6c:51:f7:0e:e9:0d:da:b9:ad:8e
-# SHA256 Fingerprint: e7:93:c9:b0:2f:d8:aa:13:e2:1c:31:22:8a:cc:b0:81:19:64:3b:74:9c:89:89:64:b1:74:6d:46:c3:d4:cb:d2
------BEGIN CERTIFICATE-----
-MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
-iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
-cnNleSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNV
-BAMTJVVTRVJUcnVzdCBSU0EgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAw
-MjAxMDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNV
-BAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVU
-aGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBSU0EgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
-AoICAQCAEmUXNg7D2wiz0KxXDXbtzSfTTK1Qg2HiqiBNCS1kCdzOiZ/MPans9s/B
-3PHTsdZ7NygRK0faOca8Ohm0X6a9fZ2jY0K2dvKpOyuR+OJv0OwWIJAJPuLodMkY
-tJHUYmTbf6MG8YgYapAiPLz+E/CHFHv25B+O1ORRxhFnRghRy4YUVD+8M/5+bJz/
-Fp0YvVGONaanZshyZ9shZrHUm3gDwFA66Mzw3LyeTP6vBZY1H1dat//O+T23LLb2
-VN3I5xI6Ta5MirdcmrS3ID3KfyI0rn47aGYBROcBTkZTmzNg95S+UzeQc0PzMsNT
-79uq/nROacdrjGCT3sTHDN/hMq7MkztReJVni+49Vv4M0GkPGw/zJSZrM233bkf6
-c0Plfg6lZrEpfDKEY1WJxA3Bk1QwGROs0303p+tdOmw1XNtB1xLaqUkL39iAigmT
-Yo61Zs8liM2EuLE/pDkP2QKe6xJMlXzzawWpXhaDzLhn4ugTncxbgtNMs+1b/97l
-c6wjOy0AvzVVdAlJ2ElYGn+SNuZRkg7zJn0cTRe8yexDJtC/QV9AqURE9JnnV4ee
-UB9XVKg+/XRjL7FQZQnmWEIuQxpMtPAlR1n6BB6T1CZGSlCBst6+eLf8ZxXhyVeE
-Hg9j1uliutZfVS7qXMYoCAQlObgOK6nyTJccBz8NUvXt7y+CDwIDAQABo0IwQDAd
-BgNVHQ4EFgQUU3m/WqorSs9UgOHYm8Cd8rIDZsswDgYDVR0PAQH/BAQDAgEGMA8G
-A1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAFzUfA3P9wF9QZllDHPF
-Up/L+M+ZBn8b2kMVn54CVVeWFPFSPCeHlCjtHzoBN6J2/FNQwISbxmtOuowhT6KO
-VWKR82kV2LyI48SqC/3vqOlLVSoGIG1VeCkZ7l8wXEskEVX/JJpuXior7gtNn3/3
-ATiUFJVDBwn7YKnuHKsSjKCaXqeYalltiz8I+8jRRa8YFWSQEg9zKC7F4iRO/Fjs
-8PRF/iKz6y+O0tlFYQXBl2+odnKPi4w2r78NBc5xjeambx9spnFixdjQg3IM8WcR
-iQycE0xyNN+81XHfqnHd4blsjDwSXWXavVcStkNr/+XeTWYRUc+ZruwXtuhxkYze
-Sf7dNXGiFSeUHM9h4ya7b6NnJSFd5t0dCy5oGzuCr+yDZ4XUmFF0sbmZgIn/f3gZ
-XHlKYC6SQK5MNyosycdiyA5d9zZbyuAlJQG03RoHnHcAP9Dc1ew91Pq7P8yF1m9/
-qS3fuQL39ZeatTXaw2ewh0qpKJ4jjv9cJ2vhsE/zB+4ALtRZh8tSQZXq9EfX7mRB
-VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
-L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
-jjxDah2nGN59PRbxYvnKkKj9
------END CERTIFICATE-----
-
-# Issuer: CN=USERTrust ECC Certification Authority O=The USERTRUST Network
-# Subject: CN=USERTrust ECC Certification Authority O=The USERTRUST Network
-# Label: "USERTrust ECC Certification Authority"
-# Serial: 123013823720199481456569720443997572134
-# MD5 Fingerprint: fa:68:bc:d9:b5:7f:ad:fd:c9:1d:06:83:28:cc:24:c1
-# SHA1 Fingerprint: d1:cb:ca:5d:b2:d5:2a:7f:69:3b:67:4d:e5:f0:5a:1d:0c:95:7d:f0
-# SHA256 Fingerprint: 4f:f4:60:d5:4b:9c:86:da:bf:bc:fc:57:12:e0:40:0d:2b:ed:3f:bc:4d:4f:bd:aa:86:e0:6a:dc:d2:a9:ad:7a
------BEGIN CERTIFICATE-----
-MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
-MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
-eSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMT
-JVVTRVJUcnVzdCBFQ0MgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwHhcNMTAwMjAx
-MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBiDELMAkGA1UEBhMCVVMxEzARBgNVBAgT
-Ck5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNleSBDaXR5MR4wHAYDVQQKExVUaGUg
-VVNFUlRSVVNUIE5ldHdvcmsxLjAsBgNVBAMTJVVTRVJUcnVzdCBFQ0MgQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQarFRaqflo
-I+d61SRvU8Za2EurxtW20eZzca7dnNYMYf3boIkDuAUU7FfO7l0/4iGzzvfUinng
-o4N+LZfQYcTxmdwlkWOrfzCjtHDix6EznPO/LlxTsV+zfTJ/ijTjeXmjQjBAMB0G
-A1UdDgQWBBQ64QmG1M8ZwpZ2dEl23OA1xmNjmjAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB
-zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW
-RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R5
-# Label: "GlobalSign ECC Root CA - R5"
-# Serial: 32785792099990507226680698011560947931244
-# MD5 Fingerprint: 9f:ad:3b:1c:02:1e:8a:ba:17:74:38:81:0c:a2:bc:08
-# SHA1 Fingerprint: 1f:24:c6:30:cd:a4:18:ef:20:69:ff:ad:4f:dd:5f:46:3a:1b:69:aa
-# SHA256 Fingerprint: 17:9f:bc:14:8a:3d:d0:0f:d2:4e:a1:34:58:cc:43:bf:a7:f5:9c:81:82:d7:83:a5:13:f6:eb:ec:10:0c:89:24
------BEGIN CERTIFICATE-----
-MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
-8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
-hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
-KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
-515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
-xwy8p2Fp8fc74SrL+SvzZpA3
------END CERTIFICATE-----
-
-# Issuer: CN=IdenTrust Commercial Root CA 1 O=IdenTrust
-# Subject: CN=IdenTrust Commercial Root CA 1 O=IdenTrust
-# Label: "IdenTrust Commercial Root CA 1"
-# Serial: 13298821034946342390520003877796839426
-# MD5 Fingerprint: b3:3e:77:73:75:ee:a0:d3:e3:7e:49:63:49:59:bb:c7
-# SHA1 Fingerprint: df:71:7e:aa:4a:d9:4e:c9:55:84:99:60:2d:48:de:5f:bc:f0:3a:25
-# SHA256 Fingerprint: 5d:56:49:9b:e4:d2:e0:8b:cf:ca:d0:8a:3e:38:72:3d:50:50:3b:de:70:69:48:e4:2f:55:60:30:19:e5:28:ae
------BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
-MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
-VHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwHhcNMTQwMTE2MTgxMjIzWhcNMzQw
-MTE2MTgxMjIzWjBKMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScw
-JQYDVQQDEx5JZGVuVHJ1c3QgQ29tbWVyY2lhbCBSb290IENBIDEwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCnUBneP5k91DNG8W9RYYKyqU+PZ4ldhNlT
-3Qwo2dfw/66VQ3KZ+bVdfIrBQuExUHTRgQ18zZshq0PirK1ehm7zCYofWjK9ouuU
-+ehcCuz/mNKvcbO0U59Oh++SvL3sTzIwiEsXXlfEU8L2ApeN2WIrvyQfYo3fw7gp
-S0l4PJNgiCL8mdo2yMKi1CxUAGc1bnO/AljwpN3lsKImesrgNqUZFvX9t++uP0D1
-bVoE/c40yiTcdCMbXTMTEl3EASX2MN0CXZ/g1Ue9tOsbobtJSdifWwLziuQkkORi
-T0/Br4sOdBeo0XKIanoBScy0RnnGF7HamB4HWfp1IYVl3ZBWzvurpWCdxJ35UrCL
-vYf5jysjCiN2O/cz4ckA82n5S6LgTrx+kzmEB/dEcH7+B1rlsazRGMzyNeVJSQjK
-Vsk9+w8YfYs7wRPCTY/JTw436R+hDmrfYi7LNQZReSzIJTj0+kuniVyc0uMNOYZK
-dHzVWYfCP04MXFL0PfdSgvHqo6z9STQaKPNBiDoT7uje/5kdX7rL6B7yuVBgwDHT
-c+XvvqDtMwt0viAgxGds8AgDelWAf0ZOlqf0Hj7h9tgJ4TNkK2PXMl6f+cB7D3hv
-l7yTmvmcEpB4eoCHFddydJxVdHixuuFucAS6T6C6aMN7/zHwcz09lCqxC0EOoP5N
-iGVreTO01wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB
-/zAdBgNVHQ4EFgQU7UQZwNPwBovupHu+QucmVMiONnYwDQYJKoZIhvcNAQELBQAD
-ggIBAA2ukDL2pkt8RHYZYR4nKM1eVO8lvOMIkPkp165oCOGUAFjvLi5+U1KMtlwH
-6oi6mYtQlNeCgN9hCQCTrQ0U5s7B8jeUeLBfnLOic7iPBZM4zY0+sLj7wM+x8uwt
-LRvM7Kqas6pgghstO8OEPVeKlh6cdbjTMM1gCIOQ045U8U1mwF10A0Cj7oV+wh93
-nAbowacYXVKV7cndJZ5t+qntozo00Fl72u1Q8zW/7esUTTHHYPTa8Yec4kjixsU3
-+wYQ+nVZZjFHKdp2mhzpgq7vmrlR94gjmmmVYjzlVYA211QC//G5Xc7UI2/YRYRK
-W2XviQzdFKcgyxilJbQN+QHwotL0AMh0jqEqSI5l2xPE4iUXfeu+h1sXIFRRk0pT
-AwvsXcoz7WL9RccvW9xYoIA55vrX/hMUpu09lEpCdNTDd1lzzY9GvlU47/rokTLq
-l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG
-4iZZRHUe2XWJUc0QhJ1hYMtd+ZciTY6Y5uN/9lu7rs3KSoFrXgvzUeF0K+l+J6fZ
-mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A
-7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H
------END CERTIFICATE-----
-
-# Issuer: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust
-# Subject: CN=IdenTrust Public Sector Root CA 1 O=IdenTrust
-# Label: "IdenTrust Public Sector Root CA 1"
-# Serial: 13298821034946342390521976156843933698
-# MD5 Fingerprint: 37:06:a5:b0:fc:89:9d:ba:f4:6b:8c:1a:64:cd:d5:ba
-# SHA1 Fingerprint: ba:29:41:60:77:98:3f:f4:f3:ef:f2:31:05:3b:2e:ea:6d:4d:45:fd
-# SHA256 Fingerprint: 30:d0:89:5a:9a:44:8a:26:20:91:63:55:22:d1:f5:20:10:b5:86:7a:ca:e1:2c:78:ef:95:8f:d4:f4:38:9f:2f
------BEGIN CERTIFICATE-----
-MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN
-MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu
-VHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwHhcNMTQwMTE2MTc1MzMyWhcN
-MzQwMTE2MTc1MzMyWjBNMQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0
-MSowKAYDVQQDEyFJZGVuVHJ1c3QgUHVibGljIFNlY3RvciBSb290IENBIDEwggIi
-MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2IpT8pEiv6EdrCvsnduTyP4o7
-ekosMSqMjbCpwzFrqHd2hCa2rIFCDQjrVVi7evi8ZX3yoG2LqEfpYnYeEe4IFNGy
-RBb06tD6Hi9e28tzQa68ALBKK0CyrOE7S8ItneShm+waOh7wCLPQ5CQ1B5+ctMlS
-bdsHyo+1W/CD80/HLaXIrcuVIKQxKFdYWuSNG5qrng0M8gozOSI5Cpcu81N3uURF
-/YTLNiCBWS2ab21ISGHKTN9T0a9SvESfqy9rg3LvdYDaBjMbXcjaY8ZNzaxmMc3R
-3j6HEDbhuaR672BQssvKplbgN6+rNBM5Jeg5ZuSYeqoSmJxZZoY+rfGwyj4GD3vw
-EUs3oERte8uojHH01bWRNszwFcYr3lEXsZdMUD2xlVl8BX0tIdUAvwFnol57plzy
-9yLxkA2T26pEUWbMfXYD62qoKjgZl3YNa4ph+bz27nb9cCvdKTz4Ch5bQhyLVi9V
-GxyhLrXHFub4qjySjmm2AcG1hp2JDws4lFTo6tyePSW8Uybt1as5qsVATFSrsrTZ
-2fjXctscvG29ZV/viDUqZi/u9rNl8DONfJhBaUYPQxxp+pu10GFqzcpL2UyQRqsV
-WaFHVCkugyhfHMKiq3IXAAaOReyL4jM9f9oZRORicsPfIsbyVtTdX5Vy7W1f90gD
-W/3FKqD2cyOEEBsB5wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zAdBgNVHQ4EFgQU43HgntinQtnbcZFrlJPrw6PRFKMwDQYJKoZIhvcN
-AQELBQADggIBAEf63QqwEZE4rU1d9+UOl1QZgkiHVIyqZJnYWv6IAcVYpZmxI1Qj
-t2odIFflAWJBF9MJ23XLblSQdf4an4EKwt3X9wnQW3IV5B4Jaj0z8yGa5hV+rVHV
-DRDtfULAj+7AmgjVQdZcDiFpboBhDhXAuM/FSRJSzL46zNQuOAXeNf0fb7iAaJg9
-TaDKQGXSc3z1i9kKlT/YPyNtGtEqJBnZhbMX73huqVjRI9PHE+1yJX9dsXNw0H8G
-lwmEKYBhHfpe/3OsoOOJuBxxFcbeMX8S3OFtm6/n6J91eEyrRjuazr8FGF1NFTwW
-mhlQBJqymm9li1JfPFgEKCXAZmExfrngdbkaqIHWchezxQMxNRF4eKLg6TCMf4Df
-WN88uieW4oA0beOY02QnrEh+KHdcxiVhJfiFDGX6xDIvpZgF5PgLZxYWxoK4Mhn5
-+bl53B/N66+rDt0b20XkeucC4pVd/GnwU2lhlXV5C15V5jgclKlZM57IcXR5f1GJ
-tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA
-GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv
-8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only
-# Subject: CN=Entrust Root Certification Authority - G2 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2009 Entrust, Inc. - for authorized use only
-# Label: "Entrust Root Certification Authority - G2"
-# Serial: 1246989352
-# MD5 Fingerprint: 4b:e2:c9:91:96:65:0c:f4:0e:5a:93:92:a0:0a:fe:b2
-# SHA1 Fingerprint: 8c:f4:27:fd:79:0c:3a:d1:66:06:8d:e8:1e:57:ef:bb:93:22:72:d4
-# SHA256 Fingerprint: 43:df:57:74:b0:3e:7f:ef:5f:e4:0d:93:1a:7b:ed:f1:bb:2e:6b:42:73:8c:4e:6d:38:41:10:3d:3a:a7:f3:39
------BEGIN CERTIFICATE-----
-MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
-VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
-cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3Qs
-IEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVz
-dCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIwHhcNMDkwNzA3MTcy
-NTU0WhcNMzAxMjA3MTc1NTU0WjCBvjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUVu
-dHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50cnVzdC5uZXQvbGVnYWwt
-dGVybXMxOTA3BgNVBAsTMChjKSAyMDA5IEVudHJ1c3QsIEluYy4gLSBmb3IgYXV0
-aG9yaXplZCB1c2Ugb25seTEyMDAGA1UEAxMpRW50cnVzdCBSb290IENlcnRpZmlj
-YXRpb24gQXV0aG9yaXR5IC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
-AoIBAQC6hLZy254Ma+KZ6TABp3bqMriVQRrJ2mFOWHLP/vaCeb9zYQYKpSfYs1/T
-RU4cctZOMvJyig/3gxnQaoCAAEUesMfnmr8SVycco2gvCoe9amsOXmXzHHfV1IWN
-cCG0szLni6LVhjkCsbjSR87kyUnEO6fe+1R9V77w6G7CebI6C1XiUJgWMhNcL3hW
-wcKUs/Ja5CeanyTXxuzQmyWC48zCxEXFjJd6BmsqEZ+pCm5IO2/b1BEZQvePB7/1
-U1+cPvQXLOZprE4yTGJ36rfo5bs0vBmLrpxR57d+tVOxMyLlbc9wPBr64ptntoP0
-jaWvYkxN4FisZDQSA/i2jZRjJKRxAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAP
-BgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRqciZ60B7vfec7aVHUbI2fkBJmqzAN
-BgkqhkiG9w0BAQsFAAOCAQEAeZ8dlsa2eT8ijYfThwMEYGprmi5ZiXMRrEPR9RP/
-jTkrwPK9T3CMqS/qF8QLVJ7UG5aYMzyorWKiAHarWWluBh1+xLlEjZivEtRh2woZ
-Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
-1fN2D807iDginWyTmsQ9v4IbZT+mD12q/OWyFcq1rca8PdCE6OoGcrBNOTJ4vz4R
-nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
-VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only
-# Subject: CN=Entrust Root Certification Authority - EC1 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2012 Entrust, Inc. - for authorized use only
-# Label: "Entrust Root Certification Authority - EC1"
-# Serial: 51543124481930649114116133369
-# MD5 Fingerprint: b6:7e:1d:f0:58:c5:49:6c:24:3b:3d:ed:98:18:ed:bc
-# SHA1 Fingerprint: 20:d8:06:40:df:9b:25:f5:12:25:3a:11:ea:f7:59:8a:eb:14:b5:47
-# SHA256 Fingerprint: 02:ed:0e:b2:8c:14:da:45:16:5c:56:67:91:70:0d:64:51:d7:fb:56:f0:b2:ab:1d:3b:8e:b0:70:e5:6e:df:f5
------BEGIN CERTIFICATE-----
-MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
-A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
-d3cuZW50cnVzdC5uZXQvbGVnYWwtdGVybXMxOTA3BgNVBAsTMChjKSAyMDEyIEVu
-dHJ1c3QsIEluYy4gLSBmb3IgYXV0aG9yaXplZCB1c2Ugb25seTEzMDEGA1UEAxMq
-RW50cnVzdCBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRUMxMB4XDTEy
-MTIxODE1MjUzNloXDTM3MTIxODE1NTUzNlowgb8xCzAJBgNVBAYTAlVTMRYwFAYD
-VQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1c3QubmV0
-L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxMiBFbnRydXN0LCBJbmMuIC0g
-Zm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMzAxBgNVBAMTKkVudHJ1c3QgUm9vdCBD
-ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEVDMTB2MBAGByqGSM49AgEGBSuBBAAi
-A2IABIQTydC6bUF74mzQ61VfZgIaJPRbiWlH47jCffHyAsWfoPZb1YsGGYZPUxBt
-ByQnoaD41UcZYUx9ypMn6nQM72+WCf5j7HBdNq1nd67JnXxVRDqiY1Ef9eNi1KlH
-Bz7MIKNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
-BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC
-R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX
-hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
------END CERTIFICATE-----
-
-# Issuer: CN=CFCA EV ROOT O=China Financial Certification Authority
-# Subject: CN=CFCA EV ROOT O=China Financial Certification Authority
-# Label: "CFCA EV ROOT"
-# Serial: 407555286
-# MD5 Fingerprint: 74:e1:b6:ed:26:7a:7a:44:30:33:94:ab:7b:27:81:30
-# SHA1 Fingerprint: e2:b8:29:4b:55:84:ab:6b:58:c2:90:46:6c:ac:3f:b8:39:8f:84:83
-# SHA256 Fingerprint: 5c:c3:d7:8e:4e:1d:5e:45:54:7a:04:e6:87:3e:64:f9:0c:f9:53:6d:1c:cc:2e:f8:00:f3:55:c4:c5:fd:70:fd
------BEGIN CERTIFICATE-----
-MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD
-TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
-aXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJPT1QwHhcNMTIwODA4MDMwNzAxWhcNMjkx
-MjMxMDMwNzAxWjBWMQswCQYDVQQGEwJDTjEwMC4GA1UECgwnQ2hpbmEgRmluYW5j
-aWFsIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MRUwEwYDVQQDDAxDRkNBIEVWIFJP
-T1QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDXXWvNED8fBVnVBU03
-sQ7smCuOFR36k0sXgiFxEFLXUWRwFsJVaU2OFW2fvwwbwuCjZ9YMrM8irq93VCpL
-TIpTUnrD7i7es3ElweldPe6hL6P3KjzJIx1qqx2hp/Hz7KDVRM8Vz3IvHWOX6Jn5
-/ZOkVIBMUtRSqy5J35DNuF++P96hyk0g1CXohClTt7GIH//62pCfCqktQT+x8Rgp
-7hZZLDRJGqgG16iI0gNyejLi6mhNbiyWZXvKWfry4t3uMCz7zEasxGPrb382KzRz
-EpR/38wmnvFyXVBlWY9ps4deMm/DGIq1lY+wejfeWkU7xzbh72fROdOXW3NiGUgt
-hxwG+3SYIElz8AXSG7Ggo7cbcNOIabla1jj0Ytwli3i/+Oh+uFzJlU9fpy25IGvP
-a931DfSCt/SyZi4QKPaXWnuWFo8BGS1sbn85WAZkgwGDg8NNkt0yxoekN+kWzqot
-aK8KgWU6cMGbrU1tVMoqLUuFG7OA5nBFDWteNfB/O7ic5ARwiRIlk9oKmSJgamNg
-TnYGmE69g60dWIolhdLHZR4tjsbftsbhf4oEIRUpdPA+nJCdDC7xij5aqgwJHsfV
-PKPtl8MeNPo4+QgO48BdK4PRVmrJtqhUUy54Mmc9gn900PvhtgVguXDbjgv5E1hv
-cWAQUhC5wUEJ73IfZzF4/5YFjQIDAQABo2MwYTAfBgNVHSMEGDAWgBTj/i39KNAL
-tbq2osS/BqoFjJP7LzAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd
-BgNVHQ4EFgQU4/4t/SjQC7W6tqLEvwaqBYyT+y8wDQYJKoZIhvcNAQELBQADggIB
-ACXGumvrh8vegjmWPfBEp2uEcwPenStPuiB/vHiyz5ewG5zz13ku9Ui20vsXiObT
-ej/tUxPQ4i9qecsAIyjmHjdXNYmEwnZPNDatZ8POQQaIxffu2Bq41gt/UP+TqhdL
-jOztUmCypAbqTuv0axn96/Ua4CUqmtzHQTb3yHQFhDmVOdYLO6Qn+gjYXB74BGBS
-ESgoA//vU2YApUo0FmZ8/Qmkrp5nGm9BC2sGE5uPhnEFtC+NiWYzKXZUmhH4J/qy
-P5Hgzg0b8zAarb8iXRvTvyUFTeGSGn+ZnzxEk8rUQElsgIfXBDrDMlI1Dlb4pd19
-xIsNER9Tyx6yF7Zod1rg1MvIB671Oi6ON7fQAUtDKXeMOZePglr4UeWJoBjnaH9d
-Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN
-5mydLIhyPDCBBpEi6lmt2hkuIsKNuYyH4Ga8cyNfIWRjgEj1oDwYPZTISEEdQLpe
-/v5WOaHIz16eGWRGENoXkbcFgKyLmZJ956LYBws2J+dIeWCKw9cTXPhyQN9Ky8+Z
-AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ
-5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
------END CERTIFICATE-----
-
-# Issuer: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed
-# Subject: CN=OISTE WISeKey Global Root GB CA O=WISeKey OU=OISTE Foundation Endorsed
-# Label: "OISTE WISeKey Global Root GB CA"
-# Serial: 157768595616588414422159278966750757568
-# MD5 Fingerprint: a4:eb:b9:61:28:2e:b7:2f:98:b0:35:26:90:99:51:1d
-# SHA1 Fingerprint: 0f:f9:40:76:18:d3:d7:6a:4b:98:f0:a8:35:9e:0c:fd:27:ac:cc:ed
-# SHA256 Fingerprint: 6b:9c:08:e8:6e:b0:f7:67:cf:ad:65:cd:98:b6:21:49:e5:49:4a:67:f5:84:5e:7b:d1:ed:01:9f:27:b8:6b:d6
------BEGIN CERTIFICATE-----
-MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt
-MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg
-Rm91bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9i
-YWwgUm9vdCBHQiBDQTAeFw0xNDEyMDExNTAwMzJaFw0zOTEyMDExNTEwMzFaMG0x
-CzAJBgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBG
-b3VuZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2Jh
-bCBSb290IEdCIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2Be3
-HEokKtaXscriHvt9OO+Y9bI5mE4nuBFde9IllIiCFSZqGzG7qFshISvYD06fWvGx
-WuR51jIjK+FTzJlFXHtPrby/h0oLS5daqPZI7H17Dc0hBt+eFf1Biki3IPShehtX
-1F1Q/7pn2COZH8g/497/b1t3sWtuuMlk9+HKQUYOKXHQuSP8yYFfTvdv37+ErXNk
-u7dCjmn21HYdfp2nuFeKUWdy19SouJVUQHMD9ur06/4oQnc/nSMbsrY9gBQHTC5P
-99UKFg29ZkM3fiNDecNAhvVMKdqOmq0NpQSHiB6F4+lT1ZvIiwNjeOvgGUpuuy9r
-M2RYk61pv48b74JIxwIDAQABo1EwTzALBgNVHQ8EBAMCAYYwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUNQ/INmNe4qPs+TtmFc5RUuORmj0wEAYJKwYBBAGCNxUB
-BAMCAQAwDQYJKoZIhvcNAQELBQADggEBAEBM+4eymYGQfp3FsLAmzYh7KzKNbrgh
-cViXfa43FK8+5/ea4n32cZiZBKpDdHij40lhPnOMTZTg+XHEthYOU3gf1qKHLwI5
-gSk8rxWYITD+KJAAjNHhy/peyP34EEY7onhCkRd0VQreUGdNZtGn//3ZwLWoo4rO
-ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf
-aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
-Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
------END CERTIFICATE-----
-
-# Issuer: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A.
-# Subject: CN=SZAFIR ROOT CA2 O=Krajowa Izba Rozliczeniowa S.A.
-# Label: "SZAFIR ROOT CA2"
-# Serial: 357043034767186914217277344587386743377558296292
-# MD5 Fingerprint: 11:64:c1:89:b0:24:b1:8c:b1:07:7e:89:9e:51:9e:99
-# SHA1 Fingerprint: e2:52:fa:95:3f:ed:db:24:60:bd:6e:28:f3:9c:cc:cf:5e:b3:3f:de
-# SHA256 Fingerprint: a1:33:9d:33:28:1a:0b:56:e5:57:d3:d3:2b:1c:e7:f9:36:7e:b0:94:bd:5f:a7:2a:7e:50:04:c8:de:d7:ca:fe
------BEGIN CERTIFICATE-----
-MIIDcjCCAlqgAwIBAgIUPopdB+xV0jLVt+O2XwHrLdzk1uQwDQYJKoZIhvcNAQEL
-BQAwUTELMAkGA1UEBhMCUEwxKDAmBgNVBAoMH0tyYWpvd2EgSXpiYSBSb3psaWN6
-ZW5pb3dhIFMuQS4xGDAWBgNVBAMMD1NaQUZJUiBST09UIENBMjAeFw0xNTEwMTkw
-NzQzMzBaFw0zNTEwMTkwNzQzMzBaMFExCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9L
-cmFqb3dhIEl6YmEgUm96bGljemVuaW93YSBTLkEuMRgwFgYDVQQDDA9TWkFGSVIg
-Uk9PVCBDQTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC3vD5QqEvN
-QLXOYeeWyrSh2gwisPq1e3YAd4wLz32ohswmUeQgPYUM1ljj5/QqGJ3a0a4m7utT
-3PSQ1hNKDJA8w/Ta0o4NkjrcsbH/ON7Dui1fgLkCvUqdGw+0w8LBZwPd3BucPbOw
-3gAeqDRHu5rr/gsUvTaE2g0gv/pby6kWIK05YO4vdbbnl5z5Pv1+TW9NL++IDWr6
-3fE9biCloBK0TXC5ztdyO4mTp4CEHCdJckm1/zuVnsHMyAHs6A6KCpbns6aH5db5
-BSsNl0BwPLqsdVqc1U2dAgrSS5tmS0YHF2Wtn2yIANwiieDhZNRnvDF5YTy7ykHN
-XGoAyDw4jlivAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
-AgEGMB0GA1UdDgQWBBQuFqlKGLXLzPVvUPMjX/hd56zwyDANBgkqhkiG9w0BAQsF
-AAOCAQEAtXP4A9xZWx126aMqe5Aosk3AM0+qmrHUuOQn/6mWmc5G4G18TKI4pAZw
-8PRBEew/R40/cof5O/2kbytTAOD/OblqBw7rHRz2onKQy4I9EYKL0rufKq8h5mOG
-nXkZ7/e7DDWQw4rtTw/1zBLZpD67oPwglV9PJi8RI4NOdQcPv5vRtB3pEAT+ymCP
-oky4rc/hkA/NrgrHXXu3UNLUYfrVFdvXn4dRVOul4+vJhaAlIDf7js4MNIThPIGy
-d05DpYhfhmehPea0XGG2Ptv+tyjFogeutcrKjSoS75ftwjCkySp6+/NNIxuZMzSg
-LvWpCz/UXeHPhJ/iGcJfitYgHuNztw==
------END CERTIFICATE-----
-
-# Issuer: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority
-# Subject: CN=Certum Trusted Network CA 2 O=Unizeto Technologies S.A. OU=Certum Certification Authority
-# Label: "Certum Trusted Network CA 2"
-# Serial: 44979900017204383099463764357512596969
-# MD5 Fingerprint: 6d:46:9e:d9:25:6d:08:23:5b:5e:74:7d:1e:27:db:f2
-# SHA1 Fingerprint: d3:dd:48:3e:2b:bf:4c:05:e8:af:10:f5:fa:76:26:cf:d3:dc:30:92
-# SHA256 Fingerprint: b6:76:f2:ed:da:e8:77:5c:d3:6c:b0:f6:3c:d1:d4:60:39:61:f4:9e:62:65:ba:01:3a:2f:03:07:b6:d0:b8:04
------BEGIN CERTIFICATE-----
-MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB
-gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
-QS4xJzAlBgNVBAsTHkNlcnR1bSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEkMCIG
-A1UEAxMbQ2VydHVtIFRydXN0ZWQgTmV0d29yayBDQSAyMCIYDzIwMTExMDA2MDgz
-OTU2WhgPMjA0NjEwMDYwODM5NTZaMIGAMQswCQYDVQQGEwJQTDEiMCAGA1UEChMZ
-VW5pemV0byBUZWNobm9sb2dpZXMgUy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MSQwIgYDVQQDExtDZXJ0dW0gVHJ1c3RlZCBOZXR3
-b3JrIENBIDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC9+Xj45tWA
-DGSdhhuWZGc/IjoedQF97/tcZ4zJzFxrqZHmuULlIEub2pt7uZld2ZuAS9eEQCsn
-0+i6MLs+CRqnSZXvK0AkwpfHp+6bJe+oCgCXhVqqndwpyeI1B+twTUrWwbNWuKFB
-OJvR+zF/j+Bf4bE/D44WSWDXBo0Y+aomEKsq09DRZ40bRr5HMNUuctHFY9rnY3lE
-fktjJImGLjQ/KUxSiyqnwOKRKIm5wFv5HdnnJ63/mgKXwcZQkpsCLL2puTRZCr+E
-Sv/f/rOf69me4Jgj7KZrdxYq28ytOxykh9xGc14ZYmhFV+SQgkK7QtbwYeDBoz1m
-o130GO6IyY0XRSmZMnUCMe4pJshrAua1YkV/NxVaI2iJ1D7eTiew8EAMvE0Xy02i
-sx7QBlrd9pPPV3WZ9fqGGmd4s7+W/jTcvedSVuWz5XV710GRBdxdaeOVDUO5/IOW
-OZV7bIBaTxNyxtd9KXpEulKkKtVBRgkg/iKgtlswjbyJDNXXcPiHUv3a76xRLgez
-Tv7QCdpw75j6VuZt27VXS9zlLCUVyJ4ueE742pyehizKV/Ma5ciSixqClnrDvFAS
-adgOWkaLOusm+iPJtrCBvkIApPjW/jAux9JG9uWOdf3yzLnQh1vMBhBgu4M1t15n
-3kfsmUjxpKEV/q2MYo45VU85FrmxY53/twIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBS2oVQ5AsOgP46KvPrU+Bym0ToO/TAOBgNVHQ8BAf8EBAMC
-AQYwDQYJKoZIhvcNAQENBQADggIBAHGlDs7k6b8/ONWJWsQCYftMxRQXLYtPU2sQ
-F/xlhMcQSZDe28cmk4gmb3DWAl45oPePq5a1pRNcgRRtDoGCERuKTsZPpd1iHkTf
-CVn0W3cLN+mLIMb4Ck4uWBzrM9DPhmDJ2vuAL55MYIR4PSFk1vtBHxgP58l1cb29
-XN40hz5BsA72udY/CROWFC/emh1auVbONTqwX3BNXuMp8SMoclm2q8KMZiYcdywm
-djWLKKdpoPk79SPdhRB0yZADVpHnr7pH1BKXESLjokmUbOe3lEu6LaTaM4tMpkT/
-WjzGHWTYtTHkpjx6qFcL2+1hGsvxznN3Y6SHb0xRONbkX8eftoEq5IVIeVheO/jb
-AoJnwTnbw3RLPTYe+SmTiGhbqEQZIfCn6IENLOiTNrQ3ssqwGyZ6miUfmpqAnksq
-P/ujmv5zMnHCnsZy4YpoJ/HkD7TETKVhk/iXEAcqMCWpuchxuO9ozC1+9eB+D4Ko
-b7a6bINDd82Kkhehnlt4Fj1F4jNy3eFmypnTycUm/Q1oBEauttmbjL4ZvrHG8hnj
-XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P
-5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi
-DrW5viSP
------END CERTIFICATE-----
-
-# Issuer: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority
-# Subject: CN=Hellenic Academic and Research Institutions RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority
-# Label: "Hellenic Academic and Research Institutions RootCA 2015"
-# Serial: 0
-# MD5 Fingerprint: ca:ff:e2:db:03:d9:cb:4b:e9:0f:ad:84:fd:7b:18:ce
-# SHA1 Fingerprint: 01:0c:06:95:a6:98:19:14:ff:bf:5f:c6:b0:b6:95:ea:29:e9:12:a6
-# SHA256 Fingerprint: a0:40:92:9a:02:ce:53:b4:ac:f4:f2:ff:c6:98:1c:e4:49:6f:75:5e:6d:45:fe:0b:2a:69:2b:cd:52:52:3f:36
------BEGIN CERTIFICATE-----
-MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix
-DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k
-IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT
-N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v
-dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG
-A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh
-ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx
-QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
-dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
-AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA
-4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0
-AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10
-4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C
-ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV
-9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD
-gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6
-Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq
-NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko
-LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
-Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV
-HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd
-ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I
-XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI
-M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot
-9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V
-Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea
-j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh
-X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ
-l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf
-bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4
-pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK
-e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0
-vm9qp/UsQu0yrbYhnr68
------END CERTIFICATE-----
-
-# Issuer: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority
-# Subject: CN=Hellenic Academic and Research Institutions ECC RootCA 2015 O=Hellenic Academic and Research Institutions Cert. Authority
-# Label: "Hellenic Academic and Research Institutions ECC RootCA 2015"
-# Serial: 0
-# MD5 Fingerprint: 81:e5:b4:17:eb:c2:f5:e1:4b:0d:41:7b:49:92:fe:ef
-# SHA1 Fingerprint: 9f:f1:71:8d:92:d5:9a:f3:7d:74:97:b4:bc:6f:84:68:0b:ba:b6:66
-# SHA256 Fingerprint: 44:b5:45:aa:8a:25:e6:5a:73:ca:15:dc:27:fc:36:d2:4c:1c:b9:95:3a:06:65:39:b1:15:82:dc:48:7b:48:33
------BEGIN CERTIFICATE-----
-MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN
-BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
-c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl
-bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv
-b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ
-BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj
-YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5
-MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0
-dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg
-QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa
-jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC
-MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi
-C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep
-lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof
-TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
------END CERTIFICATE-----
-
-# Issuer: CN=ISRG Root X1 O=Internet Security Research Group
-# Subject: CN=ISRG Root X1 O=Internet Security Research Group
-# Label: "ISRG Root X1"
-# Serial: 172886928669790476064670243504169061120
-# MD5 Fingerprint: 0c:d2:f9:e0:da:17:73:e9:ed:86:4d:a5:e3:70:e7:4e
-# SHA1 Fingerprint: ca:bd:2a:79:a1:07:6a:31:f2:1d:25:36:35:cb:03:9d:43:29:a5:e8
-# SHA256 Fingerprint: 96:bc:ec:06:26:49:76:f3:74:60:77:9a:cf:28:c5:a7:cf:e8:a3:c0:aa:e1:1a:8f:fc:ee:05:c0:bd:df:08:c6
------BEGIN CERTIFICATE-----
-MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
-TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
-cmNoIEdyb3VwMRUwEwYDVQQDEwxJU1JHIFJvb3QgWDEwHhcNMTUwNjA0MTEwNDM4
-WhcNMzUwNjA0MTEwNDM4WjBPMQswCQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJu
-ZXQgU2VjdXJpdHkgUmVzZWFyY2ggR3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBY
-MTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK3oJHP0FDfzm54rVygc
-h77ct984kIxuPOZXoHj3dcKi/vVqbvYATyjb3miGbESTtrFj/RQSa78f0uoxmyF+
-0TM8ukj13Xnfs7j/EvEhmkvBioZxaUpmZmyPfjxwv60pIgbz5MDmgK7iS4+3mX6U
-A5/TR5d8mUgjU+g4rk8Kb4Mu0UlXjIB0ttov0DiNewNwIRt18jA8+o+u3dpjq+sW
-T8KOEUt+zwvo/7V3LvSye0rgTBIlDHCNAymg4VMk7BPZ7hm/ELNKjD+Jo2FR3qyH
-B5T0Y3HsLuJvW5iB4YlcNHlsdu87kGJ55tukmi8mxdAQ4Q7e2RCOFvu396j3x+UC
-B5iPNgiV5+I3lg02dZ77DnKxHZu8A/lJBdiB3QW0KtZB6awBdpUKD9jf1b0SHzUv
-KBds0pjBqAlkd25HN7rOrFleaJ1/ctaJxQZBKT5ZPt0m9STJEadao0xAH0ahmbWn
-OlFuhjuefXKnEgV4We0+UXgVCwOPjdAvBbI+e0ocS3MFEvzG6uBQE3xDk3SzynTn
-jh8BCNAw1FtxNrQHusEwMFxIt4I7mKZ9YIqioymCzLq9gwQbooMDQaHWBfEbwrbw
-qHyGO0aoSCqI3Haadr8faqU9GY/rOPNk3sgrDQoo//fb4hVC1CLQJ13hef4Y53CI
-rU7m2Ys6xt0nUW7/vGT1M0NPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR5tFnme7bl5AFzgAiIyBpY9umbbjANBgkq
-hkiG9w0BAQsFAAOCAgEAVR9YqbyyqFDQDLHYGmkgJykIrGF1XIpu+ILlaS/V9lZL
-ubhzEFnTIZd+50xx+7LSYK05qAvqFyFWhfFQDlnrzuBZ6brJFe+GnY+EgPbk6ZGQ
-3BebYhtF8GaV0nxvwuo77x/Py9auJ/GpsMiu/X1+mvoiBOv/2X/qkSsisRcOj/KK
-NFtY2PwByVS5uCbMiogziUwthDyC3+6WVwW6LLv3xLfHTjuCvjHIInNzktHCgKQ5
-ORAzI4JMPJ+GslWYHb4phowim57iaztXOoJwTdwJx4nLCgdNbOhdjsnvzqvHu7Ur
-TkXWStAmzOVyyghqpZXjFaH3pO3JLF+l+/+sKAIuvtd7u+Nxe5AW0wdeRlN8NwdC
-jNPElpzVmbUq4JUagEiuTDkHzsxHpFKVK7q4+63SM1N95R1NbdWhscdCb+ZAJzVc
-oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
-4RgqsahDYVvTH9w7jXbyLeiNdd8XM2w9U/t7y0Ff/9yi0GE44Za4rF2LN9d11TPA
-mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
-emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
------END CERTIFICATE-----
-
-# Issuer: O=FNMT-RCM OU=AC RAIZ FNMT-RCM
-# Subject: O=FNMT-RCM OU=AC RAIZ FNMT-RCM
-# Label: "AC RAIZ FNMT-RCM"
-# Serial: 485876308206448804701554682760554759
-# MD5 Fingerprint: e2:09:04:b4:d3:bd:d1:a0:14:fd:1a:d2:47:c4:57:1d
-# SHA1 Fingerprint: ec:50:35:07:b2:15:c4:95:62:19:e2:a8:9a:5b:42:99:2c:4c:2c:20
-# SHA256 Fingerprint: eb:c5:57:0c:29:01:8c:4d:67:b1:aa:12:7b:af:12:f7:03:b4:61:1e:bc:17:b7:da:b5:57:38:94:17:9b:93:fa
------BEGIN CERTIFICATE-----
-MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx
-CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ
-WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ
-BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG
-Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/
-yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf
-BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz
-WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF
-tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z
-374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC
-IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL
-mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7
-wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS
-MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2
-ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet
-UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw
-AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H
-YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3
-LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
-nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1
-RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM
-LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf
-77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N
-JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm
-fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp
-6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp
-1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B
-9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok
-RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv
-uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
------END CERTIFICATE-----
-
-# Issuer: CN=Amazon Root CA 1 O=Amazon
-# Subject: CN=Amazon Root CA 1 O=Amazon
-# Label: "Amazon Root CA 1"
-# Serial: 143266978916655856878034712317230054538369994
-# MD5 Fingerprint: 43:c6:bf:ae:ec:fe:ad:2f:18:c6:88:68:30:fc:c8:e6
-# SHA1 Fingerprint: 8d:a7:f9:65:ec:5e:fc:37:91:0f:1c:6e:59:fd:c1:cc:6a:6e:de:16
-# SHA256 Fingerprint: 8e:cd:e6:88:4f:3d:87:b1:12:5b:a3:1a:c3:fc:b1:3d:70:16:de:7f:57:cc:90:4f:e1:cb:97:c6:ae:98:19:6e
------BEGIN CERTIFICATE-----
-MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
-ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
-9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
-IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
-VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
-93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
-jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
-AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
-A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
-U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
-N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
-o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
-5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
-rqXRfboQnoZsG4q5WTP468SQvvG5
------END CERTIFICATE-----
-
-# Issuer: CN=Amazon Root CA 2 O=Amazon
-# Subject: CN=Amazon Root CA 2 O=Amazon
-# Label: "Amazon Root CA 2"
-# Serial: 143266982885963551818349160658925006970653239
-# MD5 Fingerprint: c8:e5:8d:ce:a8:42:e2:7a:c0:2a:5c:7c:9e:26:bf:66
-# SHA1 Fingerprint: 5a:8c:ef:45:d7:a6:98:59:76:7a:8c:8b:44:96:b5:78:cf:47:4b:1a
-# SHA256 Fingerprint: 1b:a5:b2:aa:8c:65:40:1a:82:96:01:18:f8:0b:ec:4f:62:30:4d:83:ce:c4:71:3a:19:c3:9c:01:1e:a4:6d:b4
------BEGIN CERTIFICATE-----
-MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
-ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
-b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
-MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
-b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
-gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
-W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
-1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
-8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
-2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
-z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
-8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
-mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
-7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
-+XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
-0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
-Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
-UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
-LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
-+gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
-k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
-7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
-btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
-urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
-fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
-n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
-76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
-9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
-4PsJYGw=
------END CERTIFICATE-----
-
-# Issuer: CN=Amazon Root CA 3 O=Amazon
-# Subject: CN=Amazon Root CA 3 O=Amazon
-# Label: "Amazon Root CA 3"
-# Serial: 143266986699090766294700635381230934788665930
-# MD5 Fingerprint: a0:d4:ef:0b:f7:b5:d8:49:95:2a:ec:f5:c4:fc:81:87
-# SHA1 Fingerprint: 0d:44:dd:8c:3c:8c:1a:1a:58:75:64:81:e9:0f:2e:2a:ff:b3:d2:6e
-# SHA256 Fingerprint: 18:ce:6c:fe:7b:f1:4e:60:b2:e3:47:b8:df:e8:68:cb:31:d0:2e:bb:3a:da:27:15:69:f5:03:43:b4:6d:b3:a4
------BEGIN CERTIFICATE-----
-MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
-MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
-Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
-A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
-Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
-ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
-QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
-ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
-BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
-YyRIHN8wfdVoOw==
------END CERTIFICATE-----
-
-# Issuer: CN=Amazon Root CA 4 O=Amazon
-# Subject: CN=Amazon Root CA 4 O=Amazon
-# Label: "Amazon Root CA 4"
-# Serial: 143266989758080763974105200630763877849284878
-# MD5 Fingerprint: 89:bc:27:d5:eb:17:8d:06:6a:69:d5:fd:89:47:b4:cd
-# SHA1 Fingerprint: f6:10:84:07:d6:f8:bb:67:98:0c:c2:e2:44:c2:eb:ae:1c:ef:63:be
-# SHA256 Fingerprint: e3:5d:28:41:9e:d0:20:25:cf:a6:90:38:cd:62:39:62:45:8d:a5:c6:95:fb:de:a3:c2:2b:0b:fb:25:89:70:92
------BEGIN CERTIFICATE-----
-MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
-MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
-Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
-A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
-Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
-9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
-M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
-/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
-MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
-CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
-1KyLa2tJElMzrdfkviT8tQp21KW8EA==
------END CERTIFICATE-----
-
-# Issuer: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
-# Subject: CN=TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1 O=Turkiye Bilimsel ve Teknolojik Arastirma Kurumu - TUBITAK OU=Kamu Sertifikasyon Merkezi - Kamu SM
-# Label: "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
-# Serial: 1
-# MD5 Fingerprint: dc:00:81:dc:69:2f:3e:2f:b0:3b:f6:3d:5a:91:8e:49
-# SHA1 Fingerprint: 31:43:64:9b:ec:ce:27:ec:ed:3a:3f:0b:8f:0d:e4:e8:91:dd:ee:ca
-# SHA256 Fingerprint: 46:ed:c3:68:90:46:d5:3a:45:3f:b3:10:4a:b8:0d:ca:ec:65:8b:26:60:ea:16:29:dd:7e:86:79:90:64:87:16
------BEGIN CERTIFICATE-----
-MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
-GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
-bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
-KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0
-BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy
-dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG
-EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll
-IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU
-QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT
-TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg
-LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7
-a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr
-LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr
-N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X
-YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/
-iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f
-AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH
-V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
-BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
-AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf
-IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4
-lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c
-8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
-lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
------END CERTIFICATE-----
-
-# Issuer: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD.
-# Subject: CN=GDCA TrustAUTH R5 ROOT O=GUANG DONG CERTIFICATE AUTHORITY CO.,LTD.
-# Label: "GDCA TrustAUTH R5 ROOT"
-# Serial: 9009899650740120186
-# MD5 Fingerprint: 63:cc:d9:3d:34:35:5c:6f:53:a3:e2:08:70:48:1f:b4
-# SHA1 Fingerprint: 0f:36:38:5b:81:1a:25:c3:9b:31:4e:83:ca:e9:34:66:70:cc:74:b4
-# SHA256 Fingerprint: bf:ff:8f:d0:44:33:48:7d:6a:8a:a6:0c:1a:29:76:7a:9f:c2:bb:b0:5e:42:0f:71:3a:13:b9:92:89:1d:38:93
------BEGIN CERTIFICATE-----
-MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
-BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
-IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0
-MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV
-BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w
-HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF
-AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj
-Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj
-TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u
-KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj
-qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm
-MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12
-ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP
-zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk
-L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC
-jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA
-HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC
-AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB
-/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
-p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm
-DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5
-COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry
-L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf
-JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg
-IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io
-2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV
-09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ
-XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq
-T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe
-MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com Root Certification Authority RSA O=SSL Corporation
-# Subject: CN=SSL.com Root Certification Authority RSA O=SSL Corporation
-# Label: "SSL.com Root Certification Authority RSA"
-# Serial: 8875640296558310041
-# MD5 Fingerprint: 86:69:12:c0:70:f1:ec:ac:ac:c2:d5:bc:a5:5b:a1:29
-# SHA1 Fingerprint: b7:ab:33:08:d1:ea:44:77:ba:14:80:12:5a:6f:bd:a9:36:49:0c:bb
-# SHA256 Fingerprint: 85:66:6a:56:2e:e0:be:5c:e9:25:c1:d8:89:0a:6f:76:a8:7e:c1:6d:4d:7d:5f:29:ea:74:19:cf:20:12:3b:69
------BEGIN CERTIFICATE-----
-MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
-BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
-DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz
-OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
-dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
-bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN
-AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R
-xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX
-qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC
-C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3
-6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh
-/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF
-YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E
-JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc
-US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8
-ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm
-+Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi
-M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
-HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G
-A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV
-cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc
-Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs
-PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/
-q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0
-cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr
-a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I
-H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y
-K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu
-nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf
-oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
-Ic2wBlX7Jz9TkHCpBB5XJ7k=
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com Root Certification Authority ECC O=SSL Corporation
-# Subject: CN=SSL.com Root Certification Authority ECC O=SSL Corporation
-# Label: "SSL.com Root Certification Authority ECC"
-# Serial: 8495723813297216424
-# MD5 Fingerprint: 2e:da:e4:39:7f:9c:8f:37:d1:70:9f:26:17:51:3a:8e
-# SHA1 Fingerprint: c3:19:7c:39:24:e6:54:af:1b:c4:ab:20:95:7a:e2:c3:0e:13:02:6a
-# SHA256 Fingerprint: 34:17:bb:06:cc:60:07:da:1b:96:1c:92:0b:8a:b4:ce:3f:ad:82:0e:4a:a3:0b:9a:cb:c4:a7:4e:bd:ce:bc:65
------BEGIN CERTIFICATE-----
-MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
-VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
-U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
-aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz
-WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0
-b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS
-b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
-BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI
-7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg
-CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud
-EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD
-VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T
-kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+
-gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation
-# Subject: CN=SSL.com EV Root Certification Authority RSA R2 O=SSL Corporation
-# Label: "SSL.com EV Root Certification Authority RSA R2"
-# Serial: 6248227494352943350
-# MD5 Fingerprint: e1:1e:31:58:1a:ae:54:53:02:f6:17:6a:11:7b:4d:95
-# SHA1 Fingerprint: 74:3a:f0:52:9b:d0:32:a0:f4:4a:83:cd:d4:ba:a9:7b:7c:2e:c4:9a
-# SHA256 Fingerprint: 2e:7b:f1:6c:c2:24:85:a7:bb:e2:aa:86:96:75:07:61:b0:ae:39:be:3b:2f:e9:d0:cc:6d:4e:f7:34:91:42:5c
------BEGIN CERTIFICATE-----
-MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
-BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
-CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
-dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy
-MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G
-A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD
-DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq
-M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf
-OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa
-4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9
-HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR
-aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA
-b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ
-Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV
-PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO
-pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu
-UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY
-MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
-HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4
-9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW
-s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5
-Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg
-cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM
-79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz
-/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt
-ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm
-Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK
-QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ
-w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi
-S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07
-mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation
-# Subject: CN=SSL.com EV Root Certification Authority ECC O=SSL Corporation
-# Label: "SSL.com EV Root Certification Authority ECC"
-# Serial: 3182246526754555285
-# MD5 Fingerprint: 59:53:22:65:83:42:01:54:c0:ce:42:b9:5a:7c:f2:90
-# SHA1 Fingerprint: 4c:dd:51:a3:d1:f5:20:32:14:b0:c6:c5:32:23:03:91:c7:46:42:6d
-# SHA256 Fingerprint: 22:a2:c1:f7:bd:ed:70:4c:c1:e7:01:b5:f4:08:c3:10:88:0f:e9:56:b5:de:2a:4a:44:f9:9c:87:3a:25:a7:c8
------BEGIN CERTIFICATE-----
-MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC
-VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
-U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx
-NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
-dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv
-bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49
-AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA
-VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku
-WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP
-MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX
-5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ
-ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg
-h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign Root CA - R6
-# Label: "GlobalSign Root CA - R6"
-# Serial: 1417766617973444989252670301619537
-# MD5 Fingerprint: 4f:dd:07:e4:d4:22:64:39:1e:0c:37:42:ea:d1:c6:ae
-# SHA1 Fingerprint: 80:94:64:0e:b5:a7:a1:ca:11:9c:1f:dd:d5:9f:81:02:63:a7:fb:d1
-# SHA256 Fingerprint: 2c:ab:ea:fe:37:d0:6c:a2:2a:ba:73:91:c0:03:3d:25:98:29:52:c4:53:64:73:49:76:3a:3a:b5:ad:6c:cf:69
------BEGIN CERTIFICATE-----
-MIIFgzCCA2ugAwIBAgIORea7A4Mzw4VlSOb/RVEwDQYJKoZIhvcNAQEMBQAwTDEg
-MB4GA1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjYxEzARBgNVBAoTCkdsb2Jh
-bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTQxMjEwMDAwMDAwWhcNMzQx
-MjEwMDAwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSNjET
-MBEGA1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAJUH6HPKZvnsFMp7PPcNCPG0RQssgrRI
-xutbPK6DuEGSMxSkb3/pKszGsIhrxbaJ0cay/xTOURQh7ErdG1rG1ofuTToVBu1k
-ZguSgMpE3nOUTvOniX9PeGMIyBJQbUJmL025eShNUhqKGoC3GYEOfsSKvGRMIRxD
-aNc9PIrFsmbVkJq3MQbFvuJtMgamHvm566qjuL++gmNQ0PAYid/kD3n16qIfKtJw
-LnvnvJO7bVPiSHyMEAc4/2ayd2F+4OqMPKq0pPbzlUoSB239jLKJz9CgYXfIWHSw
-1CM69106yqLbnQneXUQtkPGBzVeS+n68UARjNN9rkxi+azayOeSsJDa38O+2HBNX
-k7besvjihbdzorg1qkXy4J02oW9UivFyVm4uiMVRQkQVlO6jxTiWm05OWgtH8wY2
-SXcwvHE35absIQh1/OZhFj931dmRl4QKbNQCTXTAFO39OfuD8l4UoQSwC+n+7o/h
-bguyCLNhZglqsQY6ZZZZwPA1/cnaKI0aEYdwgQqomnUdnjqGBQCe24DWJfncBZ4n
-WUx2OVvq+aWh2IMP0f/fMBH5hc8zSPXKbWQULHpYT9NLCEnFlWQaYw55PfWzjMpY
-rZxCRXluDocZXFSxZba/jJvcE+kNb7gu3GduyYsRtYQUigAZcIN5kZeR1Bonvzce
-MgfYFGM8KEyvAgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTAD
-AQH/MB0GA1UdDgQWBBSubAWjkxPioufi1xzWx/B/yGdToDAfBgNVHSMEGDAWgBSu
-bAWjkxPioufi1xzWx/B/yGdToDANBgkqhkiG9w0BAQwFAAOCAgEAgyXt6NH9lVLN
-nsAEoJFp5lzQhN7craJP6Ed41mWYqVuoPId8AorRbrcWc+ZfwFSY1XS+wc3iEZGt
-Ixg93eFyRJa0lV7Ae46ZeBZDE1ZXs6KzO7V33EByrKPrmzU+sQghoefEQzd5Mr61
-55wsTLxDKZmOMNOsIeDjHfrYBzN2VAAiKrlNIC5waNrlU/yDXNOd8v9EDERm8tLj
-vUYAGm0CuiVdjaExUd1URhxN25mW7xocBFymFe944Hn+Xds+qkxV/ZoVqW/hpvvf
-cDDpw+5CRu3CkwWJ+n1jez/QcYF8AOiYrg54NMMl+68KnyBr3TsTjxKM4kEaSHpz
-oHdpx7Zcf4LIHv5YGygrqGytXm3ABdJ7t+uA/iU3/gKbaKxCXcPu9czc8FB10jZp
-nOZ7BN9uBmm23goJSFmH63sUYHpkqmlD75HHTOwY3WzvUy2MmeFe8nI+z1TIvWfs
-pA9MRf/TuTAjB0yPEL+GltmZWrSZVxykzLsViVO6LAUP5MSeGbEYNNVMnbrt9x+v
-JJUEeKgDu+6B5dpffItKoZB0JaezPkvILFa9x8jvOOJckvB595yEunQtYQEgfn7R
-8k8HWV+LLUNS60YMlOH1Zkd5d9VUWx+tJDfLRVpOoERIyNiwmcUVhAn21klJwGW4
-5hpxbqCo8YLoRT5s1gLXCmeDBVrJpBA=
------END CERTIFICATE-----
-
-# Issuer: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
-# Subject: CN=OISTE WISeKey Global Root GC CA O=WISeKey OU=OISTE Foundation Endorsed
-# Label: "OISTE WISeKey Global Root GC CA"
-# Serial: 44084345621038548146064804565436152554
-# MD5 Fingerprint: a9:d6:b9:2d:2f:93:64:f8:a5:69:ca:91:e9:68:07:23
-# SHA1 Fingerprint: e0:11:84:5e:34:de:be:88:81:b9:9c:f6:16:26:d1:96:1f:c3:b9:31
-# SHA256 Fingerprint: 85:60:f9:1c:36:24:da:ba:95:70:b5:fe:a0:db:e3:6f:f1:1a:83:23:be:94:86:85:4f:b3:f3:4a:55:71:19:8d
------BEGIN CERTIFICATE-----
-MIICaTCCAe+gAwIBAgIQISpWDK7aDKtARb8roi066jAKBggqhkjOPQQDAzBtMQsw
-CQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUgRm91
-bmRhdGlvbiBFbmRvcnNlZDEoMCYGA1UEAxMfT0lTVEUgV0lTZUtleSBHbG9iYWwg
-Um9vdCBHQyBDQTAeFw0xNzA1MDkwOTQ4MzRaFw00MjA1MDkwOTU4MzNaMG0xCzAJ
-BgNVBAYTAkNIMRAwDgYDVQQKEwdXSVNlS2V5MSIwIAYDVQQLExlPSVNURSBGb3Vu
-ZGF0aW9uIEVuZG9yc2VkMSgwJgYDVQQDEx9PSVNURSBXSVNlS2V5IEdsb2JhbCBS
-b290IEdDIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAETOlQwMYPchi82PG6s4ni
-eUqjFqdrVCTbUf/q9Akkwwsin8tqJ4KBDdLArzHkdIJuyiXZjHWd8dvQmqJLIX4W
-p2OQ0jnUsYd4XxiWD1AbNTcPasbc2RNNpI6QN+a9WzGRo1QwUjAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUSIcUrOPDnpBgOtfKie7T
-rYy0UGYwEAYJKwYBBAGCNxUBBAMCAQAwCgYIKoZIzj0EAwMDaAAwZQIwJsdpW9zV
-57LnyAyMjMPdeYwbY9XJUpROTYJKcx6ygISpJcBMWm1JKWB4E+J+SOtkAjEA2zQg
-Mgj/mkkCtojeFK9dbJlxjRo/i9fgojaGHAeCOnZT/cKi7e97sIBPWA9LUzm9
------END CERTIFICATE-----
-
-# Issuer: CN=UCA Global G2 Root O=UniTrust
-# Subject: CN=UCA Global G2 Root O=UniTrust
-# Label: "UCA Global G2 Root"
-# Serial: 124779693093741543919145257850076631279
-# MD5 Fingerprint: 80:fe:f0:c4:4a:f0:5c:62:32:9f:1c:ba:78:a9:50:f8
-# SHA1 Fingerprint: 28:f9:78:16:19:7a:ff:18:25:18:aa:44:fe:c1:a0:ce:5c:b6:4c:8a
-# SHA256 Fingerprint: 9b:ea:11:c9:76:fe:01:47:64:c1:be:56:a6:f9:14:b5:a5:60:31:7a:bd:99:88:39:33:82:e5:16:1a:a0:49:3c
------BEGIN CERTIFICATE-----
-MIIFRjCCAy6gAwIBAgIQXd+x2lqj7V2+WmUgZQOQ7zANBgkqhkiG9w0BAQsFADA9
-MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxGzAZBgNVBAMMElVDQSBH
-bG9iYWwgRzIgUm9vdDAeFw0xNjAzMTEwMDAwMDBaFw00MDEyMzEwMDAwMDBaMD0x
-CzAJBgNVBAYTAkNOMREwDwYDVQQKDAhVbmlUcnVzdDEbMBkGA1UEAwwSVUNBIEds
-b2JhbCBHMiBSb290MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAxeYr
-b3zvJgUno4Ek2m/LAfmZmqkywiKHYUGRO8vDaBsGxUypK8FnFyIdK+35KYmToni9
-kmugow2ifsqTs6bRjDXVdfkX9s9FxeV67HeToI8jrg4aA3++1NDtLnurRiNb/yzm
-VHqUwCoV8MmNsHo7JOHXaOIxPAYzRrZUEaalLyJUKlgNAQLx+hVRZ2zA+te2G3/R
-VogvGjqNO7uCEeBHANBSh6v7hn4PJGtAnTRnvI3HLYZveT6OqTwXS3+wmeOwcWDc
-C/Vkw85DvG1xudLeJ1uK6NjGruFZfc8oLTW4lVYa8bJYS7cSN8h8s+1LgOGN+jIj
-tm+3SJUIsUROhYw6AlQgL9+/V087OpAh18EmNVQg7Mc/R+zvWr9LesGtOxdQXGLY
-D0tK3Cv6brxzks3sx1DoQZbXqX5t2Okdj4q1uViSukqSKwxW/YDrCPBeKW4bHAyv
-j5OJrdu9o54hyokZ7N+1wxrrFv54NkzWbtA+FxyQF2smuvt6L78RHBgOLXMDj6Dl
-NaBa4kx1HXHhOThTeEDMg5PXCp6dW4+K5OXgSORIskfNTip1KnvyIvbJvgmRlld6
-iIis7nCs+dwp4wwcOxJORNanTrAmyPPZGpeRaOrvjUYG0lZFWJo8DA+DuAUlwznP
-O6Q0ibd5Ei9Hxeepl2n8pndntd978XplFeRhVmUCAwEAAaNCMEAwDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFIHEjMz15DD/pQwIX4wV
-ZyF0Ad/fMA0GCSqGSIb3DQEBCwUAA4ICAQATZSL1jiutROTL/7lo5sOASD0Ee/oj
-L3rtNtqyzm325p7lX1iPyzcyochltq44PTUbPrw7tgTQvPlJ9Zv3hcU2tsu8+Mg5
-1eRfB70VVJd0ysrtT7q6ZHafgbiERUlMjW+i67HM0cOU2kTC5uLqGOiiHycFutfl
-1qnN3e92mI0ADs0b+gO3joBYDic/UvuUospeZcnWhNq5NXHzJsBPd+aBJ9J3O5oU
-b3n09tDh05S60FdRvScFDcH9yBIw7m+NESsIndTUv4BFFJqIRNow6rSn4+7vW4LV
-PtateJLbXDzz2K36uGt/xDYotgIVilQsnLAXc47QN6MUPJiVAAwpBVueSUmxX8fj
-y88nZY41F7dXyDDZQVu5FLbowg+UMaeUmMxq67XhJ/UQqAHojhJi6IjMtX9Gl8Cb
-EGY4GjZGXyJoPd/JxhMnq1MGrKI8hgZlb7F+sSlEmqO6SWkoaY/X5V+tBIZkbxqg
-DMUIYs6Ao9Dz7GjevjPHF1t/gMRMTLGmhIrDO7gJzRSBuhjjVFc2/tsvfEehOjPI
-+Vg7RE+xygKJBJYoaMVLuCaJu9YzL1DV/pqJuhgyklTGW+Cd+V7lDSKb9triyCGy
-YiGqhkCyLmTTX8jjfhFnRR8F/uOi77Oos/N9j/gMHyIfLXC0uAE0djAA5SN4p1bX
-UB+K+wb1whnw0A==
------END CERTIFICATE-----
-
-# Issuer: CN=UCA Extended Validation Root O=UniTrust
-# Subject: CN=UCA Extended Validation Root O=UniTrust
-# Label: "UCA Extended Validation Root"
-# Serial: 106100277556486529736699587978573607008
-# MD5 Fingerprint: a1:f3:5f:43:c6:34:9b:da:bf:8c:7e:05:53:ad:96:e2
-# SHA1 Fingerprint: a3:a1:b0:6f:24:61:23:4a:e3:36:a5:c2:37:fc:a6:ff:dd:f0:d7:3a
-# SHA256 Fingerprint: d4:3a:f9:b3:54:73:75:5c:96:84:fc:06:d7:d8:cb:70:ee:5c:28:e7:73:fb:29:4e:b4:1e:e7:17:22:92:4d:24
------BEGIN CERTIFICATE-----
-MIIFWjCCA0KgAwIBAgIQT9Irj/VkyDOeTzRYZiNwYDANBgkqhkiG9w0BAQsFADBH
-MQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNVBAMMHFVDQSBF
-eHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwHhcNMTUwMzEzMDAwMDAwWhcNMzgxMjMx
-MDAwMDAwWjBHMQswCQYDVQQGEwJDTjERMA8GA1UECgwIVW5pVHJ1c3QxJTAjBgNV
-BAMMHFVDQSBFeHRlbmRlZCBWYWxpZGF0aW9uIFJvb3QwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCpCQcoEwKwmeBkqh5DFnpzsZGgdT6o+uM4AHrsiWog
-D4vFsJszA1qGxliG1cGFu0/GnEBNyr7uaZa4rYEwmnySBesFK5pI0Lh2PpbIILvS
-sPGP2KxFRv+qZ2C0d35qHzwaUnoEPQc8hQ2E0B92CvdqFN9y4zR8V05WAT558aop
-O2z6+I9tTcg1367r3CTueUWnhbYFiN6IXSV8l2RnCdm/WhUFhvMJHuxYMjMR83dk
-sHYf5BA1FxvyDrFspCqjc/wJHx4yGVMR59mzLC52LqGj3n5qiAno8geK+LLNEOfi
-c0CTuwjRP+H8C5SzJe98ptfRr5//lpr1kXuYC3fUfugH0mK1lTnj8/FtDw5lhIpj
-VMWAtuCeS31HJqcBCF3RiJ7XwzJE+oJKCmhUfzhTA8ykADNkUVkLo4KRel7sFsLz
-KuZi2irbWWIQJUoqgQtHB0MGcIfS+pMRKXpITeuUx3BNr2fVUbGAIAEBtHoIppB/
-TuDvB0GHr2qlXov7z1CymlSvw4m6WC31MJixNnI5fkkE/SmnTHnkBVfblLkWU41G
-sx2VYVdWf6/wFlthWG82UBEL2KwrlRYaDh8IzTY0ZRBiZtWAXxQgXy0MoHgKaNYs
-1+lvK9JKBZP8nm9rZ/+I8U6laUpSNwXqxhaN0sSZ0YIrO7o1dfdRUVjzyAfd5LQD
-fwIDAQABo0IwQDAdBgNVHQ4EFgQU2XQ65DA9DfcS3H5aBZ8eNJr34RQwDwYDVR0T
-AQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQADggIBADaN
-l8xCFWQpN5smLNb7rhVpLGsaGvdftvkHTFnq88nIua7Mui563MD1sC3AO6+fcAUR
-ap8lTwEpcOPlDOHqWnzcSbvBHiqB9RZLcpHIojG5qtr8nR/zXUACE/xOHAbKsxSQ
-VBcZEhrxH9cMaVr2cXj0lH2RC47skFSOvG+hTKv8dGT9cZr4QQehzZHkPJrgmzI5
-c6sq1WnIeJEmMX3ixzDx/BR4dxIOE/TdFpS/S2d7cFOFyrC78zhNLJA5wA3CXWvp
-4uXViI3WLL+rG761KIcSF3Ru/H38j9CHJrAb+7lsq+KePRXBOy5nAliRn+/4Qh8s
-t2j1da3Ptfb/EX3C8CSlrdP6oDyp+l3cpaDvRKS+1ujl5BOWF3sGPjLtx7dCvHaj
-2GU4Kzg1USEODm8uNBNA4StnDG1KQTAYI1oyVZnJF+A83vbsea0rWBmirSwiGpWO
-vpaQXUJXxPkUAzUrHC1RVwinOt4/5Mi0A3PCwSaAuwtCH60NryZy2sy+s6ODWA2C
-xR9GUeOcGMyNm43sSet1UNWMKFnKdDTajAshqx7qG+XH/RU+wBeq+yNuJkbL+vmx
-cmtpzyKEC2IPrNkZAJSidjzULZrtBJ4tBmIQN1IchXIbJ+XMxjHsN+xjWZsLHXbM
-fjKaiJUINlK73nZfdklJrX+9ZSCyycErdhh2n1ax
------END CERTIFICATE-----
-
-# Issuer: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
-# Subject: CN=Certigna Root CA O=Dhimyotis OU=0002 48146308100036
-# Label: "Certigna Root CA"
-# Serial: 269714418870597844693661054334862075617
-# MD5 Fingerprint: 0e:5c:30:62:27:eb:5b:bc:d7:ae:62:ba:e9:d5:df:77
-# SHA1 Fingerprint: 2d:0d:52:14:ff:9e:ad:99:24:01:74:20:47:6e:6c:85:27:27:f5:43
-# SHA256 Fingerprint: d4:8d:3d:23:ee:db:50:a4:59:e5:51:97:60:1c:27:77:4b:9d:7b:18:c9:4d:5a:05:95:11:a1:02:50:b9:31:68
------BEGIN CERTIFICATE-----
-MIIGWzCCBEOgAwIBAgIRAMrpG4nxVQMNo+ZBbcTjpuEwDQYJKoZIhvcNAQELBQAw
-WjELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCURoaW15b3RpczEcMBoGA1UECwwTMDAw
-MiA0ODE0NjMwODEwMDAzNjEZMBcGA1UEAwwQQ2VydGlnbmEgUm9vdCBDQTAeFw0x
-MzEwMDEwODMyMjdaFw0zMzEwMDEwODMyMjdaMFoxCzAJBgNVBAYTAkZSMRIwEAYD
-VQQKDAlEaGlteW90aXMxHDAaBgNVBAsMEzAwMDIgNDgxNDYzMDgxMDAwMzYxGTAX
-BgNVBAMMEENlcnRpZ25hIFJvb3QgQ0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw
-ggIKAoICAQDNGDllGlmx6mQWDoyUJJV8g9PFOSbcDO8WV43X2KyjQn+Cyu3NW9sO
-ty3tRQgXstmzy9YXUnIo245Onoq2C/mehJpNdt4iKVzSs9IGPjA5qXSjklYcoW9M
-CiBtnyN6tMbaLOQdLNyzKNAT8kxOAkmhVECe5uUFoC2EyP+YbNDrihqECB63aCPu
-I9Vwzm1RaRDuoXrC0SIxwoKF0vJVdlB8JXrJhFwLrN1CTivngqIkicuQstDuI7pm
-TLtipPlTWmR7fJj6o0ieD5Wupxj0auwuA0Wv8HT4Ks16XdG+RCYyKfHx9WzMfgIh
-C59vpD++nVPiz32pLHxYGpfhPTc3GGYo0kDFUYqMwy3OU4gkWGQwFsWq4NYKpkDf
-ePb1BHxpE4S80dGnBs8B92jAqFe7OmGtBIyT46388NtEbVncSVmurJqZNjBBe3Yz
-IoejwpKGbvlw7q6Hh5UbxHq9MfPU0uWZ/75I7HX1eBYdpnDBfzwboZL7z8g81sWT
-Co/1VTp2lc5ZmIoJlXcymoO6LAQ6l73UL77XbJuiyn1tJslV1c/DeVIICZkHJC1k
-JWumIWmbat10TWuXekG9qxf5kBdIjzb5LdXF2+6qhUVB+s06RbFo5jZMm5BX7CO5
-hwjCxAnxl4YqKE3idMDaxIzb3+KhF1nOJFl0Mdp//TBt2dzhauH8XwIDAQABo4IB
-GjCCARYwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYE
-FBiHVuBud+4kNTxOc5of1uHieX4rMB8GA1UdIwQYMBaAFBiHVuBud+4kNTxOc5of
-1uHieX4rMEQGA1UdIAQ9MDswOQYEVR0gADAxMC8GCCsGAQUFBwIBFiNodHRwczov
-L3d3d3cuY2VydGlnbmEuZnIvYXV0b3JpdGVzLzBtBgNVHR8EZjBkMC+gLaArhilo
-dHRwOi8vY3JsLmNlcnRpZ25hLmZyL2NlcnRpZ25hcm9vdGNhLmNybDAxoC+gLYYr
-aHR0cDovL2NybC5kaGlteW90aXMuY29tL2NlcnRpZ25hcm9vdGNhLmNybDANBgkq
-hkiG9w0BAQsFAAOCAgEAlLieT/DjlQgi581oQfccVdV8AOItOoldaDgvUSILSo3L
-6btdPrtcPbEo/uRTVRPPoZAbAh1fZkYJMyjhDSSXcNMQH+pkV5a7XdrnxIxPTGRG
-HVyH41neQtGbqH6mid2PHMkwgu07nM3A6RngatgCdTer9zQoKJHyBApPNeNgJgH6
-0BGM+RFq7q89w1DTj18zeTyGqHNFkIwgtnJzFyO+B2XleJINugHA64wcZr+shncB
-lA2c5uk5jR+mUYyZDDl34bSb+hxnV29qao6pK0xXeXpXIs/NX2NGjVxZOob4Mkdi
-o2cNGJHc+6Zr9UhhcyNZjgKnvETq9Emd8VRY+WCv2hikLyhF3HqgiIZd8zvn/yk1
-gPxkQ5Tm4xxvvq0OKmOZK8l+hfZx6AYDlf7ej0gcWtSS6Cvu5zHbugRqh5jnxV/v
-faci9wHYTfmJ0A6aBVmknpjZbyvKcL5kwlWj9Omvw5Ip3IgWJJk8jSaYtlu3zM63
-Nwf9JtmYhST/WSMDmu2dnajkXjjO11INb9I/bbEFa0nOipFGc/T2L/Coc3cOZayh
-jWZSaX5LaAzHHjcng6WMxwLkFM1JAbBzs/3GkDpv0mztO+7skb6iQ12LAEpmJURw
-3kAP+HwV96LOPNdeE4yBFxgX0b3xdxA61GU5wSesVywlVP+i2k+KYTlerj1KjL0=
------END CERTIFICATE-----
-
-# Issuer: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI
-# Subject: CN=emSign Root CA - G1 O=eMudhra Technologies Limited OU=emSign PKI
-# Label: "emSign Root CA - G1"
-# Serial: 235931866688319308814040
-# MD5 Fingerprint: 9c:42:84:57:dd:cb:0b:a7:2e:95:ad:b6:f3:da:bc:ac
-# SHA1 Fingerprint: 8a:c7:ad:8f:73:ac:4e:c1:b5:75:4d:a5:40:f4:fc:cf:7c:b5:8e:8c
-# SHA256 Fingerprint: 40:f6:af:03:46:a9:9a:a1:cd:1d:55:5a:4e:9c:ce:62:c7:f9:63:46:03:ee:40:66:15:83:3d:c8:c8:d0:03:67
------BEGIN CERTIFICATE-----
-MIIDlDCCAnygAwIBAgIKMfXkYgxsWO3W2DANBgkqhkiG9w0BAQsFADBnMQswCQYD
-VQQGEwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBU
-ZWNobm9sb2dpZXMgTGltaXRlZDEcMBoGA1UEAxMTZW1TaWduIFJvb3QgQ0EgLSBH
-MTAeFw0xODAyMTgxODMwMDBaFw00MzAyMTgxODMwMDBaMGcxCzAJBgNVBAYTAklO
-MRMwEQYDVQQLEwplbVNpZ24gUEtJMSUwIwYDVQQKExxlTXVkaHJhIFRlY2hub2xv
-Z2llcyBMaW1pdGVkMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEcxMIIBIjAN
-BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAk0u76WaK7p1b1TST0Bsew+eeuGQz
-f2N4aLTNLnF115sgxk0pvLZoYIr3IZpWNVrzdr3YzZr/k1ZLpVkGoZM0Kd0WNHVO
-8oG0x5ZOrRkVUkr+PHB1cM2vK6sVmjM8qrOLqs1D/fXqcP/tzxE7lM5OMhbTI0Aq
-d7OvPAEsbO2ZLIvZTmmYsvePQbAyeGHWDV/D+qJAkh1cF+ZwPjXnorfCYuKrpDhM
-tTk1b+oDafo6VGiFbdbyL0NVHpENDtjVaqSW0RM8LHhQ6DqS0hdW5TUaQBw+jSzt
-Od9C4INBdN+jzcKGYEho42kLVACL5HZpIQ15TjQIXhTCzLG3rdd8cIrHhQIDAQAB
-o0IwQDAdBgNVHQ4EFgQU++8Nhp6w492pufEhF38+/PB3KxowDgYDVR0PAQH/BAQD
-AgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAFn/8oz1h31x
-PaOfG1vR2vjTnGs2vZupYeveFix0PZ7mddrXuqe8QhfnPZHr5X3dPpzxz5KsbEjM
-wiI/aTvFthUvozXGaCocV685743QNcMYDHsAVhzNixl03r4PEuDQqqE/AjSxcM6d
-GNYIAwlG7mDgfrbESQRRfXBgvKqy/3lyeqYdPV8q+Mri/Tm3R7nrft8EI6/6nAYH
-6ftjk4BAtcZsCjEozgyfz7MjNYBBjWzEN3uBL4ChQEKF6dk4jeihU80Bv2noWgby
-RQuQ+q7hv53yrlc8pa6yVvSLZUDp/TGBLPQ5Cdjua6e0ph0VpZj3AYHYhX3zUVxx
-iN66zB+Afko=
------END CERTIFICATE-----
-
-# Issuer: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI
-# Subject: CN=emSign ECC Root CA - G3 O=eMudhra Technologies Limited OU=emSign PKI
-# Label: "emSign ECC Root CA - G3"
-# Serial: 287880440101571086945156
-# MD5 Fingerprint: ce:0b:72:d1:9f:88:8e:d0:50:03:e8:e3:b8:8b:67:40
-# SHA1 Fingerprint: 30:43:fa:4f:f2:57:dc:a0:c3:80:ee:2e:58:ea:78:b2:3f:e6:bb:c1
-# SHA256 Fingerprint: 86:a1:ec:ba:08:9c:4a:8d:3b:be:27:34:c6:12:ba:34:1d:81:3e:04:3c:f9:e8:a8:62:cd:5c:57:a3:6b:be:6b
------BEGIN CERTIFICATE-----
-MIICTjCCAdOgAwIBAgIKPPYHqWhwDtqLhDAKBggqhkjOPQQDAzBrMQswCQYDVQQG
-EwJJTjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNo
-bm9sb2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0g
-RzMwHhcNMTgwMjE4MTgzMDAwWhcNNDMwMjE4MTgzMDAwWjBrMQswCQYDVQQGEwJJ
-TjETMBEGA1UECxMKZW1TaWduIFBLSTElMCMGA1UEChMcZU11ZGhyYSBUZWNobm9s
-b2dpZXMgTGltaXRlZDEgMB4GA1UEAxMXZW1TaWduIEVDQyBSb290IENBIC0gRzMw
-djAQBgcqhkjOPQIBBgUrgQQAIgNiAAQjpQy4LRL1KPOxst3iAhKAnjlfSU2fySU0
-WXTsuwYc58Byr+iuL+FBVIcUqEqy6HyC5ltqtdyzdc6LBtCGI79G1Y4PPwT01xyS
-fvalY8L1X44uT6EYGQIrMgqCZH0Wk9GjQjBAMB0GA1UdDgQWBBR8XQKEE9TMipuB
-zhccLikenEhjQjAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggq
-hkjOPQQDAwNpADBmAjEAvvNhzwIQHWSVB7gYboiFBS+DCBeQyh+KTOgNG3qxrdWB
-CUfvO6wIBHxcmbHtRwfSAjEAnbpV/KlK6O3t5nYBQnvI+GDZjVGLVTv7jHvrZQnD
-+JbNR6iC8hZVdyR+EhCVBCyj
------END CERTIFICATE-----
-
-# Issuer: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI
-# Subject: CN=emSign Root CA - C1 O=eMudhra Inc OU=emSign PKI
-# Label: "emSign Root CA - C1"
-# Serial: 825510296613316004955058
-# MD5 Fingerprint: d8:e3:5d:01:21:fa:78:5a:b0:df:ba:d2:ee:2a:5f:68
-# SHA1 Fingerprint: e7:2e:f1:df:fc:b2:09:28:cf:5d:d4:d5:67:37:b1:51:cb:86:4f:01
-# SHA256 Fingerprint: 12:56:09:aa:30:1d:a0:a2:49:b9:7a:82:39:cb:6a:34:21:6f:44:dc:ac:9f:39:54:b1:42:92:f2:e8:c8:60:8f
------BEGIN CERTIFICATE-----
-MIIDczCCAlugAwIBAgILAK7PALrEzzL4Q7IwDQYJKoZIhvcNAQELBQAwVjELMAkG
-A1UEBhMCVVMxEzARBgNVBAsTCmVtU2lnbiBQS0kxFDASBgNVBAoTC2VNdWRocmEg
-SW5jMRwwGgYDVQQDExNlbVNpZ24gUm9vdCBDQSAtIEMxMB4XDTE4MDIxODE4MzAw
-MFoXDTQzMDIxODE4MzAwMFowVjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
-biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMRwwGgYDVQQDExNlbVNpZ24gUm9v
-dCBDQSAtIEMxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAz+upufGZ
-BczYKCFK83M0UYRWEPWgTywS4/oTmifQz/l5GnRfHXk5/Fv4cI7gklL35CX5VIPZ
-HdPIWoU/Xse2B+4+wM6ar6xWQio5JXDWv7V7Nq2s9nPczdcdioOl+yuQFTdrHCZH
-3DspVpNqs8FqOp099cGXOFgFixwR4+S0uF2FHYP+eF8LRWgYSKVGczQ7/g/IdrvH
-GPMF0Ybzhe3nudkyrVWIzqa2kbBPrH4VI5b2P/AgNBbeCsbEBEV5f6f9vtKppa+c
-xSMq9zwhbL2vj07FOrLzNBL834AaSaTUqZX3noleoomslMuoaJuvimUnzYnu3Yy1
-aylwQ6BpC+S5DwIDAQABo0IwQDAdBgNVHQ4EFgQU/qHgcB4qAzlSWkK+XJGFehiq
-TbUwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
-BQADggEBAMJKVvoVIXsoounlHfv4LcQ5lkFMOycsxGwYFYDGrK9HWS8mC+M2sO87
-/kOXSTKZEhVb3xEp/6tT+LvBeA+snFOvV71ojD1pM/CjoCNjO2RnIkSt1XHLVip4
-kqNPEjE2NuLe/gDEo2APJ62gsIq1NnpSob0n9CAnYuhNlCQT5AoE6TyrLshDCUrG
-YQTlSTR+08TI9Q/Aqum6VF7zYytPT1DU/rl7mYw9wC68AivTxEDkigcxHpvOJpkT
-+xHqmiIMERnHXhuBUDDIlhJu58tBf5E7oke3VIAb3ADMmpDqw8NQBmIMMMAVSKeo
-WXzhriKi4gp6D/piq1JM4fHfyr6DDUI=
------END CERTIFICATE-----
-
-# Issuer: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI
-# Subject: CN=emSign ECC Root CA - C3 O=eMudhra Inc OU=emSign PKI
-# Label: "emSign ECC Root CA - C3"
-# Serial: 582948710642506000014504
-# MD5 Fingerprint: 3e:53:b3:a3:81:ee:d7:10:f8:d3:b0:1d:17:92:f5:d5
-# SHA1 Fingerprint: b6:af:43:c2:9b:81:53:7d:f6:ef:6b:c3:1f:1f:60:15:0c:ee:48:66
-# SHA256 Fingerprint: bc:4d:80:9b:15:18:9d:78:db:3e:1d:8c:f4:f9:72:6a:79:5d:a1:64:3c:a5:f1:35:8e:1d:db:0e:dc:0d:7e:b3
------BEGIN CERTIFICATE-----
-MIICKzCCAbGgAwIBAgIKe3G2gla4EnycqDAKBggqhkjOPQQDAzBaMQswCQYDVQQG
-EwJVUzETMBEGA1UECxMKZW1TaWduIFBLSTEUMBIGA1UEChMLZU11ZGhyYSBJbmMx
-IDAeBgNVBAMTF2VtU2lnbiBFQ0MgUm9vdCBDQSAtIEMzMB4XDTE4MDIxODE4MzAw
-MFoXDTQzMDIxODE4MzAwMFowWjELMAkGA1UEBhMCVVMxEzARBgNVBAsTCmVtU2ln
-biBQS0kxFDASBgNVBAoTC2VNdWRocmEgSW5jMSAwHgYDVQQDExdlbVNpZ24gRUND
-IFJvb3QgQ0EgLSBDMzB2MBAGByqGSM49AgEGBSuBBAAiA2IABP2lYa57JhAd6bci
-MK4G9IGzsUJxlTm801Ljr6/58pc1kjZGDoeVjbk5Wum739D+yAdBPLtVb4Ojavti
-sIGJAnB9SMVK4+kiVCJNk7tCDK93nCOmfddhEc5lx/h//vXyqaNCMEAwHQYDVR0O
-BBYEFPtaSNCAIEDyqOkAB2kZd6fmw/TPMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMB
-Af8EBTADAQH/MAoGCCqGSM49BAMDA2gAMGUCMQC02C8Cif22TGK6Q04ThHK1rt0c
-3ta13FaPWEBaLd4gTCKDypOofu4SQMfWh0/434UCMBwUZOR8loMRnLDRWmFLpg9J
-0wD8ofzkpf9/rdcw0Md3f76BB1UwUCAU9Vc4CqgxUQ==
------END CERTIFICATE-----
-
-# Issuer: CN=Hongkong Post Root CA 3 O=Hongkong Post
-# Subject: CN=Hongkong Post Root CA 3 O=Hongkong Post
-# Label: "Hongkong Post Root CA 3"
-# Serial: 46170865288971385588281144162979347873371282084
-# MD5 Fingerprint: 11:fc:9f:bd:73:30:02:8a:fd:3f:f3:58:b9:cb:20:f0
-# SHA1 Fingerprint: 58:a2:d0:ec:20:52:81:5b:c1:f3:f8:64:02:24:4e:c2:8e:02:4b:02
-# SHA256 Fingerprint: 5a:2f:c0:3f:0c:83:b0:90:bb:fa:40:60:4b:09:88:44:6c:76:36:18:3d:f9:84:6e:17:10:1a:44:7f:b8:ef:d6
------BEGIN CERTIFICATE-----
-MIIFzzCCA7egAwIBAgIUCBZfikyl7ADJk0DfxMauI7gcWqQwDQYJKoZIhvcNAQEL
-BQAwbzELMAkGA1UEBhMCSEsxEjAQBgNVBAgTCUhvbmcgS29uZzESMBAGA1UEBxMJ
-SG9uZyBLb25nMRYwFAYDVQQKEw1Ib25na29uZyBQb3N0MSAwHgYDVQQDExdIb25n
-a29uZyBQb3N0IFJvb3QgQ0EgMzAeFw0xNzA2MDMwMjI5NDZaFw00MjA2MDMwMjI5
-NDZaMG8xCzAJBgNVBAYTAkhLMRIwEAYDVQQIEwlIb25nIEtvbmcxEjAQBgNVBAcT
-CUhvbmcgS29uZzEWMBQGA1UEChMNSG9uZ2tvbmcgUG9zdDEgMB4GA1UEAxMXSG9u
-Z2tvbmcgUG9zdCBSb290IENBIDMwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
-AoICAQCziNfqzg8gTr7m1gNt7ln8wlffKWihgw4+aMdoWJwcYEuJQwy51BWy7sFO
-dem1p+/l6TWZ5Mwc50tfjTMwIDNT2aa71T4Tjukfh0mtUC1Qyhi+AViiE3CWu4mI
-VoBc+L0sPOFMV4i707mV78vH9toxdCim5lSJ9UExyuUmGs2C4HDaOym71QP1mbpV
-9WTRYA6ziUm4ii8F0oRFKHyPaFASePwLtVPLwpgchKOesL4jpNrcyCse2m5FHomY
-2vkALgbpDDtw1VAliJnLzXNg99X/NWfFobxeq81KuEXryGgeDQ0URhLj0mRiikKY
-vLTGCAj4/ahMZJx2Ab0vqWwzD9g/KLg8aQFChn5pwckGyuV6RmXpwtZQQS4/t+Tt
-bNe/JgERohYpSms0BpDsE9K2+2p20jzt8NYt3eEV7KObLyzJPivkaTv/ciWxNoZb
-x39ri1UbSsUgYT2uy1DhCDq+sI9jQVMwCFk8mB13umOResoQUGC/8Ne8lYePl8X+
-l2oBlKN8W4UdKjk60FSh0Tlxnf0h+bV78OLgAo9uliQlLKAeLKjEiafv7ZkGL7YK
-TE/bosw3Gq9HhS2KX8Q0NEwA/RiTZxPRN+ZItIsGxVd7GYYKecsAyVKvQv83j+Gj
-Hno9UKtjBucVtT+2RTeUN7F+8kjDf8V1/peNRY8apxpyKBpADwIDAQABo2MwYTAP
-BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAfBgNVHSMEGDAWgBQXnc0e
-i9Y5K3DTXNSguB+wAPzFYTAdBgNVHQ4EFgQUF53NHovWOStw01zUoLgfsAD8xWEw
-DQYJKoZIhvcNAQELBQADggIBAFbVe27mIgHSQpsY1Q7XZiNc4/6gx5LS6ZStS6LG
-7BJ8dNVI0lkUmcDrudHr9EgwW62nV3OZqdPlt9EuWSRY3GguLmLYauRwCy0gUCCk
-MpXRAJi70/33MvJJrsZ64Ee+bs7Lo3I6LWldy8joRTnU+kLBEUx3XZL7av9YROXr
-gZ6voJmtvqkBZss4HTzfQx/0TW60uhdG/H39h4F5ag0zD/ov+BS5gLNdTaqX4fnk
-GMX41TiMJjz98iji7lpJiCzfeT2OnpA8vUFKOt1b9pq0zj8lMH8yfaIDlNDceqFS
-3m6TjRgm/VWsvY+b0s+v54Ysyx8Jb6NvqYTUc79NoXQbTiNg8swOqn+knEwlqLJm
-Ozj/2ZQw9nKEvmhVEA/GcywWaZMH/rFF7buiVWqw2rVKAiUnhde3t4ZEFolsgCs+
-l6mc1X5VTMbeRRAc6uk7nwNT7u56AQIWeNTowr5GdogTPyK7SBIdUgC0An4hGh6c
-JfTzPV4e0hz5sy229zdcxsshTrD3mUcYhcErulWuBurQB7Lcq9CClnXO0lD+mefP
-L5/ndtFhKvshuzHQqp9HpLIiyhY6UFfEW0NnxWViA0kB60PZ2Pierc+xYw5F9KBa
-LJstxabArahH9CdMOA0uG0k7UvToiIMrVCjU8jVStDKDYmlkDJGcn5fqdBb9HxEG
-mpv0
------END CERTIFICATE-----
-
-# Issuer: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only
-# Subject: CN=Entrust Root Certification Authority - G4 O=Entrust, Inc. OU=See www.entrust.net/legal-terms/(c) 2015 Entrust, Inc. - for authorized use only
-# Label: "Entrust Root Certification Authority - G4"
-# Serial: 289383649854506086828220374796556676440
-# MD5 Fingerprint: 89:53:f1:83:23:b7:7c:8e:05:f1:8c:71:38:4e:1f:88
-# SHA1 Fingerprint: 14:88:4e:86:26:37:b0:26:af:59:62:5c:40:77:ec:35:29:ba:96:01
-# SHA256 Fingerprint: db:35:17:d1:f6:73:2a:2d:5a:b9:7c:53:3e:c7:07:79:ee:32:70:a6:2f:b4:ac:42:38:37:24:60:e6:f0:1e:88
------BEGIN CERTIFICATE-----
-MIIGSzCCBDOgAwIBAgIRANm1Q3+vqTkPAAAAAFVlrVgwDQYJKoZIhvcNAQELBQAw
-gb4xCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQL
-Ex9TZWUgd3d3LmVudHJ1c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykg
-MjAxNSBFbnRydXN0LCBJbmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAw
-BgNVBAMTKUVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0
-MB4XDTE1MDUyNzExMTExNloXDTM3MTIyNzExNDExNlowgb4xCzAJBgNVBAYTAlVT
-MRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMSgwJgYDVQQLEx9TZWUgd3d3LmVudHJ1
-c3QubmV0L2xlZ2FsLXRlcm1zMTkwNwYDVQQLEzAoYykgMjAxNSBFbnRydXN0LCBJ
-bmMuIC0gZm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxMjAwBgNVBAMTKUVudHJ1c3Qg
-Um9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEc0MIICIjANBgkqhkiG9w0B
-AQEFAAOCAg8AMIICCgKCAgEAsewsQu7i0TD/pZJH4i3DumSXbcr3DbVZwbPLqGgZ
-2K+EbTBwXX7zLtJTmeH+H17ZSK9dE43b/2MzTdMAArzE+NEGCJR5WIoV3imz/f3E
-T+iq4qA7ec2/a0My3dl0ELn39GjUu9CH1apLiipvKgS1sqbHoHrmSKvS0VnM1n4j
-5pds8ELl3FFLFUHtSUrJ3hCX1nbB76W1NhSXNdh4IjVS70O92yfbYVaCNNzLiGAM
-C1rlLAHGVK/XqsEQe9IFWrhAnoanw5CGAlZSCXqc0ieCU0plUmr1POeo8pyvi73T
-DtTUXm6Hnmo9RR3RXRv06QqsYJn7ibT/mCzPfB3pAqoEmh643IhuJbNsZvc8kPNX
-wbMv9W3y+8qh+CmdRouzavbmZwe+LGcKKh9asj5XxNMhIWNlUpEbsZmOeX7m640A
-2Vqq6nPopIICR5b+W45UYaPrL0swsIsjdXJ8ITzI9vF01Bx7owVV7rtNOzK+mndm
-nqxpkCIHH2E6lr7lmk/MBTwoWdPBDFSoWWG9yHJM6Nyfh3+9nEg2XpWjDrk4JFX8
-dWbrAuMINClKxuMrLzOg2qOGpRKX/YAr2hRC45K9PvJdXmd0LhyIRyk0X+IyqJwl
-N4y6mACXi0mWHv0liqzc2thddG5msP9E36EYxr5ILzeUePiVSj9/E15dWf10hkNj
-c0kCAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFJ84xFYjwznooHFs6FRM5Og6sb9nMA0GCSqGSIb3DQEBCwUAA4ICAQAS
-5UKme4sPDORGpbZgQIeMJX6tuGguW8ZAdjwD+MlZ9POrYs4QjbRaZIxowLByQzTS
-Gwv2LFPSypBLhmb8qoMi9IsabyZIrHZ3CL/FmFz0Jomee8O5ZDIBf9PD3Vht7LGr
-hFV0d4QEJ1JrhkzO3bll/9bGXp+aEJlLdWr+aumXIOTkdnrG0CSqkM0gkLpHZPt/
-B7NTeLUKYvJzQ85BK4FqLoUWlFPUa19yIqtRLULVAJyZv967lDtX/Zr1hstWO1uI
-AeV8KEsD+UmDfLJ/fOPtjqF/YFOOVZ1QNBIPt5d7bIdKROf1beyAN/BYGW5KaHbw
-H5Lk6rWS02FREAutp9lfx1/cH6NcjKF+m7ee01ZvZl4HliDtC3T7Zk6LERXpgUl+
-b7DUUH8i119lAg2m9IUe2K4GS0qn0jFmwvjO5QimpAKWRGhXxNUzzxkvFMSUHHuk
-2fCfDrGA4tGeEWSpiBE6doLlYsKA2KSD7ZPvfC+QsDJMlhVoSFLUmQjAJOgc47Ol
-IQ6SwJAfzyBfyjs4x7dtOvPmRLgOMWuIjnDrnBdSqEGULoe256YSxXXfW8AKbnuk
-5F6G+TaU33fD6Q3AOfF5u0aOq0NZJ7cguyPpVkAh7DE9ZapD8j3fcEThuk0mEDuY
-n/PIjhs4ViFqUZPTkcpG2om3PVODLAgfi49T3f+sHw==
------END CERTIFICATE-----
-
-# Issuer: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation
-# Subject: CN=Microsoft ECC Root Certificate Authority 2017 O=Microsoft Corporation
-# Label: "Microsoft ECC Root Certificate Authority 2017"
-# Serial: 136839042543790627607696632466672567020
-# MD5 Fingerprint: dd:a1:03:e6:4a:93:10:d1:bf:f0:19:42:cb:fe:ed:67
-# SHA1 Fingerprint: 99:9a:64:c3:7f:f4:7d:9f:ab:95:f1:47:69:89:14:60:ee:c4:c3:c5
-# SHA256 Fingerprint: 35:8d:f3:9d:76:4a:f9:e1:b7:66:e9:c9:72:df:35:2e:e1:5c:fa:c2:27:af:6a:d1:d7:0e:8e:4a:6e:dc:ba:02
------BEGIN CERTIFICATE-----
-MIICWTCCAd+gAwIBAgIQZvI9r4fei7FK6gxXMQHC7DAKBggqhkjOPQQDAzBlMQsw
-CQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYD
-VQQDEy1NaWNyb3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIw
-MTcwHhcNMTkxMjE4MjMwNjQ1WhcNNDIwNzE4MjMxNjA0WjBlMQswCQYDVQQGEwJV
-UzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1NaWNy
-b3NvZnQgRUNDIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwdjAQBgcq
-hkjOPQIBBgUrgQQAIgNiAATUvD0CQnVBEyPNgASGAlEvaqiBYgtlzPbKnR5vSmZR
-ogPZnZH6thaxjG7efM3beaYvzrvOcS/lpaso7GMEZpn4+vKTEAXhgShC48Zo9OYb
-hGBKia/teQ87zvH2RPUBeMCjVDBSMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBTIy5lycFIM+Oa+sgRXKSrPQhDtNTAQBgkrBgEEAYI3
-FQEEAwIBADAKBggqhkjOPQQDAwNoADBlAjBY8k3qDPlfXu5gKcs68tvWMoQZP3zV
-L8KxzJOuULsJMsbG7X7JNpQS5GiFBqIb0C8CMQCZ6Ra0DvpWSNSkMBaReNtUjGUB
-iudQZsIxtzm6uBoiB078a1QWIP8rtedMDE2mT3M=
------END CERTIFICATE-----
-
-# Issuer: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation
-# Subject: CN=Microsoft RSA Root Certificate Authority 2017 O=Microsoft Corporation
-# Label: "Microsoft RSA Root Certificate Authority 2017"
-# Serial: 40975477897264996090493496164228220339
-# MD5 Fingerprint: 10:ff:00:ff:cf:c9:f8:c7:7a:c0:ee:35:8e:c9:0f:47
-# SHA1 Fingerprint: 73:a5:e6:4a:3b:ff:83:16:ff:0e:dc:cc:61:8a:90:6e:4e:ae:4d:74
-# SHA256 Fingerprint: c7:41:f7:0f:4b:2a:8d:88:bf:2e:71:c1:41:22:ef:53:ef:10:eb:a0:cf:a5:e6:4c:fa:20:f4:18:85:30:73:e0
------BEGIN CERTIFICATE-----
-MIIFqDCCA5CgAwIBAgIQHtOXCV/YtLNHcB6qvn9FszANBgkqhkiG9w0BAQwFADBl
-MQswCQYDVQQGEwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYw
-NAYDVQQDEy1NaWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5
-IDIwMTcwHhcNMTkxMjE4MjI1MTIyWhcNNDIwNzE4MjMwMDIzWjBlMQswCQYDVQQG
-EwJVUzEeMBwGA1UEChMVTWljcm9zb2Z0IENvcnBvcmF0aW9uMTYwNAYDVQQDEy1N
-aWNyb3NvZnQgUlNBIFJvb3QgQ2VydGlmaWNhdGUgQXV0aG9yaXR5IDIwMTcwggIi
-MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKW76UM4wplZEWCpW9R2LBifOZ
-Nt9GkMml7Xhqb0eRaPgnZ1AzHaGm++DlQ6OEAlcBXZxIQIJTELy/xztokLaCLeX0
-ZdDMbRnMlfl7rEqUrQ7eS0MdhweSE5CAg2Q1OQT85elss7YfUJQ4ZVBcF0a5toW1
-HLUX6NZFndiyJrDKxHBKrmCk3bPZ7Pw71VdyvD/IybLeS2v4I2wDwAW9lcfNcztm
-gGTjGqwu+UcF8ga2m3P1eDNbx6H7JyqhtJqRjJHTOoI+dkC0zVJhUXAoP8XFWvLJ
-jEm7FFtNyP9nTUwSlq31/niol4fX/V4ggNyhSyL71Imtus5Hl0dVe49FyGcohJUc
-aDDv70ngNXtk55iwlNpNhTs+VcQor1fznhPbRiefHqJeRIOkpcrVE7NLP8TjwuaG
-YaRSMLl6IE9vDzhTyzMMEyuP1pq9KsgtsRx9S1HKR9FIJ3Jdh+vVReZIZZ2vUpC6
-W6IYZVcSn2i51BVrlMRpIpj0M+Dt+VGOQVDJNE92kKz8OMHY4Xu54+OU4UZpyw4K
-UGsTuqwPN1q3ErWQgR5WrlcihtnJ0tHXUeOrO8ZV/R4O03QK0dqq6mm4lyiPSMQH
-+FJDOvTKVTUssKZqwJz58oHhEmrARdlns87/I6KJClTUFLkqqNfs+avNJVgyeY+Q
-W5g5xAgGwax/Dj0ApQIDAQABo1QwUjAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/
-BAUwAwEB/zAdBgNVHQ4EFgQUCctZf4aycI8awznjwNnpv7tNsiMwEAYJKwYBBAGC
-NxUBBAMCAQAwDQYJKoZIhvcNAQEMBQADggIBAKyvPl3CEZaJjqPnktaXFbgToqZC
-LgLNFgVZJ8og6Lq46BrsTaiXVq5lQ7GPAJtSzVXNUzltYkyLDVt8LkS/gxCP81OC
-gMNPOsduET/m4xaRhPtthH80dK2Jp86519efhGSSvpWhrQlTM93uCupKUY5vVau6
-tZRGrox/2KJQJWVggEbbMwSubLWYdFQl3JPk+ONVFT24bcMKpBLBaYVu32TxU5nh
-SnUgnZUP5NbcA/FZGOhHibJXWpS2qdgXKxdJ5XbLwVaZOjex/2kskZGT4d9Mozd2
-TaGf+G0eHdP67Pv0RR0Tbc/3WeUiJ3IrhvNXuzDtJE3cfVa7o7P4NHmJweDyAmH3
-pvwPuxwXC65B2Xy9J6P9LjrRk5Sxcx0ki69bIImtt2dmefU6xqaWM/5TkshGsRGR
-xpl/j8nWZjEgQRCHLQzWwa80mMpkg/sTV9HB8Dx6jKXB/ZUhoHHBk2dxEuqPiApp
-GWSZI1b7rCoucL5mxAyE7+WL85MB+GqQk2dLsmijtWKP6T+MejteD+eMuMZ87zf9
-dOLITzNy4ZQ5bb0Sr74MTnB8G2+NszKTc0QWbej09+CVgI+WXTik9KveCjCHk9hN
-AHFiRSdLOkKEW39lt2c0Ui2cFmuqqNh7o0JMcccMyj6D5KbvtwEwXlGjefVwaaZB
-RA+GsCyRxj3qrg+E
------END CERTIFICATE-----
-
-# Issuer: CN=e-Szigno Root CA 2017 O=Microsec Ltd.
-# Subject: CN=e-Szigno Root CA 2017 O=Microsec Ltd.
-# Label: "e-Szigno Root CA 2017"
-# Serial: 411379200276854331539784714
-# MD5 Fingerprint: de:1f:f6:9e:84:ae:a7:b4:21:ce:1e:58:7d:d1:84:98
-# SHA1 Fingerprint: 89:d4:83:03:4f:9e:9a:48:80:5f:72:37:d4:a9:a6:ef:cb:7c:1f:d1
-# SHA256 Fingerprint: be:b0:0b:30:83:9b:9b:c3:2c:32:e4:44:79:05:95:06:41:f2:64:21:b1:5e:d0:89:19:8b:51:8a:e2:ea:1b:99
------BEGIN CERTIFICATE-----
-MIICQDCCAeWgAwIBAgIMAVRI7yH9l1kN9QQKMAoGCCqGSM49BAMCMHExCzAJBgNV
-BAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMgTHRk
-LjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25vIFJv
-b3QgQ0EgMjAxNzAeFw0xNzA4MjIxMjA3MDZaFw00MjA4MjIxMjA3MDZaMHExCzAJ
-BgNVBAYTAkhVMREwDwYDVQQHDAhCdWRhcGVzdDEWMBQGA1UECgwNTWljcm9zZWMg
-THRkLjEXMBUGA1UEYQwOVkFUSFUtMjM1ODQ0OTcxHjAcBgNVBAMMFWUtU3ppZ25v
-IFJvb3QgQ0EgMjAxNzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJbcPYrYsHtv
-xie+RJCxs1YVe45DJH0ahFnuY2iyxl6H0BVIHqiQrb1TotreOpCmYF9oMrWGQd+H
-Wyx7xf58etqjYzBhMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0G
-A1UdDgQWBBSHERUI0arBeAyxr87GyZDvvzAEwDAfBgNVHSMEGDAWgBSHERUI0arB
-eAyxr87GyZDvvzAEwDAKBggqhkjOPQQDAgNJADBGAiEAtVfd14pVCzbhhkT61Nlo
-jbjcI4qKDdQvfepz7L9NbKgCIQDLpbQS+ue16M9+k/zzNY9vTlp8tLxOsvxyqltZ
-+efcMQ==
------END CERTIFICATE-----
-
-# Issuer: O=CERTSIGN SA OU=certSIGN ROOT CA G2
-# Subject: O=CERTSIGN SA OU=certSIGN ROOT CA G2
-# Label: "certSIGN Root CA G2"
-# Serial: 313609486401300475190
-# MD5 Fingerprint: 8c:f1:75:8a:c6:19:cf:94:b7:f7:65:20:87:c3:97:c7
-# SHA1 Fingerprint: 26:f9:93:b4:ed:3d:28:27:b0:b9:4b:a7:e9:15:1d:a3:8d:92:e5:32
-# SHA256 Fingerprint: 65:7c:fe:2f:a7:3f:aa:38:46:25:71:f3:32:a2:36:3a:46:fc:e7:02:09:51:71:07:02:cd:fb:b6:ee:da:33:05
------BEGIN CERTIFICATE-----
-MIIFRzCCAy+gAwIBAgIJEQA0tk7GNi02MA0GCSqGSIb3DQEBCwUAMEExCzAJBgNV
-BAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJR04g
-Uk9PVCBDQSBHMjAeFw0xNzAyMDYwOTI3MzVaFw00MjAyMDYwOTI3MzVaMEExCzAJ
-BgNVBAYTAlJPMRQwEgYDVQQKEwtDRVJUU0lHTiBTQTEcMBoGA1UECxMTY2VydFNJ
-R04gUk9PVCBDQSBHMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMDF
-dRmRfUR0dIf+DjuW3NgBFszuY5HnC2/OOwppGnzC46+CjobXXo9X69MhWf05N0Iw
-vlDqtg+piNguLWkh59E3GE59kdUWX2tbAMI5Qw02hVK5U2UPHULlj88F0+7cDBrZ
-uIt4ImfkabBoxTzkbFpG583H+u/E7Eu9aqSs/cwoUe+StCmrqzWaTOTECMYmzPhp
-n+Sc8CnTXPnGFiWeI8MgwT0PPzhAsP6CRDiqWhqKa2NYOLQV07YRaXseVO6MGiKs
-cpc/I1mbySKEwQdPzH/iV8oScLumZfNpdWO9lfsbl83kqK/20U6o2YpxJM02PbyW
-xPFsqa7lzw1uKA2wDrXKUXt4FMMgL3/7FFXhEZn91QqhngLjYl/rNUssuHLoPj1P
-rCy7Lobio3aP5ZMqz6WryFyNSwb/EkaseMsUBzXgqd+L6a8VTxaJW732jcZZroiF
-DsGJ6x9nxUWO/203Nit4ZoORUSs9/1F3dmKh7Gc+PoGD4FapUB8fepmrY7+EF3fx
-DTvf95xhszWYijqy7DwaNz9+j5LP2RIUZNoQAhVB/0/E6xyjyfqZ90bp4RjZsbgy
-LcsUDFDYg2WD7rlcz8sFWkz6GZdr1l0T08JcVLwyc6B49fFtHsufpaafItzRUZ6C
-eWRgKRM+o/1Pcmqr4tTluCRVLERLiohEnMqE0yo7AgMBAAGjQjBAMA8GA1UdEwEB
-/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSCIS1mxteg4BXrzkwJ
-d8RgnlRuAzANBgkqhkiG9w0BAQsFAAOCAgEAYN4auOfyYILVAzOBywaK8SJJ6ejq
-kX/GM15oGQOGO0MBzwdw5AgeZYWR5hEit/UCI46uuR59H35s5r0l1ZUa8gWmr4UC
-b6741jH/JclKyMeKqdmfS0mbEVeZkkMR3rYzpMzXjWR91M08KCy0mpbqTfXERMQl
-qiCA2ClV9+BB/AYm/7k29UMUA2Z44RGx2iBfRgB4ACGlHgAoYXhvqAEBj500mv/0
-OJD7uNGzcgbJceaBxXntC6Z58hMLnPddDnskk7RI24Zf3lCGeOdA5jGokHZwYa+c
-NywRtYK3qq4kNFtyDGkNzVmf9nGvnAvRCjj5BiKDUyUM/FHE5r7iOZULJK2v0ZXk
-ltd0ZGtxTgI8qoXzIKNDOXZbbFD+mpwUHmUUihW9o4JFWklWatKcsWMy5WHgUyIO
-pwpJ6st+H6jiYoD2EEVSmAYY3qXNL3+q1Ok+CHLsIwMCPKaq2LxndD0UF/tUSxfj
-03k9bWtJySgOLnRQvwzZRjoQhsmnP+mg7H/rpXdYaXHmgwo38oZJar55CJD2AhZk
-PuXaTH4MNMn5X7azKFGnpyuqSfqNZSlO42sTp5SjLVFteAxEy9/eCG/Oo2Sr05WE
-1LlSVHJ7liXMvGnjSG4N0MedJ5qq+BOS3R7fY581qRY27Iy4g/Q9iY/NtBde17MX
-QRBdJ3NghVdJIgc=
------END CERTIFICATE-----
-
-# Issuer: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc.
-# Subject: CN=Trustwave Global Certification Authority O=Trustwave Holdings, Inc.
-# Label: "Trustwave Global Certification Authority"
-# Serial: 1846098327275375458322922162
-# MD5 Fingerprint: f8:1c:18:2d:2f:ba:5f:6d:a1:6c:bc:c7:ab:91:c7:0e
-# SHA1 Fingerprint: 2f:8f:36:4f:e1:58:97:44:21:59:87:a5:2a:9a:d0:69:95:26:7f:b5
-# SHA256 Fingerprint: 97:55:20:15:f5:dd:fc:3c:87:88:c0:06:94:45:55:40:88:94:45:00:84:f1:00:86:70:86:bc:1a:2b:b5:8d:c8
------BEGIN CERTIFICATE-----
-MIIF2jCCA8KgAwIBAgIMBfcOhtpJ80Y1LrqyMA0GCSqGSIb3DQEBCwUAMIGIMQsw
-CQYDVQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28x
-ITAfBgNVBAoMGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1
-c3R3YXZlIEdsb2JhbCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0xNzA4MjMx
-OTM0MTJaFw00MjA4MjMxOTM0MTJaMIGIMQswCQYDVQQGEwJVUzERMA8GA1UECAwI
-SWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xITAfBgNVBAoMGFRydXN0d2F2ZSBI
-b2xkaW5ncywgSW5jLjExMC8GA1UEAwwoVHJ1c3R3YXZlIEdsb2JhbCBDZXJ0aWZp
-Y2F0aW9uIEF1dGhvcml0eTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
-ALldUShLPDeS0YLOvR29zd24q88KPuFd5dyqCblXAj7mY2Hf8g+CY66j96xz0Xzn
-swuvCAAJWX/NKSqIk4cXGIDtiLK0thAfLdZfVaITXdHG6wZWiYj+rDKd/VzDBcdu
-7oaJuogDnXIhhpCujwOl3J+IKMujkkkP7NAP4m1ET4BqstTnoApTAbqOl5F2brz8
-1Ws25kCI1nsvXwXoLG0R8+eyvpJETNKXpP7ScoFDB5zpET71ixpZfR9oWN0EACyW
-80OzfpgZdNmcc9kYvkHHNHnZ9GLCQ7mzJ7Aiy/k9UscwR7PJPrhq4ufogXBeQotP
-JqX+OsIgbrv4Fo7NDKm0G2x2EOFYeUY+VM6AqFcJNykbmROPDMjWLBz7BegIlT1l
-RtzuzWniTY+HKE40Cz7PFNm73bZQmq131BnW2hqIyE4bJ3XYsgjxroMwuREOzYfw
-hI0Vcnyh78zyiGG69Gm7DIwLdVcEuE4qFC49DxweMqZiNu5m4iK4BUBjECLzMx10
-coos9TkpoNPnG4CELcU9402x/RpvumUHO1jsQkUm+9jaJXLE9gCxInm943xZYkqc
-BW89zubWR2OZxiRvchLIrH+QtAuRcOi35hYQcRfO3gZPSEF9NUqjifLJS3tBEW1n
-twiYTOURGa5CgNz7kAXU+FDKvuStx8KU1xad5hePrzb7AgMBAAGjQjBAMA8GA1Ud
-EwEB/wQFMAMBAf8wHQYDVR0OBBYEFJngGWcNYtt2s9o9uFvo/ULSMQ6HMA4GA1Ud
-DwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAmHNw4rDT7TnsTGDZqRKGFx6W
-0OhUKDtkLSGm+J1WE2pIPU/HPinbbViDVD2HfSMF1OQc3Og4ZYbFdada2zUFvXfe
-uyk3QAUHw5RSn8pk3fEbK9xGChACMf1KaA0HZJDmHvUqoai7PF35owgLEQzxPy0Q
-lG/+4jSHg9bP5Rs1bdID4bANqKCqRieCNqcVtgimQlRXtpla4gt5kNdXElE1GYhB
-aCXUNxeEFfsBctyV3lImIJgm4nb1J2/6ADtKYdkNy1GTKv0WBpanI5ojSP5RvbbE
-sLFUzt5sQa0WZ37b/TjNuThOssFgy50X31ieemKyJo90lZvkWx3SD92YHJtZuSPT
-MaCm/zjdzyBP6VhWOmfD0faZmZ26NraAL4hHT4a/RDqA5Dccprrql5gR0IRiR2Qe
-qu5AvzSxnI9O4fKSTx+O856X3vOmeWqJcU9LJxdI/uz0UA9PSX3MReO9ekDFQdxh
-VicGaeVyQYHTtgGJoC86cnn+OjC/QezHYj6RS8fZMXZC+fc8Y+wmjHMMfRod6qh8
-h6jCJ3zhM0EPz8/8AKAigJ5Kp28AsEFFtyLKaEjFQqKu3R3y4G5OBVixwJAWKqQ9
-EEC+j2Jjg6mcgn0tAumDMHzLJ8n9HmYAsC7TIS+OMxZsmO0QqAfWzJPP29FpHOTK
-yeC2nOnOcXHebD8WpHk=
------END CERTIFICATE-----
-
-# Issuer: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc.
-# Subject: CN=Trustwave Global ECC P256 Certification Authority O=Trustwave Holdings, Inc.
-# Label: "Trustwave Global ECC P256 Certification Authority"
-# Serial: 4151900041497450638097112925
-# MD5 Fingerprint: 5b:44:e3:8d:5d:36:86:26:e8:0d:05:d2:59:a7:83:54
-# SHA1 Fingerprint: b4:90:82:dd:45:0c:be:8b:5b:b1:66:d3:e2:a4:08:26:cd:ed:42:cf
-# SHA256 Fingerprint: 94:5b:bc:82:5e:a5:54:f4:89:d1:fd:51:a7:3d:df:2e:a6:24:ac:70:19:a0:52:05:22:5c:22:a7:8c:cf:a8:b4
------BEGIN CERTIFICATE-----
-MIICYDCCAgegAwIBAgIMDWpfCD8oXD5Rld9dMAoGCCqGSM49BAMCMIGRMQswCQYD
-VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
-BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
-YXZlIEdsb2JhbCBFQ0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
-NzA4MjMxOTM1MTBaFw00MjA4MjMxOTM1MTBaMIGRMQswCQYDVQQGEwJVUzERMA8G
-A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
-d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
-Q0MgUDI1NiBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTBZMBMGByqGSM49AgEGCCqG
-SM49AwEHA0IABH77bOYj43MyCMpg5lOcunSNGLB4kFKA3TjASh3RqMyTpJcGOMoN
-FWLGjgEqZZ2q3zSRLoHB5DOSMcT9CTqmP62jQzBBMA8GA1UdEwEB/wQFMAMBAf8w
-DwYDVR0PAQH/BAUDAwcGADAdBgNVHQ4EFgQUo0EGrJBt0UrrdaVKEJmzsaGLSvcw
-CgYIKoZIzj0EAwIDRwAwRAIgB+ZU2g6gWrKuEZ+Hxbb/ad4lvvigtwjzRM4q3wgh
-DDcCIC0mA6AFvWvR9lz4ZcyGbbOcNEhjhAnFjXca4syc4XR7
------END CERTIFICATE-----
-
-# Issuer: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc.
-# Subject: CN=Trustwave Global ECC P384 Certification Authority O=Trustwave Holdings, Inc.
-# Label: "Trustwave Global ECC P384 Certification Authority"
-# Serial: 2704997926503831671788816187
-# MD5 Fingerprint: ea:cf:60:c4:3b:b9:15:29:40:a1:97:ed:78:27:93:d6
-# SHA1 Fingerprint: e7:f3:a3:c8:cf:6f:c3:04:2e:6d:0e:67:32:c5:9e:68:95:0d:5e:d2
-# SHA256 Fingerprint: 55:90:38:59:c8:c0:c3:eb:b8:75:9e:ce:4e:25:57:22:5f:f5:75:8b:bd:38:eb:d4:82:76:60:1e:1b:d5:80:97
------BEGIN CERTIFICATE-----
-MIICnTCCAiSgAwIBAgIMCL2Fl2yZJ6SAaEc7MAoGCCqGSM49BAMDMIGRMQswCQYD
-VQQGEwJVUzERMA8GA1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAf
-BgNVBAoTGFRydXN0d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3
-YXZlIEdsb2JhbCBFQ0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0x
-NzA4MjMxOTM2NDNaFw00MjA4MjMxOTM2NDNaMIGRMQswCQYDVQQGEwJVUzERMA8G
-A1UECBMISWxsaW5vaXMxEDAOBgNVBAcTB0NoaWNhZ28xITAfBgNVBAoTGFRydXN0
-d2F2ZSBIb2xkaW5ncywgSW5jLjE6MDgGA1UEAxMxVHJ1c3R3YXZlIEdsb2JhbCBF
-Q0MgUDM4NCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTB2MBAGByqGSM49AgEGBSuB
-BAAiA2IABGvaDXU1CDFHBa5FmVXxERMuSvgQMSOjfoPTfygIOiYaOs+Xgh+AtycJ
-j9GOMMQKmw6sWASr9zZ9lCOkmwqKi6vr/TklZvFe/oyujUF5nQlgziip04pt89ZF
-1PKYhDhloKNDMEEwDwYDVR0TAQH/BAUwAwEB/zAPBgNVHQ8BAf8EBQMDBwYAMB0G
-A1UdDgQWBBRVqYSJ0sEyvRjLbKYHTsjnnb6CkDAKBggqhkjOPQQDAwNnADBkAjA3
-AZKXRRJ+oPM+rRk6ct30UJMDEr5E0k9BpIycnR+j9sKS50gU/k6bpZFXrsY3crsC
-MGclCrEMXu6pY5Jv5ZAL/mYiykf9ijH3g/56vxC+GCsej/YpHpRZ744hN8tRmKVu
-Sw==
------END CERTIFICATE-----
-
-# Issuer: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp.
-# Subject: CN=NAVER Global Root Certification Authority O=NAVER BUSINESS PLATFORM Corp.
-# Label: "NAVER Global Root Certification Authority"
-# Serial: 9013692873798656336226253319739695165984492813
-# MD5 Fingerprint: c8:7e:41:f6:25:3b:f5:09:b3:17:e8:46:3d:bf:d0:9b
-# SHA1 Fingerprint: 8f:6b:f2:a9:27:4a:da:14:a0:c4:f4:8e:61:27:f9:c0:1e:78:5d:d1
-# SHA256 Fingerprint: 88:f4:38:dc:f8:ff:d1:fa:8f:42:91:15:ff:e5:f8:2a:e1:e0:6e:0c:70:c3:75:fa:ad:71:7b:34:a4:9e:72:65
------BEGIN CERTIFICATE-----
-MIIFojCCA4qgAwIBAgIUAZQwHqIL3fXFMyqxQ0Rx+NZQTQ0wDQYJKoZIhvcNAQEM
-BQAwaTELMAkGA1UEBhMCS1IxJjAkBgNVBAoMHU5BVkVSIEJVU0lORVNTIFBMQVRG
-T1JNIENvcnAuMTIwMAYDVQQDDClOQVZFUiBHbG9iYWwgUm9vdCBDZXJ0aWZpY2F0
-aW9uIEF1dGhvcml0eTAeFw0xNzA4MTgwODU4NDJaFw0zNzA4MTgyMzU5NTlaMGkx
-CzAJBgNVBAYTAktSMSYwJAYDVQQKDB1OQVZFUiBCVVNJTkVTUyBQTEFURk9STSBD
-b3JwLjEyMDAGA1UEAwwpTkFWRVIgR2xvYmFsIFJvb3QgQ2VydGlmaWNhdGlvbiBB
-dXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC21PGTXLVA
-iQqrDZBbUGOukJR0F0Vy1ntlWilLp1agS7gvQnXp2XskWjFlqxcX0TM62RHcQDaH
-38dq6SZeWYp34+hInDEW+j6RscrJo+KfziFTowI2MMtSAuXaMl3Dxeb57hHHi8lE
-HoSTGEq0n+USZGnQJoViAbbJAh2+g1G7XNr4rRVqmfeSVPc0W+m/6imBEtRTkZaz
-kVrd/pBzKPswRrXKCAfHcXLJZtM0l/aM9BhK4dA9WkW2aacp+yPOiNgSnABIqKYP
-szuSjXEOdMWLyEz59JuOuDxp7W87UC9Y7cSw0BwbagzivESq2M0UXZR4Yb8Obtoq
-vC8MC3GmsxY/nOb5zJ9TNeIDoKAYv7vxvvTWjIcNQvcGufFt7QSUqP620wbGQGHf
-nZ3zVHbOUzoBppJB7ASjjw2i1QnK1sua8e9DXcCrpUHPXFNwcMmIpi3Ua2FzUCaG
-YQ5fG8Ir4ozVu53BA0K6lNpfqbDKzE0K70dpAy8i+/Eozr9dUGWokG2zdLAIx6yo
-0es+nPxdGoMuK8u180SdOqcXYZaicdNwlhVNt0xz7hlcxVs+Qf6sdWA7G2POAN3a
-CJBitOUt7kinaxeZVL6HSuOpXgRM6xBtVNbv8ejyYhbLgGvtPe31HzClrkvJE+2K
-AQHJuFFYwGY6sWZLxNUxAmLpdIQM201GLQIDAQABo0IwQDAdBgNVHQ4EFgQU0p+I
-36HNLL3s9TsBAZMzJ7LrYEswDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMB
-Af8wDQYJKoZIhvcNAQEMBQADggIBADLKgLOdPVQG3dLSLvCkASELZ0jKbY7gyKoN
-qo0hV4/GPnrK21HUUrPUloSlWGB/5QuOH/XcChWB5Tu2tyIvCZwTFrFsDDUIbatj
-cu3cvuzHV+YwIHHW1xDBE1UBjCpD5EHxzzp6U5LOogMFDTjfArsQLtk70pt6wKGm
-+LUx5vR1yblTmXVHIloUFcd4G7ad6Qz4G3bxhYTeodoS76TiEJd6eN4MUZeoIUCL
-hr0N8F5OSza7OyAfikJW4Qsav3vQIkMsRIz75Sq0bBwcupTgE34h5prCy8VCZLQe
-lHsIJchxzIdFV4XTnyliIoNRlwAYl3dqmJLJfGBs32x9SuRwTMKeuB330DTHD8z7
-p/8Dvq1wkNoL3chtl1+afwkyQf3NosxabUzyqkn+Zvjp2DXrDige7kgvOtB5CTh8
-piKCk5XQA76+AqAF3SAi428diDRgxuYKuQl1C/AH6GmWNcf7I4GOODm4RStDeKLR
-LBT/DShycpWbXgnbiUSYqqFJu3FS8r/2/yehNq+4tneI3TqkbZs0kNwUXTC/t+sX
-5Ie3cdCh13cV1ELX8vMxmV2b3RZtP+oGI/hGoiLtk/bdmuYqh7GYVPEi92tF4+KO
-dh2ajcQGjTa3FPOdVGm3jjzVpG2Tgbet9r1ke8LJaDmgkpzNNIaRkPpkUZ3+/uul
-9XXeifdy
------END CERTIFICATE-----
-
-# Issuer: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres
-# Subject: CN=AC RAIZ FNMT-RCM SERVIDORES SEGUROS O=FNMT-RCM OU=Ceres
-# Label: "AC RAIZ FNMT-RCM SERVIDORES SEGUROS"
-# Serial: 131542671362353147877283741781055151509
-# MD5 Fingerprint: 19:36:9c:52:03:2f:d2:d1:bb:23:cc:dd:1e:12:55:bb
-# SHA1 Fingerprint: 62:ff:d9:9e:c0:65:0d:03:ce:75:93:d2:ed:3f:2d:32:c9:e3:e5:4a
-# SHA256 Fingerprint: 55:41:53:b1:3d:2c:f9:dd:b7:53:bf:be:1a:4e:0a:e0:8d:0a:a4:18:70:58:fe:60:a2:b8:62:b2:e4:b8:7b:cb
------BEGIN CERTIFICATE-----
-MIICbjCCAfOgAwIBAgIQYvYybOXE42hcG2LdnC6dlTAKBggqhkjOPQQDAzB4MQsw
-CQYDVQQGEwJFUzERMA8GA1UECgwIRk5NVC1SQ00xDjAMBgNVBAsMBUNlcmVzMRgw
-FgYDVQRhDA9WQVRFUy1RMjgyNjAwNEoxLDAqBgNVBAMMI0FDIFJBSVogRk5NVC1S
-Q00gU0VSVklET1JFUyBTRUdVUk9TMB4XDTE4MTIyMDA5MzczM1oXDTQzMTIyMDA5
-MzczM1oweDELMAkGA1UEBhMCRVMxETAPBgNVBAoMCEZOTVQtUkNNMQ4wDAYDVQQL
-DAVDZXJlczEYMBYGA1UEYQwPVkFURVMtUTI4MjYwMDRKMSwwKgYDVQQDDCNBQyBS
-QUlaIEZOTVQtUkNNIFNFUlZJRE9SRVMgU0VHVVJPUzB2MBAGByqGSM49AgEGBSuB
-BAAiA2IABPa6V1PIyqvfNkpSIeSX0oNnnvBlUdBeh8dHsVnyV0ebAAKTRBdp20LH
-sbI6GA60XYyzZl2hNPk2LEnb80b8s0RpRBNm/dfF/a82Tc4DTQdxz69qBdKiQ1oK
-Um8BA06Oi6NCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
-VR0OBBYEFAG5L++/EYZg8k/QQW6rcx/n0m5JMAoGCCqGSM49BAMDA2kAMGYCMQCu
-SuMrQMN0EfKVrRYj3k4MGuZdpSRea0R7/DjiT8ucRRcRTBQnJlU5dUoDzBOQn5IC
-MQD6SmxgiHPz7riYYqnOK8LZiqZwMR2vsJRM60/G49HzYqc8/5MuB1xJAWdpEgJy
-v+c=
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign Root R46 O=GlobalSign nv-sa
-# Subject: CN=GlobalSign Root R46 O=GlobalSign nv-sa
-# Label: "GlobalSign Root R46"
-# Serial: 1552617688466950547958867513931858518042577
-# MD5 Fingerprint: c4:14:30:e4:fa:66:43:94:2a:6a:1b:24:5f:19:d0:ef
-# SHA1 Fingerprint: 53:a2:b0:4b:ca:6b:d6:45:e6:39:8a:8e:c4:0d:d2:bf:77:c3:a2:90
-# SHA256 Fingerprint: 4f:a3:12:6d:8d:3a:11:d1:c4:85:5a:4f:80:7c:ba:d6:cf:91:9d:3a:5a:88:b0:3b:ea:2c:63:72:d9:3c:40:c9
------BEGIN CERTIFICATE-----
-MIIFWjCCA0KgAwIBAgISEdK7udcjGJ5AXwqdLdDfJWfRMA0GCSqGSIb3DQEBDAUA
-MEYxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYD
-VQQDExNHbG9iYWxTaWduIFJvb3QgUjQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMy
-MDAwMDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYt
-c2ExHDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCsrHQy6LNl5brtQyYdpokNRbopiLKkHWPd08EsCVeJ
-OaFV6Wc0dwxu5FUdUiXSE2te4R2pt32JMl8Nnp8semNgQB+msLZ4j5lUlghYruQG
-vGIFAha/r6gjA7aUD7xubMLL1aa7DOn2wQL7Id5m3RerdELv8HQvJfTqa1VbkNud
-316HCkD7rRlr+/fKYIje2sGP1q7Vf9Q8g+7XFkyDRTNrJ9CG0Bwta/OrffGFqfUo
-0q3v84RLHIf8E6M6cqJaESvWJ3En7YEtbWaBkoe0G1h6zD8K+kZPTXhc+CtI4wSE
-y132tGqzZfxCnlEmIyDLPRT5ge1lFgBPGmSXZgjPjHvjK8Cd+RTyG/FWaha/LIWF
-zXg4mutCagI0GIMXTpRW+LaCtfOW3T3zvn8gdz57GSNrLNRyc0NXfeD412lPFzYE
-+cCQYDdF3uYM2HSNrpyibXRdQr4G9dlkbgIQrImwTDsHTUB+JMWKmIJ5jqSngiCN
-I/onccnfxkF0oE32kRbcRoxfKWMxWXEM2G/CtjJ9++ZdU6Z+Ffy7dXxd7Pj2Fxzs
-x2sZy/N78CsHpdlseVR2bJ0cpm4O6XkMqCNqo98bMDGfsVR7/mrLZqrcZdCinkqa
-ByFrgY/bxFn63iLABJzjqls2k+g9vXqhnQt2sQvHnf3PmKgGwvgqo6GDoLclcqUC
-4wIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQUA1yrc4GHqMywptWU4jaWSf8FmSwwDQYJKoZIhvcNAQEMBQADggIBAHx4
-7PYCLLtbfpIrXTncvtgdokIzTfnvpCo7RGkerNlFo048p9gkUbJUHJNOxO97k4Vg
-JuoJSOD1u8fpaNK7ajFxzHmuEajwmf3lH7wvqMxX63bEIaZHU1VNaL8FpO7XJqti
-2kM3S+LGteWygxk6x9PbTZ4IevPuzz5i+6zoYMzRx6Fcg0XERczzF2sUyQQCPtIk
-pnnpHs6i58FZFZ8d4kuaPp92CC1r2LpXFNqD6v6MVenQTqnMdzGxRBF6XLE+0xRF
-FRhiJBPSy03OXIPBNvIQtQ6IbbjhVp+J3pZmOUdkLG5NrmJ7v2B0GbhWrJKsFjLt
-rWhV/pi60zTe9Mlhww6G9kuEYO4Ne7UyWHmRVSyBQ7N0H3qqJZ4d16GLuc1CLgSk
-ZoNNiTW2bKg2SnkheCLQQrzRQDGQob4Ez8pn7fXwgNNgyYMqIgXQBztSvwyeqiv5
-u+YfjyW6hY0XHgL+XVAEV8/+LbzvXMAaq7afJMbfc2hIkCwU9D9SGuTSyxTDYWnP
-4vkYxboznxSjBF25cfe1lNj2M8FawTSLfJvdkzrnE6JwYZ+vj+vYxXX4M2bUdGc6
-N3ec592kD3ZDZopD8p/7DEJ4Y9HiD2971KE9dJeFt0g5QdYg/NA6s/rob8SKunE3
-vouXsXgxT7PntgMTzlSdriVZzH81Xwj3QEUxeCp6
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign Root E46 O=GlobalSign nv-sa
-# Subject: CN=GlobalSign Root E46 O=GlobalSign nv-sa
-# Label: "GlobalSign Root E46"
-# Serial: 1552617690338932563915843282459653771421763
-# MD5 Fingerprint: b5:b8:66:ed:de:08:83:e3:c9:e2:01:34:06:ac:51:6f
-# SHA1 Fingerprint: 39:b4:6c:d5:fe:80:06:eb:e2:2f:4a:bb:08:33:a0:af:db:b9:dd:84
-# SHA256 Fingerprint: cb:b9:c4:4d:84:b8:04:3e:10:50:ea:31:a6:9f:51:49:55:d7:bf:d2:e2:c6:b4:93:01:01:9a:d6:1d:9f:50:58
------BEGIN CERTIFICATE-----
-MIICCzCCAZGgAwIBAgISEdK7ujNu1LzmJGjFDYQdmOhDMAoGCCqGSM49BAMDMEYx
-CzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9iYWxTaWduIG52LXNhMRwwGgYDVQQD
-ExNHbG9iYWxTaWduIFJvb3QgRTQ2MB4XDTE5MDMyMDAwMDAwMFoXDTQ2MDMyMDAw
-MDAwMFowRjELMAkGA1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2Ex
-HDAaBgNVBAMTE0dsb2JhbFNpZ24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAAScDrHPt+ieUnd1NPqlRqetMhkytAepJ8qUuwzSChDH2omwlwxwEwkBjtjq
-R+q+soArzfwoDdusvKSGN+1wCAB16pMLey5SnCNoIwZD7JIvU4Tb+0cUB+hflGdd
-yXqBPCCjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
-DgQWBBQxCpCPtsad0kRLgLWi5h+xEk8blTAKBggqhkjOPQQDAwNoADBlAjEA31SQ
-7Zvvi5QCkxeCmb6zniz2C5GMn0oUsfZkvLtoURMMA/cVi4RguYv/Uo7njLwcAjA8
-+RHUjE7AwWHCFUyqqx0LMV87HOIAl0Qx5v5zli/altP+CAezNIm8BZ/3Hobui3A=
------END CERTIFICATE-----
-
-# Issuer: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
-# Subject: CN=ANF Secure Server Root CA O=ANF Autoridad de Certificacion OU=ANF CA Raiz
-# Label: "ANF Secure Server Root CA"
-# Serial: 996390341000653745
-# MD5 Fingerprint: 26:a6:44:5a:d9:af:4e:2f:b2:1d:b6:65:b0:4e:e8:96
-# SHA1 Fingerprint: 5b:6e:68:d0:cc:15:b6:a0:5f:1e:c1:5f:ae:02:fc:6b:2f:5d:6f:74
-# SHA256 Fingerprint: fb:8f:ec:75:91:69:b9:10:6b:1e:51:16:44:c6:18:c5:13:04:37:3f:6c:06:43:08:8d:8b:ef:fd:1b:99:75:99
------BEGIN CERTIFICATE-----
-MIIF7zCCA9egAwIBAgIIDdPjvGz5a7EwDQYJKoZIhvcNAQELBQAwgYQxEjAQBgNV
-BAUTCUc2MzI4NzUxMDELMAkGA1UEBhMCRVMxJzAlBgNVBAoTHkFORiBBdXRvcmlk
-YWQgZGUgQ2VydGlmaWNhY2lvbjEUMBIGA1UECxMLQU5GIENBIFJhaXoxIjAgBgNV
-BAMTGUFORiBTZWN1cmUgU2VydmVyIFJvb3QgQ0EwHhcNMTkwOTA0MTAwMDM4WhcN
-MzkwODMwMTAwMDM4WjCBhDESMBAGA1UEBRMJRzYzMjg3NTEwMQswCQYDVQQGEwJF
-UzEnMCUGA1UEChMeQU5GIEF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uMRQwEgYD
-VQQLEwtBTkYgQ0EgUmFpejEiMCAGA1UEAxMZQU5GIFNlY3VyZSBTZXJ2ZXIgUm9v
-dCBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANvrayvmZFSVgpCj
-cqQZAZ2cC4Ffc0m6p6zzBE57lgvsEeBbphzOG9INgxwruJ4dfkUyYA8H6XdYfp9q
-yGFOtibBTI3/TO80sh9l2Ll49a2pcbnvT1gdpd50IJeh7WhM3pIXS7yr/2WanvtH
-2Vdy8wmhrnZEE26cLUQ5vPnHO6RYPUG9tMJJo8gN0pcvB2VSAKduyK9o7PQUlrZX
-H1bDOZ8rbeTzPvY1ZNoMHKGESy9LS+IsJJ1tk0DrtSOOMspvRdOoiXsezx76W0OL
-zc2oD2rKDF65nkeP8Nm2CgtYZRczuSPkdxl9y0oukntPLxB3sY0vaJxizOBQ+OyR
-p1RMVwnVdmPF6GUe7m1qzwmd+nxPrWAI/VaZDxUse6mAq4xhj0oHdkLePfTdsiQz
-W7i1o0TJrH93PB0j7IKppuLIBkwC/qxcmZkLLxCKpvR/1Yd0DVlJRfbwcVw5Kda/
-SiOL9V8BY9KHcyi1Swr1+KuCLH5zJTIdC2MKF4EA/7Z2Xue0sUDKIbvVgFHlSFJn
-LNJhiQcND85Cd8BEc5xEUKDbEAotlRyBr+Qc5RQe8TZBAQIvfXOn3kLMTOmJDVb3
-n5HUA8ZsyY/b2BzgQJhdZpmYgG4t/wHFzstGH6wCxkPmrqKEPMVOHj1tyRRM4y5B
-u8o5vzY8KhmqQYdOpc5LMnndkEl/AgMBAAGjYzBhMB8GA1UdIwQYMBaAFJxf0Gxj
-o1+TypOYCK2Mh6UsXME3MB0GA1UdDgQWBBScX9BsY6Nfk8qTmAitjIelLFzBNzAO
-BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC
-AgEATh65isagmD9uw2nAalxJUqzLK114OMHVVISfk/CHGT0sZonrDUL8zPB1hT+L
-9IBdeeUXZ701guLyPI59WzbLWoAAKfLOKyzxj6ptBZNscsdW699QIyjlRRA96Gej
-rw5VD5AJYu9LWaL2U/HANeQvwSS9eS9OICI7/RogsKQOLHDtdD+4E5UGUcjohybK
-pFtqFiGS3XNgnhAY3jyB6ugYw3yJ8otQPr0R4hUDqDZ9MwFsSBXXiJCZBMXM5gf0
-vPSQ7RPi6ovDj6MzD8EpTBNO2hVWcXNyglD2mjN8orGoGjR0ZVzO0eurU+AagNjq
-OknkJjCb5RyKqKkVMoaZkgoQI1YS4PbOTOK7vtuNknMBZi9iPrJyJ0U27U1W45eZ
-/zo1PqVUSlJZS2Db7v54EX9K3BR5YLZrZAPbFYPhor72I5dQ8AkzNqdxliXzuUJ9
-2zg/LFis6ELhDtjTO0wugumDLmsx2d1Hhk9tl5EuT+IocTUW0fJz/iUrB0ckYyfI
-+PbZa/wSMVYIwFNCr5zQM378BvAxRAMU8Vjq8moNqRGyg77FGr8H6lnco4g175x2
-MjxNBiLOFeXdntiP2t7SxDnlF4HPOEfrf4htWRvfn0IUrn7PqLBmZdo3r5+qPeoo
-tt7VMVgWglvquxl1AnMaykgaIZOQCo6ThKd9OyMYkomgjaw=
------END CERTIFICATE-----
-
-# Issuer: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
-# Subject: CN=Certum EC-384 CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
-# Label: "Certum EC-384 CA"
-# Serial: 160250656287871593594747141429395092468
-# MD5 Fingerprint: b6:65:b3:96:60:97:12:a1:ec:4e:e1:3d:a3:c6:c9:f1
-# SHA1 Fingerprint: f3:3e:78:3c:ac:df:f4:a2:cc:ac:67:55:69:56:d7:e5:16:3c:e1:ed
-# SHA256 Fingerprint: 6b:32:80:85:62:53:18:aa:50:d1:73:c9:8d:8b:da:09:d5:7e:27:41:3d:11:4c:f7:87:a0:f5:d0:6c:03:0c:f6
------BEGIN CERTIFICATE-----
-MIICZTCCAeugAwIBAgIQeI8nXIESUiClBNAt3bpz9DAKBggqhkjOPQQDAzB0MQsw
-CQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEuMScw
-JQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAXBgNVBAMT
-EENlcnR1bSBFQy0zODQgQ0EwHhcNMTgwMzI2MDcyNDU0WhcNNDMwMzI2MDcyNDU0
-WjB0MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBT
-LkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxGTAX
-BgNVBAMTEENlcnR1bSBFQy0zODQgQ0EwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATE
-KI6rGFtqvm5kN2PkzeyrOvfMobgOgknXhimfoZTy42B4mIF4Bk3y7JoOV2CDn7Tm
-Fy8as10CW4kjPMIRBSqniBMY81CE1700LCeJVf/OTOffph8oxPBUw7l8t1Ot68Kj
-QjBAMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFI0GZnQkdjrzife81r1HfS+8
-EF9LMA4GA1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNoADBlAjADVS2m5hjEfO/J
-UG7BJw+ch69u1RsIGL2SKcHvlJF40jocVYli5RsJHrpka/F2tNQCMQC0QoSZ/6vn
-nvuRlydd3LBbMHHOXjgaatkl5+r3YZJW+OraNsKHZZYuciUvf9/DE8k=
------END CERTIFICATE-----
-
-# Issuer: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
-# Subject: CN=Certum Trusted Root CA O=Asseco Data Systems S.A. OU=Certum Certification Authority
-# Label: "Certum Trusted Root CA"
-# Serial: 40870380103424195783807378461123655149
-# MD5 Fingerprint: 51:e1:c2:e7:fe:4c:84:af:59:0e:2f:f4:54:6f:ea:29
-# SHA1 Fingerprint: c8:83:44:c0:18:ae:9f:cc:f1:87:b7:8f:22:d1:c5:d7:45:84:ba:e5
-# SHA256 Fingerprint: fe:76:96:57:38:55:77:3e:37:a9:5e:7a:d4:d9:cc:96:c3:01:57:c1:5d:31:76:5b:a9:b1:57:04:e1:ae:78:fd
------BEGIN CERTIFICATE-----
-MIIFwDCCA6igAwIBAgIQHr9ZULjJgDdMBvfrVU+17TANBgkqhkiG9w0BAQ0FADB6
-MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEgU3lzdGVtcyBTLkEu
-MScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxHzAdBgNV
-BAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwHhcNMTgwMzE2MTIxMDEzWhcNNDMw
-MzE2MTIxMDEzWjB6MQswCQYDVQQGEwJQTDEhMB8GA1UEChMYQXNzZWNvIERhdGEg
-U3lzdGVtcyBTLkEuMScwJQYDVQQLEx5DZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRo
-b3JpdHkxHzAdBgNVBAMTFkNlcnR1bSBUcnVzdGVkIFJvb3QgQ0EwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQDRLY67tzbqbTeRn06TpwXkKQMlzhyC93yZ
-n0EGze2jusDbCSzBfN8pfktlL5On1AFrAygYo9idBcEq2EXxkd7fO9CAAozPOA/q
-p1x4EaTByIVcJdPTsuclzxFUl6s1wB52HO8AU5853BSlLCIls3Jy/I2z5T4IHhQq
-NwuIPMqw9MjCoa68wb4pZ1Xi/K1ZXP69VyywkI3C7Te2fJmItdUDmj0VDT06qKhF
-8JVOJVkdzZhpu9PMMsmN74H+rX2Ju7pgE8pllWeg8xn2A1bUatMn4qGtg/BKEiJ3
-HAVz4hlxQsDsdUaakFjgao4rpUYwBI4Zshfjvqm6f1bxJAPXsiEodg42MEx51UGa
-mqi4NboMOvJEGyCI98Ul1z3G4z5D3Yf+xOr1Uz5MZf87Sst4WmsXXw3Hw09Omiqi
-7VdNIuJGmj8PkTQkfVXjjJU30xrwCSss0smNtA0Aq2cpKNgB9RkEth2+dv5yXMSF
-ytKAQd8FqKPVhJBPC/PgP5sZ0jeJP/J7UhyM9uH3PAeXjA6iWYEMspA90+NZRu0P
-qafegGtaqge2Gcu8V/OXIXoMsSt0Puvap2ctTMSYnjYJdmZm/Bo/6khUHL4wvYBQ
-v3y1zgD2DGHZ5yQD4OMBgQ692IU0iL2yNqh7XAjlRICMb/gv1SHKHRzQ+8S1h9E6
-Tsd2tTVItQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSM+xx1
-vALTn04uSNn5YFSqxLNP+jAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQENBQAD
-ggIBAEii1QALLtA/vBzVtVRJHlpr9OTy4EA34MwUe7nJ+jW1dReTagVphZzNTxl4
-WxmB82M+w85bj/UvXgF2Ez8sALnNllI5SW0ETsXpD4YN4fqzX4IS8TrOZgYkNCvo
-zMrnadyHncI013nR03e4qllY/p0m+jiGPp2Kh2RX5Rc64vmNueMzeMGQ2Ljdt4NR
-5MTMI9UGfOZR0800McD2RrsLrfw9EAUqO0qRJe6M1ISHgCq8CYyqOhNf6DR5UMEQ
-GfnTKB7U0VEwKbOukGfWHwpjscWpxkIxYxeU72nLL/qMFH3EQxiJ2fAyQOaA4kZf
-5ePBAFmo+eggvIksDkc0C+pXwlM2/KfUrzHN/gLldfq5Jwn58/U7yn2fqSLLiMmq
-0Uc9NneoWWRrJ8/vJ8HjJLWG965+Mk2weWjROeiQWMODvA8s1pfrzgzhIMfatz7D
-P78v3DSk+yshzWePS/Tj6tQ/50+6uaWTRRxmHyH6ZF5v4HaUMst19W7l9o/HuKTM
-qJZ9ZPskWkoDbGs4xugDQ5r3V7mzKWmTOPQD8rv7gmsHINFSH5pkAnuYZttcTVoP
-0ISVoDwUQwbKytu4QTbaakRnh6+v40URFWkIsr4WOZckbxJF0WddCajJFdr60qZf
-E2Efv4WstK2tBZQIgx51F9NxO5NQI1mg7TyRVJ12AMXDuDjb
------END CERTIFICATE-----
-
-# Issuer: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique
-# Subject: CN=TunTrust Root CA O=Agence Nationale de Certification Electronique
-# Label: "TunTrust Root CA"
-# Serial: 108534058042236574382096126452369648152337120275
-# MD5 Fingerprint: 85:13:b9:90:5b:36:5c:b6:5e:b8:5a:f8:e0:31:57:b4
-# SHA1 Fingerprint: cf:e9:70:84:0f:e0:73:0f:9d:f6:0c:7f:2c:4b:ee:20:46:34:9c:bb
-# SHA256 Fingerprint: 2e:44:10:2a:b5:8c:b8:54:19:45:1c:8e:19:d9:ac:f3:66:2c:af:bc:61:4b:6a:53:96:0a:30:f7:d0:e2:eb:41
------BEGIN CERTIFICATE-----
-MIIFszCCA5ugAwIBAgIUEwLV4kBMkkaGFmddtLu7sms+/BMwDQYJKoZIhvcNAQEL
-BQAwYTELMAkGA1UEBhMCVE4xNzA1BgNVBAoMLkFnZW5jZSBOYXRpb25hbGUgZGUg
-Q2VydGlmaWNhdGlvbiBFbGVjdHJvbmlxdWUxGTAXBgNVBAMMEFR1blRydXN0IFJv
-b3QgQ0EwHhcNMTkwNDI2MDg1NzU2WhcNNDQwNDI2MDg1NzU2WjBhMQswCQYDVQQG
-EwJUTjE3MDUGA1UECgwuQWdlbmNlIE5hdGlvbmFsZSBkZSBDZXJ0aWZpY2F0aW9u
-IEVsZWN0cm9uaXF1ZTEZMBcGA1UEAwwQVHVuVHJ1c3QgUm9vdCBDQTCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMPN0/y9BFPdDCA61YguBUtB9YOCfvdZ
-n56eY+hz2vYGqU8ftPkLHzmMmiDQfgbU7DTZhrx1W4eI8NLZ1KMKsmwb60ksPqxd
-2JQDoOw05TDENX37Jk0bbjBU2PWARZw5rZzJJQRNmpA+TkBuimvNKWfGzC3gdOgF
-VwpIUPp6Q9p+7FuaDmJ2/uqdHYVy7BG7NegfJ7/Boce7SBbdVtfMTqDhuazb1YMZ
-GoXRlJfXyqNlC/M4+QKu3fZnz8k/9YosRxqZbwUN/dAdgjH8KcwAWJeRTIAAHDOF
-li/LQcKLEITDCSSJH7UP2dl3RxiSlGBcx5kDPP73lad9UKGAwqmDrViWVSHbhlnU
-r8a83YFuB9tgYv7sEG7aaAH0gxupPqJbI9dkxt/con3YS7qC0lH4Zr8GRuR5KiY2
-eY8fTpkdso8MDhz/yV3A/ZAQprE38806JG60hZC/gLkMjNWb1sjxVj8agIl6qeIb
-MlEsPvLfe/ZdeikZjuXIvTZxi11Mwh0/rViizz1wTaZQmCXcI/m4WEEIcb9PuISg
-jwBUFfyRbVinljvrS5YnzWuioYasDXxU5mZMZl+QviGaAkYt5IPCgLnPSz7ofzwB
-7I9ezX/SKEIBlYrilz0QIX32nRzFNKHsLA4KUiwSVXAkPcvCFDVDXSdOvsC9qnyW
-5/yeYa1E0wCXAgMBAAGjYzBhMB0GA1UdDgQWBBQGmpsfU33x9aTI04Y+oXNZtPdE
-ITAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFAaamx9TffH1pMjThj6hc1m0
-90QhMA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAqgVutt0Vyb+z
-xiD2BkewhpMl0425yAA/l/VSJ4hxyXT968pk21vvHl26v9Hr7lxpuhbI87mP0zYu
-QEkHDVneixCwSQXi/5E/S7fdAo74gShczNxtr18UnH1YeA32gAm56Q6XKRm4t+v4
-FstVEuTGfbvE7Pi1HE4+Z7/FXxttbUcoqgRYYdZ2vyJ/0Adqp2RT8JeNnYA/u8EH
-22Wv5psymsNUk8QcCMNE+3tjEUPRahphanltkE8pjkcFwRJpadbGNjHh/PqAulxP
-xOu3Mqz4dWEX1xAZufHSCe96Qp1bWgvUxpVOKs7/B9dPfhgGiPEZtdmYu65xxBzn
-dFlY7wyJz4sfdZMaBBSSSFCp61cpABbjNhzI+L/wM9VBD8TMPN3pM0MBkRArHtG5
-Xc0yGYuPjCB31yLEQtyEFpslbei0VXF/sHyz03FJuc9SpAQ/3D2gu68zngowYI7b
-nV2UqL1g52KAdoGDDIzMMEZJ4gzSqK/rYXHv5yJiqfdcZGyfFoxnNidF9Ql7v/YQ
-CvGwjVRDjAS6oz/v4jXH+XTgbzRB0L9zZVcg+ZtnemZoJE6AZb0QmQZZ8mWvuMZH
-u/2QeItBcy6vVR/cO5JyboTT0GFMDcx2V+IthSIVNg3rAZ3r2OvEhJn7wAzMMujj
-d9qDRIueVSjAi1jTkD5OGwDxFa2DK5o=
------END CERTIFICATE-----
-
-# Issuer: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA
-# Subject: CN=HARICA TLS RSA Root CA 2021 O=Hellenic Academic and Research Institutions CA
-# Label: "HARICA TLS RSA Root CA 2021"
-# Serial: 76817823531813593706434026085292783742
-# MD5 Fingerprint: 65:47:9b:58:86:dd:2c:f0:fc:a2:84:1f:1e:96:c4:91
-# SHA1 Fingerprint: 02:2d:05:82:fa:88:ce:14:0c:06:79:de:7f:14:10:e9:45:d7:a5:6d
-# SHA256 Fingerprint: d9:5d:0e:8e:da:79:52:5b:f9:be:b1:1b:14:d2:10:0d:32:94:98:5f:0c:62:d9:fa:bd:9c:d9:99:ec:cb:7b:1d
------BEGIN CERTIFICATE-----
-MIIFpDCCA4ygAwIBAgIQOcqTHO9D88aOk8f0ZIk4fjANBgkqhkiG9w0BAQsFADBs
-MQswCQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
-c2VhcmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBSU0Eg
-Um9vdCBDQSAyMDIxMB4XDTIxMDIxOTEwNTUzOFoXDTQ1MDIxMzEwNTUzN1owbDEL
-MAkGA1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNl
-YXJjaCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgUlNBIFJv
-b3QgQ0EgMjAyMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAIvC569l
-mwVnlskNJLnQDmT8zuIkGCyEf3dRywQRNrhe7Wlxp57kJQmXZ8FHws+RFjZiPTgE
-4VGC/6zStGndLuwRo0Xua2s7TL+MjaQenRG56Tj5eg4MmOIjHdFOY9TnuEFE+2uv
-a9of08WRiFukiZLRgeaMOVig1mlDqa2YUlhu2wr7a89o+uOkXjpFc5gH6l8Cct4M
-pbOfrqkdtx2z/IpZ525yZa31MJQjB/OCFks1mJxTuy/K5FrZx40d/JiZ+yykgmvw
-Kh+OC19xXFyuQnspiYHLA6OZyoieC0AJQTPb5lh6/a6ZcMBaD9YThnEvdmn8kN3b
-LW7R8pv1GmuebxWMevBLKKAiOIAkbDakO/IwkfN4E8/BPzWr8R0RI7VDIp4BkrcY
-AuUR0YLbFQDMYTfBKnya4dC6s1BG7oKsnTH4+yPiAwBIcKMJJnkVU2DzOFytOOqB
-AGMUuTNe3QvboEUHGjMJ+E20pwKmafTCWQWIZYVWrkvL4N48fS0ayOn7H6NhStYq
-E613TBoYm5EPWNgGVMWX+Ko/IIqmhaZ39qb8HOLubpQzKoNQhArlT4b4UEV4AIHr
-W2jjJo3Me1xR9BQsQL4aYB16cmEdH2MtiKrOokWQCPxrvrNQKlr9qEgYRtaQQJKQ
-CoReaDH46+0N0x3GfZkYVVYnZS6NRcUk7M7jAgMBAAGjQjBAMA8GA1UdEwEB/wQF
-MAMBAf8wHQYDVR0OBBYEFApII6ZgpJIKM+qTW8VX6iVNvRLuMA4GA1UdDwEB/wQE
-AwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAPpBIqm5iFSVmewzVjIuJndftTgfvnNAU
-X15QvWiWkKQUEapobQk1OUAJ2vQJLDSle1mESSmXdMgHHkdt8s4cUCbjnj1AUz/3
-f5Z2EMVGpdAgS1D0NTsY9FVqQRtHBmg8uwkIYtlfVUKqrFOFrJVWNlar5AWMxaja
-H6NpvVMPxP/cyuN+8kyIhkdGGvMA9YCRotxDQpSbIPDRzbLrLFPCU3hKTwSUQZqP
-JzLB5UkZv/HywouoCjkxKLR9YjYsTewfM7Z+d21+UPCfDtcRj88YxeMn/ibvBZ3P
-zzfF0HvaO7AWhAw6k9a+F9sPPg4ZeAnHqQJyIkv3N3a6dcSFA1pj1bF1BcK5vZSt
-jBWZp5N99sXzqnTPBIWUmAD04vnKJGW/4GKvyMX6ssmeVkjaef2WdhW+o45WxLM0
-/L5H9MG0qPzVMIho7suuyWPEdr6sOBjhXlzPrjoiUevRi7PzKzMHVIf6tLITe7pT
-BGIBnfHAT+7hOtSLIBD6Alfm78ELt5BGnBkpjNxvoEppaZS3JGWg/6w/zgH7IS79
-aPib8qXPMThcFarmlwDB31qlpzmq6YR/PFGoOtmUW4y/Twhx5duoXNTSpv4Ao8YW
-xw/ogM4cKGR0GQjTQuPOAF1/sdwTsOEFy9EgqoZ0njnnkf3/W9b3raYvAwtt41dU
-63ZTGI0RmLo=
------END CERTIFICATE-----
-
-# Issuer: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
-# Subject: CN=HARICA TLS ECC Root CA 2021 O=Hellenic Academic and Research Institutions CA
-# Label: "HARICA TLS ECC Root CA 2021"
-# Serial: 137515985548005187474074462014555733966
-# MD5 Fingerprint: ae:f7:4c:e5:66:35:d1:b7:9b:8c:22:93:74:d3:4b:b0
-# SHA1 Fingerprint: bc:b0:c1:9d:e9:98:92:70:19:38:57:e9:8d:a7:b4:5d:6e:ee:01:48
-# SHA256 Fingerprint: 3f:99:cc:47:4a:cf:ce:4d:fe:d5:87:94:66:5e:47:8d:15:47:73:9f:2e:78:0f:1b:b4:ca:9b:13:30:97:d4:01
------BEGIN CERTIFICATE-----
-MIICVDCCAdugAwIBAgIQZ3SdjXfYO2rbIvT/WeK/zjAKBggqhkjOPQQDAzBsMQsw
-CQYDVQQGEwJHUjE3MDUGA1UECgwuSGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJlc2Vh
-cmNoIEluc3RpdHV0aW9ucyBDQTEkMCIGA1UEAwwbSEFSSUNBIFRMUyBFQ0MgUm9v
-dCBDQSAyMDIxMB4XDTIxMDIxOTExMDExMFoXDTQ1MDIxMzExMDEwOVowbDELMAkG
-A1UEBhMCR1IxNzA1BgNVBAoMLkhlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJj
-aCBJbnN0aXR1dGlvbnMgQ0ExJDAiBgNVBAMMG0hBUklDQSBUTFMgRUNDIFJvb3Qg
-Q0EgMjAyMTB2MBAGByqGSM49AgEGBSuBBAAiA2IABDgI/rGgltJ6rK9JOtDA4MM7
-KKrxcm1lAEeIhPyaJmuqS7psBAqIXhfyVYf8MLA04jRYVxqEU+kw2anylnTDUR9Y
-STHMmE5gEYd103KUkE+bECUqqHgtvpBBWJAVcqeht6NCMEAwDwYDVR0TAQH/BAUw
-AwEB/zAdBgNVHQ4EFgQUyRtTgRL+BNUW0aq8mm+3oJUZbsowDgYDVR0PAQH/BAQD
-AgGGMAoGCCqGSM49BAMDA2cAMGQCMBHervjcToiwqfAircJRQO9gcS3ujwLEXQNw
-SaSS6sUUiHCm0w2wqsosQJz76YJumgIwK0eaB8bRwoF8yguWGEEbo/QwCZ61IygN
-nxS2PFOiTAZpffpskcYqSUXm7LcT4Tps
------END CERTIFICATE-----
-
-# Issuer: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
-# Subject: CN=Autoridad de Certificacion Firmaprofesional CIF A62634068
-# Label: "Autoridad de Certificacion Firmaprofesional CIF A62634068"
-# Serial: 1977337328857672817
-# MD5 Fingerprint: 4e:6e:9b:54:4c:ca:b7:fa:48:e4:90:b1:15:4b:1c:a3
-# SHA1 Fingerprint: 0b:be:c2:27:22:49:cb:39:aa:db:35:5c:53:e3:8c:ae:78:ff:b6:fe
-# SHA256 Fingerprint: 57:de:05:83:ef:d2:b2:6e:03:61:da:99:da:9d:f4:64:8d:ef:7e:e8:44:1c:3b:72:8a:fa:9b:cd:e0:f9:b2:6a
------BEGIN CERTIFICATE-----
-MIIGFDCCA/ygAwIBAgIIG3Dp0v+ubHEwDQYJKoZIhvcNAQELBQAwUTELMAkGA1UE
-BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
-cHJvZmVzaW9uYWwgQ0lGIEE2MjYzNDA2ODAeFw0xNDA5MjMxNTIyMDdaFw0zNjA1
-MDUxNTIyMDdaMFExCzAJBgNVBAYTAkVTMUIwQAYDVQQDDDlBdXRvcmlkYWQgZGUg
-Q2VydGlmaWNhY2lvbiBGaXJtYXByb2Zlc2lvbmFsIENJRiBBNjI2MzQwNjgwggIi
-MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDKlmuO6vj78aI14H9M2uDDUtd9
-thDIAl6zQyrET2qyyhxdKJp4ERppWVevtSBC5IsP5t9bpgOSL/UR5GLXMnE42QQM
-cas9UX4PB99jBVzpv5RvwSmCwLTaUbDBPLutN0pcyvFLNg4kq7/DhHf9qFD0sefG
-L9ItWY16Ck6WaVICqjaY7Pz6FIMMNx/Jkjd/14Et5cS54D40/mf0PmbR0/RAz15i
-NA9wBj4gGFrO93IbJWyTdBSTo3OxDqqHECNZXyAFGUftaI6SEspd/NYrspI8IM/h
-X68gvqB2f3bl7BqGYTM+53u0P6APjqK5am+5hyZvQWyIplD9amML9ZMWGxmPsu2b
-m8mQ9QEM3xk9Dz44I8kvjwzRAv4bVdZO0I08r0+k8/6vKtMFnXkIoctXMbScyJCy
-Z/QYFpM6/EfY0XiWMR+6KwxfXZmtY4laJCB22N/9q06mIqqdXuYnin1oKaPnirja
-EbsXLZmdEyRG98Xi2J+Of8ePdG1asuhy9azuJBCtLxTa/y2aRnFHvkLfuwHb9H/T
-KI8xWVvTyQKmtFLKbpf7Q8UIJm+K9Lv9nyiqDdVF8xM6HdjAeI9BZzwelGSuewvF
-6NkBiDkal4ZkQdU7hwxu+g/GvUgUvzlN1J5Bto+WHWOWk9mVBngxaJ43BjuAiUVh
-OSPHG0SjFeUc+JIwuwIDAQABo4HvMIHsMB0GA1UdDgQWBBRlzeurNR4APn7VdMAc
-tHNHDhpkLzASBgNVHRMBAf8ECDAGAQH/AgEBMIGmBgNVHSAEgZ4wgZswgZgGBFUd
-IAAwgY8wLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuZmlybWFwcm9mZXNpb25hbC5j
-b20vY3BzMFwGCCsGAQUFBwICMFAeTgBQAGEAcwBlAG8AIABkAGUAIABsAGEAIABC
-AG8AbgBhAG4AbwB2AGEAIAA0ADcAIABCAGEAcgBjAGUAbABvAG4AYQAgADAAOAAw
-ADEANzAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggIBAHSHKAIrdx9m
-iWTtj3QuRhy7qPj4Cx2Dtjqn6EWKB7fgPiDL4QjbEwj4KKE1soCzC1HA01aajTNF
-Sa9J8OA9B3pFE1r/yJfY0xgsfZb43aJlQ3CTkBW6kN/oGbDbLIpgD7dvlAceHabJ
-hfa9NPhAeGIQcDq+fUs5gakQ1JZBu/hfHAsdCPKxsIl68veg4MSPi3i1O1ilI45P
-Vf42O+AMt8oqMEEgtIDNrvx2ZnOorm7hfNoD6JQg5iKj0B+QXSBTFCZX2lSX3xZE
-EAEeiGaPcjiT3SC3NL7X8e5jjkd5KAb881lFJWAiMxujX6i6KtoaPc1A6ozuBRWV
-1aUsIC+nmCjuRfzxuIgALI9C2lHVnOUTaHFFQ4ueCyE8S1wF3BqfmI7avSKecs2t
-CsvMo2ebKHTEm9caPARYpoKdrcd7b/+Alun4jWq9GJAd/0kakFI3ky88Al2CdgtR
-5xbHV/g4+afNmyJU72OwFW1TZQNKXkqgsqeOSQBZONXH9IBk9W6VULgRfhVwOEqw
-f9DEMnDAGf/JOC0ULGb0QkTmVXYbgBVX/8Cnp6o5qtjTcNAuuuuUavpfNIbnYrX9
-ivAwhZTJryQCL2/W3Wf+47BVTwSYT6RBVuKT0Gro1vP7ZeDOdcQxWQzugsgMYDNK
-GbqEZycPvEJdvSRUDewdcAZfpLz6IHxV
------END CERTIFICATE-----
-
-# Issuer: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd.
-# Subject: CN=vTrus ECC Root CA O=iTrusChina Co.,Ltd.
-# Label: "vTrus ECC Root CA"
-# Serial: 630369271402956006249506845124680065938238527194
-# MD5 Fingerprint: de:4b:c1:f5:52:8c:9b:43:e1:3e:8f:55:54:17:8d:85
-# SHA1 Fingerprint: f6:9c:db:b0:fc:f6:02:13:b6:52:32:a6:a3:91:3f:16:70:da:c3:e1
-# SHA256 Fingerprint: 30:fb:ba:2c:32:23:8e:2a:98:54:7a:f9:79:31:e5:50:42:8b:9b:3f:1c:8e:eb:66:33:dc:fa:86:c5:b2:7d:d3
------BEGIN CERTIFICATE-----
-MIICDzCCAZWgAwIBAgIUbmq8WapTvpg5Z6LSa6Q75m0c1towCgYIKoZIzj0EAwMw
-RzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4xGjAY
-BgNVBAMTEXZUcnVzIEVDQyBSb290IENBMB4XDTE4MDczMTA3MjY0NFoXDTQzMDcz
-MTA3MjY0NFowRzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28u
-LEx0ZC4xGjAYBgNVBAMTEXZUcnVzIEVDQyBSb290IENBMHYwEAYHKoZIzj0CAQYF
-K4EEACIDYgAEZVBKrox5lkqqHAjDo6LN/llWQXf9JpRCux3NCNtzslt188+cToL0
-v/hhJoVs1oVbcnDS/dtitN9Ti72xRFhiQgnH+n9bEOf+QP3A2MMrMudwpremIFUd
-e4BdS49nTPEQo0IwQDAdBgNVHQ4EFgQUmDnNvtiyjPeyq+GtJK97fKHbH88wDwYD
-VR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwCgYIKoZIzj0EAwMDaAAwZQIw
-V53dVvHH4+m4SVBrm2nDb+zDfSXkV5UTQJtS0zvzQBm8JsctBp61ezaf9SXUY2sA
-AjEA6dPGnlaaKsyh2j/IZivTWJwghfqrkYpwcBE4YGQLYgmRWAD5Tfs0aNoJrSEG
-GJTO
------END CERTIFICATE-----
-
-# Issuer: CN=vTrus Root CA O=iTrusChina Co.,Ltd.
-# Subject: CN=vTrus Root CA O=iTrusChina Co.,Ltd.
-# Label: "vTrus Root CA"
-# Serial: 387574501246983434957692974888460947164905180485
-# MD5 Fingerprint: b8:c9:37:df:fa:6b:31:84:64:c5:ea:11:6a:1b:75:fc
-# SHA1 Fingerprint: 84:1a:69:fb:f5:cd:1a:25:34:13:3d:e3:f8:fc:b8:99:d0:c9:14:b7
-# SHA256 Fingerprint: 8a:71:de:65:59:33:6f:42:6c:26:e5:38:80:d0:0d:88:a1:8d:a4:c6:a9:1f:0d:cb:61:94:e2:06:c5:c9:63:87
------BEGIN CERTIFICATE-----
-MIIFVjCCAz6gAwIBAgIUQ+NxE9izWRRdt86M/TX9b7wFjUUwDQYJKoZIhvcNAQEL
-BQAwQzELMAkGA1UEBhMCQ04xHDAaBgNVBAoTE2lUcnVzQ2hpbmEgQ28uLEx0ZC4x
-FjAUBgNVBAMTDXZUcnVzIFJvb3QgQ0EwHhcNMTgwNzMxMDcyNDA1WhcNNDMwNzMx
-MDcyNDA1WjBDMQswCQYDVQQGEwJDTjEcMBoGA1UEChMTaVRydXNDaGluYSBDby4s
-THRkLjEWMBQGA1UEAxMNdlRydXMgUm9vdCBDQTCCAiIwDQYJKoZIhvcNAQEBBQAD
-ggIPADCCAgoCggIBAL1VfGHTuB0EYgWgrmy3cLRB6ksDXhA/kFocizuwZotsSKYc
-IrrVQJLuM7IjWcmOvFjai57QGfIvWcaMY1q6n6MLsLOaXLoRuBLpDLvPbmyAhykU
-AyyNJJrIZIO1aqwTLDPxn9wsYTwaP3BVm60AUn/PBLn+NvqcwBauYv6WTEN+VRS+
-GrPSbcKvdmaVayqwlHeFXgQPYh1jdfdr58tbmnDsPmcF8P4HCIDPKNsFxhQnL4Z9
-8Cfe/+Z+M0jnCx5Y0ScrUw5XSmXX+6KAYPxMvDVTAWqXcoKv8R1w6Jz1717CbMdH
-flqUhSZNO7rrTOiwCcJlwp2dCZtOtZcFrPUGoPc2BX70kLJrxLT5ZOrpGgrIDajt
-J8nU57O5q4IikCc9Kuh8kO+8T/3iCiSn3mUkpF3qwHYw03dQ+A0Em5Q2AXPKBlim
-0zvc+gRGE1WKyURHuFE5Gi7oNOJ5y1lKCn+8pu8fA2dqWSslYpPZUxlmPCdiKYZN
-pGvu/9ROutW04o5IWgAZCfEF2c6Rsffr6TlP9m8EQ5pV9T4FFL2/s1m02I4zhKOQ
-UqqzApVg+QxMaPnu1RcN+HFXtSXkKe5lXa/R7jwXC1pDxaWG6iSe4gUH3DRCEpHW
-OXSuTEGC2/KmSNGzm/MzqvOmwMVO9fSddmPmAsYiS8GVP1BkLFTltvA8Kc9XAgMB
-AAGjQjBAMB0GA1UdDgQWBBRUYnBj8XWEQ1iO0RYgscasGrz2iTAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAKbqSSaet
-8PFww+SX8J+pJdVrnjT+5hpk9jprUrIQeBqfTNqK2uwcN1LgQkv7bHbKJAs5EhWd
-nxEt/Hlk3ODg9d3gV8mlsnZwUKT+twpw1aA08XXXTUm6EdGz2OyC/+sOxL9kLX1j
-bhd47F18iMjrjld22VkE+rxSH0Ws8HqA7Oxvdq6R2xCOBNyS36D25q5J08FsEhvM
-Kar5CKXiNxTKsbhm7xqC5PD48acWabfbqWE8n/Uxy+QARsIvdLGx14HuqCaVvIiv
-TDUHKgLKeBRtRytAVunLKmChZwOgzoy8sHJnxDHO2zTlJQNgJXtxmOTAGytfdELS
-S8VZCAeHvsXDf+eW2eHcKJfWjwXj9ZtOyh1QRwVTsMo554WgicEFOwE30z9J4nfr
-I8iIZjs9OXYhRvHsXyO466JmdXTBQPfYaJqT4i2pLr0cox7IdMakLXogqzu4sEb9
-b91fUlV1YvCXoHzXOP0l382gmxDPi7g4Xl7FtKYCNqEeXxzP4padKar9mK5S4fNB
-UvupLnKWnyfjqnN9+BojZns7q2WwMgFLFT49ok8MKzWixtlnEjUwzXYuFrOZnk1P
-Ti07NEPhmg4NpGaXutIcSkwsKouLgU9xGqndXHt7CMUADTdA43x7VF8vhV929ven
-sBxXVsFy6K2ir40zSbofitzmdHxghm+Hl3s=
------END CERTIFICATE-----
-
-# Issuer: CN=ISRG Root X2 O=Internet Security Research Group
-# Subject: CN=ISRG Root X2 O=Internet Security Research Group
-# Label: "ISRG Root X2"
-# Serial: 87493402998870891108772069816698636114
-# MD5 Fingerprint: d3:9e:c4:1e:23:3c:a6:df:cf:a3:7e:6d:e0:14:e6:e5
-# SHA1 Fingerprint: bd:b1:b9:3c:d5:97:8d:45:c6:26:14:55:f8:db:95:c7:5a:d1:53:af
-# SHA256 Fingerprint: 69:72:9b:8e:15:a8:6e:fc:17:7a:57:af:b7:17:1d:fc:64:ad:d2:8c:2f:ca:8c:f1:50:7e:34:45:3c:cb:14:70
------BEGIN CERTIFICATE-----
-MIICGzCCAaGgAwIBAgIQQdKd0XLq7qeAwSxs6S+HUjAKBggqhkjOPQQDAzBPMQsw
-CQYDVQQGEwJVUzEpMCcGA1UEChMgSW50ZXJuZXQgU2VjdXJpdHkgUmVzZWFyY2gg
-R3JvdXAxFTATBgNVBAMTDElTUkcgUm9vdCBYMjAeFw0yMDA5MDQwMDAwMDBaFw00
-MDA5MTcxNjAwMDBaME8xCzAJBgNVBAYTAlVTMSkwJwYDVQQKEyBJbnRlcm5ldCBT
-ZWN1cml0eSBSZXNlYXJjaCBHcm91cDEVMBMGA1UEAxMMSVNSRyBSb290IFgyMHYw
-EAYHKoZIzj0CAQYFK4EEACIDYgAEzZvVn4CDCuwJSvMWSj5cz3es3mcFDR0HttwW
-+1qLFNvicWDEukWVEYmO6gbf9yoWHKS5xcUy4APgHoIYOIvXRdgKam7mAHf7AlF9
-ItgKbppbd9/w+kHsOdx1ymgHDB/qo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0T
-AQH/BAUwAwEB/zAdBgNVHQ4EFgQUfEKWrt5LSDv6kviejM9ti6lyN5UwCgYIKoZI
-zj0EAwMDaAAwZQIwe3lORlCEwkSHRhtFcP9Ymd70/aTSVaYgLXTWNLxBo1BfASdW
-tL4ndQavEi51mI38AjEAi/V3bNTIZargCyzuFJ0nN6T5U6VR5CmD1/iQMVtCnwr1
-/q4AaOeMSQ+2b1tbFfLn
------END CERTIFICATE-----
-
-# Issuer: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd.
-# Subject: CN=HiPKI Root CA - G1 O=Chunghwa Telecom Co., Ltd.
-# Label: "HiPKI Root CA - G1"
-# Serial: 60966262342023497858655262305426234976
-# MD5 Fingerprint: 69:45:df:16:65:4b:e8:68:9a:8f:76:5f:ff:80:9e:d3
-# SHA1 Fingerprint: 6a:92:e4:a8:ee:1b:ec:96:45:37:e3:29:57:49:cd:96:e3:e5:d2:60
-# SHA256 Fingerprint: f0:15:ce:3c:c2:39:bf:ef:06:4b:e9:f1:d2:c4:17:e1:a0:26:4a:0a:94:be:1f:0c:8d:12:18:64:eb:69:49:cc
------BEGIN CERTIFICATE-----
-MIIFajCCA1KgAwIBAgIQLd2szmKXlKFD6LDNdmpeYDANBgkqhkiG9w0BAQsFADBP
-MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
-ZC4xGzAZBgNVBAMMEkhpUEtJIFJvb3QgQ0EgLSBHMTAeFw0xOTAyMjIwOTQ2MDRa
-Fw0zNzEyMzExNTU5NTlaME8xCzAJBgNVBAYTAlRXMSMwIQYDVQQKDBpDaHVuZ2h3
-YSBUZWxlY29tIENvLiwgTHRkLjEbMBkGA1UEAwwSSGlQS0kgUm9vdCBDQSAtIEcx
-MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA9B5/UnMyDHPkvRN0o9Qw
-qNCuS9i233VHZvR85zkEHmpwINJaR3JnVfSl6J3VHiGh8Ge6zCFovkRTv4354twv
-Vcg3Px+kwJyz5HdcoEb+d/oaoDjq7Zpy3iu9lFc6uux55199QmQ5eiY29yTw1S+6
-lZgRZq2XNdZ1AYDgr/SEYYwNHl98h5ZeQa/rh+r4XfEuiAU+TCK72h8q3VJGZDnz
-Qs7ZngyzsHeXZJzA9KMuH5UHsBffMNsAGJZMoYFL3QRtU6M9/Aes1MU3guvklQgZ
-KILSQjqj2FPseYlgSGDIcpJQ3AOPgz+yQlda22rpEZfdhSi8MEyr48KxRURHH+CK
-FgeW0iEPU8DtqX7UTuybCeyvQqww1r/REEXgphaypcXTT3OUM3ECoWqj1jOXTyFj
-HluP2cFeRXF3D4FdXyGarYPM+l7WjSNfGz1BryB1ZlpK9p/7qxj3ccC2HTHsOyDr
-y+K49a6SsvfhhEvyovKTmiKe0xRvNlS9H15ZFblzqMF8b3ti6RZsR1pl8w4Rm0bZ
-/W3c1pzAtH2lsN0/Vm+h+fbkEkj9Bn8SV7apI09bA8PgcSojt/ewsTu8mL3WmKgM
-a/aOEmem8rJY5AIJEzypuxC00jBF8ez3ABHfZfjcK0NVvxaXxA/VLGGEqnKG/uY6
-fsI/fe78LxQ+5oXdUG+3Se0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
-HQ4EFgQU8ncX+l6o/vY9cdVouslGDDjYr7AwDgYDVR0PAQH/BAQDAgGGMA0GCSqG
-SIb3DQEBCwUAA4ICAQBQUfB13HAE4/+qddRxosuej6ip0691x1TPOhwEmSKsxBHi
-7zNKpiMdDg1H2DfHb680f0+BazVP6XKlMeJ45/dOlBhbQH3PayFUhuaVevvGyuqc
-SE5XCV0vrPSltJczWNWseanMX/mF+lLFjfiRFOs6DRfQUsJ748JzjkZ4Bjgs6Fza
-ZsT0pPBWGTMpWmWSBUdGSquEwx4noR8RkpkndZMPvDY7l1ePJlsMu5wP1G4wB9Tc
-XzZoZjmDlicmisjEOf6aIW/Vcobpf2Lll07QJNBAsNB1CI69aO4I1258EHBGG3zg
-iLKecoaZAeO/n0kZtCW+VmWuF2PlHt/o/0elv+EmBYTksMCv5wiZqAxeJoBF1Pho
-L5aPruJKHJwWDBNvOIf2u8g0X5IDUXlwpt/L9ZlNec1OvFefQ05rLisY+GpzjLrF
-Ne85akEez3GoorKGB1s6yeHvP2UEgEcyRHCVTjFnanRbEEV16rCf0OY1/k6fi8wr
-kkVbbiVghUbN0aqwdmaTd5a+g744tiROJgvM7XpWGuDpWsZkrUx6AEhEL7lAuxM+
-vhV4nYWBSipX3tUZQ9rbyltHhoMLP7YNdnhzeSJesYAfz77RP1YQmCuVh6EfnWQU
-YDksswBVLuT1sw5XxJFBAJw/6KXf6vb/yPCtbVKoF6ubYfwSUTXkJf2vqmqGOQ==
------END CERTIFICATE-----
-
-# Issuer: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4
-# Subject: CN=GlobalSign O=GlobalSign OU=GlobalSign ECC Root CA - R4
-# Label: "GlobalSign ECC Root CA - R4"
-# Serial: 159662223612894884239637590694
-# MD5 Fingerprint: 26:29:f8:6d:e1:88:bf:a2:65:7f:aa:c4:cd:0f:7f:fc
-# SHA1 Fingerprint: 6b:a0:b0:98:e1:71:ef:5a:ad:fe:48:15:80:77:10:f4:bd:6f:0b:28
-# SHA256 Fingerprint: b0:85:d7:0b:96:4f:19:1a:73:e4:af:0d:54:ae:7a:0e:07:aa:fd:af:9b:71:dd:08:62:13:8a:b7:32:5a:24:a2
------BEGIN CERTIFICATE-----
-MIIB3DCCAYOgAwIBAgINAgPlfvU/k/2lCSGypjAKBggqhkjOPQQDAjBQMSQwIgYD
-VQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0gUjQxEzARBgNVBAoTCkdsb2Jh
-bFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMTIxMTEzMDAwMDAwWhcNMzgw
-MTE5MDMxNDA3WjBQMSQwIgYDVQQLExtHbG9iYWxTaWduIEVDQyBSb290IENBIC0g
-UjQxEzARBgNVBAoTCkdsb2JhbFNpZ24xEzARBgNVBAMTCkdsb2JhbFNpZ24wWTAT
-BgcqhkjOPQIBBggqhkjOPQMBBwNCAAS4xnnTj2wlDp8uORkcA6SumuU5BwkWymOx
-uYb4ilfBV85C+nOh92VC/x7BALJucw7/xyHlGKSq2XE/qNS5zowdo0IwQDAOBgNV
-HQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVLB7rUW44kB/
-+wpu+74zyTyjhNUwCgYIKoZIzj0EAwIDRwAwRAIgIk90crlgr/HmnKAWBVBfw147
-bmF0774BxL4YSFlhgjICICadVGNA3jdgUM/I2O2dgq43mLyjj0xMqTQrbO/7lZsm
------END CERTIFICATE-----
-
-# Issuer: CN=GTS Root R1 O=Google Trust Services LLC
-# Subject: CN=GTS Root R1 O=Google Trust Services LLC
-# Label: "GTS Root R1"
-# Serial: 159662320309726417404178440727
-# MD5 Fingerprint: 05:fe:d0:bf:71:a8:a3:76:63:da:01:e0:d8:52:dc:40
-# SHA1 Fingerprint: e5:8c:1c:c4:91:3b:38:63:4b:e9:10:6e:e3:ad:8e:6b:9d:d9:81:4a
-# SHA256 Fingerprint: d9:47:43:2a:bd:e7:b7:fa:90:fc:2e:6b:59:10:1b:12:80:e0:e1:c7:e4:e4:0f:a3:c6:88:7f:ff:57:a7:f4:cf
------BEGIN CERTIFICATE-----
-MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
-CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
-MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
-MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
-Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
-27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
-Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
-TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
-qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
-szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
-Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
-MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
-wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
-aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
-VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
-AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
-C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
-QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
-h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
-7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
-ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
-MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
-Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
-6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
-0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
-2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
-bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
------END CERTIFICATE-----
-
-# Issuer: CN=GTS Root R2 O=Google Trust Services LLC
-# Subject: CN=GTS Root R2 O=Google Trust Services LLC
-# Label: "GTS Root R2"
-# Serial: 159662449406622349769042896298
-# MD5 Fingerprint: 1e:39:c0:53:e6:1e:29:82:0b:ca:52:55:36:5d:57:dc
-# SHA1 Fingerprint: 9a:44:49:76:32:db:de:fa:d0:bc:fb:5a:7b:17:bd:9e:56:09:24:94
-# SHA256 Fingerprint: 8d:25:cd:97:22:9d:bf:70:35:6b:da:4e:b3:cc:73:40:31:e2:4c:f0:0f:af:cf:d3:2d:c7:6e:b5:84:1c:7e:a8
------BEGIN CERTIFICATE-----
-MIIFVzCCAz+gAwIBAgINAgPlrsWNBCUaqxElqjANBgkqhkiG9w0BAQwFADBHMQsw
-CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
-MBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
-MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
-Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUA
-A4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3LvCvpt
-nfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3KgGjSY
-6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9BuXvAu
-MC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOdre7k
-RXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXuPuWg
-f9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1mKPV
-+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K8Yzo
-dDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqjx5RW
-Ir9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsRnTKa
-G73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0kzCq
-gc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9OktwID
-AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
-FgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBAB/Kzt3H
-vqGf2SdMC9wXmBFqiN495nFWcrKeGk6c1SuYJF2ba3uwM4IJvd8lRuqYnrYb/oM8
-0mJhwQTtzuDFycgTE1XnqGOtjHsB/ncw4c5omwX4Eu55MaBBRTUoCnGkJE+M3DyC
-B19m3H0Q/gxhswWV7uGugQ+o+MePTagjAiZrHYNSVc61LwDKgEDg4XSsYPWHgJ2u
-NmSRXbBoGOqKYcl3qJfEycel/FVL8/B/uWU9J2jQzGv6U53hkRrJXRqWbTKH7QMg
-yALOWr7Z6v2yTcQvG99fevX4i8buMTolUVVnjWQye+mew4K6Ki3pHrTgSAai/Gev
-HyICc/sgCq+dVEuhzf9gR7A/Xe8bVr2XIZYtCtFenTgCR2y59PYjJbigapordwj6
-xLEokCZYCDzifqrXPW+6MYgKBesntaFJ7qBFVHvmJ2WZICGoo7z7GJa7Um8M7YNR
-TOlZ4iBgxcJlkoKM8xAfDoqXvneCbT+PHV28SSe9zE8P4c52hgQjxcCMElv924Sg
-JPFI/2R80L5cFtHvma3AH/vLrrw4IgYmZNralw4/KBVEqE8AyvCazM90arQ+POuV
-7LXTWtiBmelDGDfrs7vRWGJB82bSj6p4lVQgw1oudCvV0b4YacCs1aTPObpRhANl
-6WLAYv7YTVWW4tAR+kg0Eeye7QUd5MjWHYbL
------END CERTIFICATE-----
-
-# Issuer: CN=GTS Root R3 O=Google Trust Services LLC
-# Subject: CN=GTS Root R3 O=Google Trust Services LLC
-# Label: "GTS Root R3"
-# Serial: 159662495401136852707857743206
-# MD5 Fingerprint: 3e:e7:9d:58:02:94:46:51:94:e5:e0:22:4a:8b:e7:73
-# SHA1 Fingerprint: ed:e5:71:80:2b:c8:92:b9:5b:83:3c:d2:32:68:3f:09:cd:a0:1e:46
-# SHA256 Fingerprint: 34:d8:a7:3e:e2:08:d9:bc:db:0d:95:65:20:93:4b:4e:40:e6:94:82:59:6e:8b:6f:73:c8:42:6b:01:0a:6f:48
------BEGIN CERTIFICATE-----
-MIICCTCCAY6gAwIBAgINAgPluILrIPglJ209ZjAKBggqhkjOPQQDAzBHMQswCQYD
-VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
-A1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
-WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
-IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
-AAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout736G
-jOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2ADDL2
-4CejQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
-BBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEA9uEglRR7
-VKOQFhG/hMjqb2sXnh5GmCCbn9MN2azTL818+FsuVbu/3ZL3pAzcMeGiAjEA/Jdm
-ZuVDFhOD3cffL74UOO0BzrEXGhF16b0DjyZ+hOXJYKaV11RZt+cRLInUue4X
------END CERTIFICATE-----
-
-# Issuer: CN=GTS Root R4 O=Google Trust Services LLC
-# Subject: CN=GTS Root R4 O=Google Trust Services LLC
-# Label: "GTS Root R4"
-# Serial: 159662532700760215368942768210
-# MD5 Fingerprint: 43:96:83:77:19:4d:76:b3:9d:65:52:e4:1d:22:a5:e8
-# SHA1 Fingerprint: 77:d3:03:67:b5:e0:0c:15:f6:0c:38:61:df:7c:e1:3b:92:46:4d:47
-# SHA256 Fingerprint: 34:9d:fa:40:58:c5:e2:63:12:3b:39:8a:e7:95:57:3c:4e:13:13:c8:3f:e6:8f:93:55:6c:d5:e8:03:1b:3c:7d
------BEGIN CERTIFICATE-----
-MIICCTCCAY6gAwIBAgINAgPlwGjvYxqccpBQUjAKBggqhkjOPQQDAzBHMQswCQYD
-VQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEUMBIG
-A1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAwMDAw
-WjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2Vz
-IExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
-AATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzuhXyi
-QHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/lxKvR
-HYqjQjBAMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQW
-BBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNpADBmAjEA6ED/g94D
-9J+uHXqnLrmvT/aDHQ4thQEd0dlq7A/Cr8deVl5c1RxYIigL9zC2L7F8AjEA8GE8
-p/SgguMh1YQdc4acLa/KNJvxn7kjNuK8YAOdgLOaVsjh4rsUecrNIdSUtUlD
------END CERTIFICATE-----
-
-# Issuer: CN=Telia Root CA v2 O=Telia Finland Oyj
-# Subject: CN=Telia Root CA v2 O=Telia Finland Oyj
-# Label: "Telia Root CA v2"
-# Serial: 7288924052977061235122729490515358
-# MD5 Fingerprint: 0e:8f:ac:aa:82:df:85:b1:f4:dc:10:1c:fc:99:d9:48
-# SHA1 Fingerprint: b9:99:cd:d1:73:50:8a:c4:47:05:08:9c:8c:88:fb:be:a0:2b:40:cd
-# SHA256 Fingerprint: 24:2b:69:74:2f:cb:1e:5b:2a:bf:98:89:8b:94:57:21:87:54:4e:5b:4d:99:11:78:65:73:62:1f:6a:74:b8:2c
------BEGIN CERTIFICATE-----
-MIIFdDCCA1ygAwIBAgIPAWdfJ9b+euPkrL4JWwWeMA0GCSqGSIb3DQEBCwUAMEQx
-CzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZMBcGA1UE
-AwwQVGVsaWEgUm9vdCBDQSB2MjAeFw0xODExMjkxMTU1NTRaFw00MzExMjkxMTU1
-NTRaMEQxCzAJBgNVBAYTAkZJMRowGAYDVQQKDBFUZWxpYSBGaW5sYW5kIE95ajEZ
-MBcGA1UEAwwQVGVsaWEgUm9vdCBDQSB2MjCCAiIwDQYJKoZIhvcNAQEBBQADggIP
-ADCCAgoCggIBALLQPwe84nvQa5n44ndp586dpAO8gm2h/oFlH0wnrI4AuhZ76zBq
-AMCzdGh+sq/H1WKzej9Qyow2RCRj0jbpDIX2Q3bVTKFgcmfiKDOlyzG4OiIjNLh9
-vVYiQJ3q9HsDrWj8soFPmNB06o3lfc1jw6P23pLCWBnglrvFxKk9pXSW/q/5iaq9
-lRdU2HhE8Qx3FZLgmEKnpNaqIJLNwaCzlrI6hEKNfdWV5Nbb6WLEWLN5xYzTNTOD
-n3WhUidhOPFZPY5Q4L15POdslv5e2QJltI5c0BE0312/UqeBAMN/mUWZFdUXyApT
-7GPzmX3MaRKGwhfwAZ6/hLzRUssbkmbOpFPlob/E2wnW5olWK8jjfN7j/4nlNW4o
-6GwLI1GpJQXrSPjdscr6bAhR77cYbETKJuFzxokGgeWKrLDiKca5JLNrRBH0pUPC
-TEPlcDaMtjNXepUugqD0XBCzYYP2AgWGLnwtbNwDRm41k9V6lS/eINhbfpSQBGq6
-WT0EBXWdN6IOLj3rwaRSg/7Qa9RmjtzG6RJOHSpXqhC8fF6CfaamyfItufUXJ63R
-DolUK5X6wK0dmBR4M0KGCqlztft0DbcbMBnEWg4cJ7faGND/isgFuvGqHKI3t+ZI
-pEYslOqodmJHixBTB0hXbOKSTbauBcvcwUpej6w9GU7C7WB1K9vBykLVAgMBAAGj
-YzBhMB8GA1UdIwQYMBaAFHKs5DN5qkWH9v2sHZ7Wxy+G2CQ5MB0GA1UdDgQWBBRy
-rOQzeapFh/b9rB2e1scvhtgkOTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUw
-AwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAoDtZpwmUPjaE0n4vOaWWl/oRrfxn83EJ
-8rKJhGdEr7nv7ZbsnGTbMjBvZ5qsfl+yqwE2foH65IRe0qw24GtixX1LDoJt0nZi
-0f6X+J8wfBj5tFJ3gh1229MdqfDBmgC9bXXYfef6xzijnHDoRnkDry5023X4blMM
-A8iZGok1GTzTyVR8qPAs5m4HeW9q4ebqkYJpCh3DflminmtGFZhb069GHWLIzoBS
-SRE/yQQSwxN8PzuKlts8oB4KtItUsiRnDe+Cy748fdHif64W1lZYudogsYMVoe+K
-TTJvQS8TUoKU1xrBeKJR3Stwbbca+few4GeXVtt8YVMJAygCQMez2P2ccGrGKMOF
-6eLtGpOg3kuYooQ+BXcBlj37tCAPnHICehIv1aO6UXivKitEZU61/Qrowc15h2Er
-3oBXRb9n8ZuRXqWk7FlIEA04x7D6w0RtBPV4UBySllva9bguulvP5fBqnUsvWHMt
-Ty3EHD70sz+rFQ47GUGKpMFXEmZxTPpT41frYpUJnlTd0cI8Vzy9OK2YZLe4A5pT
-VmBds9hCG1xLEooc6+t9xnppxyd/pPiL8uSUZodL6ZQHCRJ5irLrdATczvREWeAW
-ysUsWNc8e89ihmpQfTU2Zqf7N+cox9jQraVplI/owd8k+BsHMYeB2F326CjYSlKA
-rBPuUBQemMc=
------END CERTIFICATE-----
-
-# Issuer: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH
-# Subject: CN=D-TRUST BR Root CA 1 2020 O=D-Trust GmbH
-# Label: "D-TRUST BR Root CA 1 2020"
-# Serial: 165870826978392376648679885835942448534
-# MD5 Fingerprint: b5:aa:4b:d5:ed:f7:e3:55:2e:8f:72:0a:f3:75:b8:ed
-# SHA1 Fingerprint: 1f:5b:98:f0:e3:b5:f7:74:3c:ed:e6:b0:36:7d:32:cd:f4:09:41:67
-# SHA256 Fingerprint: e5:9a:aa:81:60:09:c2:2b:ff:5b:25:ba:d3:7d:f3:06:f0:49:79:7c:1f:81:d8:5a:b0:89:e6:57:bd:8f:00:44
------BEGIN CERTIFICATE-----
-MIIC2zCCAmCgAwIBAgIQfMmPK4TX3+oPyWWa00tNljAKBggqhkjOPQQDAzBIMQsw
-CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
-VVNUIEJSIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTA5NDUwMFoXDTM1MDIxMTA5
-NDQ1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
-A1UEAxMZRC1UUlVTVCBCUiBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
-BAAiA2IABMbLxyjR+4T1mu9CFCDhQ2tuda38KwOE1HaTJddZO0Flax7mNCq7dPYS
-zuht56vkPE4/RAiLzRZxy7+SmfSk1zxQVFKQhYN4lGdnoxwJGT11NIXe7WB9xwy0
-QVK5buXuQqOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFHOREKv/
-VbNafAkl1bK6CKBrqx9tMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
-PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2JyX3Jvb3Rf
-Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
-dC9DTj1ELVRSVVNUJTIwQlIlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
-c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
-PQQDAwNpADBmAjEAlJAtE/rhY/hhY+ithXhUkZy4kzg+GkHaQBZTQgjKL47xPoFW
-wKrY7RjEsK70PvomAjEA8yjixtsrmfu3Ubgko6SUeho/5jbiA1czijDLgsfWFBHV
-dWNbFJWcHwHP2NVypw87
------END CERTIFICATE-----
-
-# Issuer: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH
-# Subject: CN=D-TRUST EV Root CA 1 2020 O=D-Trust GmbH
-# Label: "D-TRUST EV Root CA 1 2020"
-# Serial: 126288379621884218666039612629459926992
-# MD5 Fingerprint: 8c:2d:9d:70:9f:48:99:11:06:11:fb:e9:cb:30:c0:6e
-# SHA1 Fingerprint: 61:db:8c:21:59:69:03:90:d8:7c:9c:12:86:54:cf:9d:3d:f4:dd:07
-# SHA256 Fingerprint: 08:17:0d:1a:a3:64:53:90:1a:2f:95:92:45:e3:47:db:0c:8d:37:ab:aa:bc:56:b8:1a:a1:00:dc:95:89:70:db
------BEGIN CERTIFICATE-----
-MIIC2zCCAmCgAwIBAgIQXwJB13qHfEwDo6yWjfv/0DAKBggqhkjOPQQDAzBIMQsw
-CQYDVQQGEwJERTEVMBMGA1UEChMMRC1UcnVzdCBHbWJIMSIwIAYDVQQDExlELVRS
-VVNUIEVWIFJvb3QgQ0EgMSAyMDIwMB4XDTIwMDIxMTEwMDAwMFoXDTM1MDIxMTA5
-NTk1OVowSDELMAkGA1UEBhMCREUxFTATBgNVBAoTDEQtVHJ1c3QgR21iSDEiMCAG
-A1UEAxMZRC1UUlVTVCBFViBSb290IENBIDEgMjAyMDB2MBAGByqGSM49AgEGBSuB
-BAAiA2IABPEL3YZDIBnfl4XoIkqbz52Yv7QFJsnL46bSj8WeeHsxiamJrSc8ZRCC
-/N/DnU7wMyPE0jL1HLDfMxddxfCxivnvubcUyilKwg+pf3VlSSowZ/Rk99Yad9rD
-wpdhQntJraOCAQ0wggEJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFH8QARY3
-OqQo5FD4pPfsazK2/umLMA4GA1UdDwEB/wQEAwIBBjCBxgYDVR0fBIG+MIG7MD6g
-PKA6hjhodHRwOi8vY3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X2V2X3Jvb3Rf
-Y2FfMV8yMDIwLmNybDB5oHegdYZzbGRhcDovL2RpcmVjdG9yeS5kLXRydXN0Lm5l
-dC9DTj1ELVRSVVNUJTIwRVYlMjBSb290JTIwQ0ElMjAxJTIwMjAyMCxPPUQtVHJ1
-c3QlMjBHbWJILEM9REU/Y2VydGlmaWNhdGVyZXZvY2F0aW9ubGlzdDAKBggqhkjO
-PQQDAwNpADBmAjEAyjzGKnXCXnViOTYAYFqLwZOZzNnbQTs7h5kXO9XMT8oi96CA
-y/m0sRtW9XLS/BnRAjEAkfcwkz8QRitxpNA7RJvAKQIFskF3UfN5Wp6OFKBOQtJb
-gfM0agPnIjhQW+0ZT0MW
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc.
-# Subject: CN=DigiCert TLS ECC P384 Root G5 O=DigiCert, Inc.
-# Label: "DigiCert TLS ECC P384 Root G5"
-# Serial: 13129116028163249804115411775095713523
-# MD5 Fingerprint: d3:71:04:6a:43:1c:db:a6:59:e1:a8:a3:aa:c5:71:ed
-# SHA1 Fingerprint: 17:f3:de:5e:9f:0f:19:e9:8e:f6:1f:32:26:6e:20:c4:07:ae:30:ee
-# SHA256 Fingerprint: 01:8e:13:f0:77:25:32:cf:80:9b:d1:b1:72:81:86:72:83:fc:48:c6:e1:3b:e9:c6:98:12:85:4a:49:0c:1b:05
------BEGIN CERTIFICATE-----
-MIICGTCCAZ+gAwIBAgIQCeCTZaz32ci5PhwLBCou8zAKBggqhkjOPQQDAzBOMQsw
-CQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJjAkBgNVBAMTHURp
-Z2lDZXJ0IFRMUyBFQ0MgUDM4NCBSb290IEc1MB4XDTIxMDExNTAwMDAwMFoXDTQ2
-MDExNDIzNTk1OVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDkRpZ2lDZXJ0LCBJ
-bmMuMSYwJAYDVQQDEx1EaWdpQ2VydCBUTFMgRUNDIFAzODQgUm9vdCBHNTB2MBAG
-ByqGSM49AgEGBSuBBAAiA2IABMFEoc8Rl1Ca3iOCNQfN0MsYndLxf3c1TzvdlHJS
-7cI7+Oz6e2tYIOyZrsn8aLN1udsJ7MgT9U7GCh1mMEy7H0cKPGEQQil8pQgO4CLp
-0zVozptjn4S1mU1YoI71VOeVyaNCMEAwHQYDVR0OBBYEFMFRRVBZqz7nLFr6ICIS
-B4CIfBFqMA4GA1UdDwEB/wQEAwIBhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49
-BAMDA2gAMGUCMQCJao1H5+z8blUD2WdsJk6Dxv3J+ysTvLd6jLRl0mlpYxNjOyZQ
-LgGheQaRnUi/wr4CMEfDFXuxoJGZSZOoPHzoRgaLLPIxAJSdYsiJvRmEFOml+wG4
-DXZDjC5Ty3zfDBeWUA==
------END CERTIFICATE-----
-
-# Issuer: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc.
-# Subject: CN=DigiCert TLS RSA4096 Root G5 O=DigiCert, Inc.
-# Label: "DigiCert TLS RSA4096 Root G5"
-# Serial: 11930366277458970227240571539258396554
-# MD5 Fingerprint: ac:fe:f7:34:96:a9:f2:b3:b4:12:4b:e4:27:41:6f:e1
-# SHA1 Fingerprint: a7:88:49:dc:5d:7c:75:8c:8c:de:39:98:56:b3:aa:d0:b2:a5:71:35
-# SHA256 Fingerprint: 37:1a:00:dc:05:33:b3:72:1a:7e:eb:40:e8:41:9e:70:79:9d:2b:0a:0f:2c:1d:80:69:31:65:f7:ce:c4:ad:75
------BEGIN CERTIFICATE-----
-MIIFZjCCA06gAwIBAgIQCPm0eKj6ftpqMzeJ3nzPijANBgkqhkiG9w0BAQwFADBN
-MQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQsIEluYy4xJTAjBgNVBAMT
-HERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwHhcNMjEwMTE1MDAwMDAwWhcN
-NDYwMTE0MjM1OTU5WjBNMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORGlnaUNlcnQs
-IEluYy4xJTAjBgNVBAMTHERpZ2lDZXJ0IFRMUyBSU0E0MDk2IFJvb3QgRzUwggIi
-MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCz0PTJeRGd/fxmgefM1eS87IE+
-ajWOLrfn3q/5B03PMJ3qCQuZvWxX2hhKuHisOjmopkisLnLlvevxGs3npAOpPxG0
-2C+JFvuUAT27L/gTBaF4HI4o4EXgg/RZG5Wzrn4DReW+wkL+7vI8toUTmDKdFqgp
-wgscONyfMXdcvyej/Cestyu9dJsXLfKB2l2w4SMXPohKEiPQ6s+d3gMXsUJKoBZM
-pG2T6T867jp8nVid9E6P/DsjyG244gXazOvswzH016cpVIDPRFtMbzCe88zdH5RD
-nU1/cHAN1DrRN/BsnZvAFJNY781BOHW8EwOVfH/jXOnVDdXifBBiqmvwPXbzP6Po
-sMH976pXTayGpxi0KcEsDr9kvimM2AItzVwv8n/vFfQMFawKsPHTDU9qTXeXAaDx
-Zre3zu/O7Oyldcqs4+Fj97ihBMi8ez9dLRYiVu1ISf6nL3kwJZu6ay0/nTvEF+cd
-Lvvyz6b84xQslpghjLSR6Rlgg/IwKwZzUNWYOwbpx4oMYIwo+FKbbuH2TbsGJJvX
-KyY//SovcfXWJL5/MZ4PbeiPT02jP/816t9JXkGPhvnxd3lLG7SjXi/7RgLQZhNe
-XoVPzthwiHvOAbWWl9fNff2C+MIkwcoBOU+NosEUQB+cZtUMCUbW8tDRSHZWOkPL
-tgoRObqME2wGtZ7P6wIDAQABo0IwQDAdBgNVHQ4EFgQUUTMc7TZArxfTJc1paPKv
-TiM+s0EwDgYDVR0PAQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcN
-AQEMBQADggIBAGCmr1tfV9qJ20tQqcQjNSH/0GEwhJG3PxDPJY7Jv0Y02cEhJhxw
-GXIeo8mH/qlDZJY6yFMECrZBu8RHANmfGBg7sg7zNOok992vIGCukihfNudd5N7H
-PNtQOa27PShNlnx2xlv0wdsUpasZYgcYQF+Xkdycx6u1UQ3maVNVzDl92sURVXLF
-O4uJ+DQtpBflF+aZfTCIITfNMBc9uPK8qHWgQ9w+iUuQrm0D4ByjoJYJu32jtyoQ
-REtGBzRj7TG5BO6jm5qu5jF49OokYTurWGT/u4cnYiWB39yhL/btp/96j1EuMPik
-AdKFOV8BmZZvWltwGUb+hmA+rYAQCd05JS9Yf7vSdPD3Rh9GOUrYU9DzLjtxpdRv
-/PNn5AeP3SYZ4Y1b+qOTEZvpyDrDVWiakuFSdjjo4bq9+0/V77PnSIMx8IIh47a+
-p6tv75/fTM8BuGJqIz3nCU2AG3swpMPdB380vqQmsvZB6Akd4yCYqjdP//fx4ilw
-MUc/dNAUFvohigLVigmUdy7yWSiLfFCSCmZ4OIN1xLVaqBHG5cGdZlXPU8Sv13WF
-qUITVuwhd4GTWgzqltlJyqEI8pc7bZsEGCREjnwB8twl2F6GmrE52/WRMmrRpnCK
-ovfepEWFJqgejF0pW8hL2JpqA15w8oVPbEtoL8pU9ozaMv7Da4M/OMZ+
------END CERTIFICATE-----
-
-# Issuer: CN=Certainly Root R1 O=Certainly
-# Subject: CN=Certainly Root R1 O=Certainly
-# Label: "Certainly Root R1"
-# Serial: 188833316161142517227353805653483829216
-# MD5 Fingerprint: 07:70:d4:3e:82:87:a0:fa:33:36:13:f4:fa:33:e7:12
-# SHA1 Fingerprint: a0:50:ee:0f:28:71:f4:27:b2:12:6d:6f:50:96:25:ba:cc:86:42:af
-# SHA256 Fingerprint: 77:b8:2c:d8:64:4c:43:05:f7:ac:c5:cb:15:6b:45:67:50:04:03:3d:51:c6:0c:62:02:a8:e0:c3:34:67:d3:a0
------BEGIN CERTIFICATE-----
-MIIFRzCCAy+gAwIBAgIRAI4P+UuQcWhlM1T01EQ5t+AwDQYJKoZIhvcNAQELBQAw
-PTELMAkGA1UEBhMCVVMxEjAQBgNVBAoTCUNlcnRhaW5seTEaMBgGA1UEAxMRQ2Vy
-dGFpbmx5IFJvb3QgUjEwHhcNMjEwNDAxMDAwMDAwWhcNNDYwNDAxMDAwMDAwWjA9
-MQswCQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0
-YWlubHkgUm9vdCBSMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANA2
-1B/q3avk0bbm+yLA3RMNansiExyXPGhjZjKcA7WNpIGD2ngwEc/csiu+kr+O5MQT
-vqRoTNoCaBZ0vrLdBORrKt03H2As2/X3oXyVtwxwhi7xOu9S98zTm/mLvg7fMbed
-aFySpvXl8wo0tf97ouSHocavFwDvA5HtqRxOcT3Si2yJ9HiG5mpJoM610rCrm/b0
-1C7jcvk2xusVtyWMOvwlDbMicyF0yEqWYZL1LwsYpfSt4u5BvQF5+paMjRcCMLT5
-r3gajLQ2EBAHBXDQ9DGQilHFhiZ5shGIXsXwClTNSaa/ApzSRKft43jvRl5tcdF5
-cBxGX1HpyTfcX35pe0HfNEXgO4T0oYoKNp43zGJS4YkNKPl6I7ENPT2a/Z2B7yyQ
-wHtETrtJ4A5KVpK8y7XdeReJkd5hiXSSqOMyhb5OhaRLWcsrxXiOcVTQAjeZjOVJ
-6uBUcqQRBi8LjMFbvrWhsFNunLhgkR9Za/kt9JQKl7XsxXYDVBtlUrpMklZRNaBA
-2CnbrlJ2Oy0wQJuK0EJWtLeIAaSHO1OWzaMWj/Nmqhexx2DgwUMFDO6bW2BvBlyH
-Wyf5QBGenDPBt+U1VwV/J84XIIwc/PH72jEpSe31C4SnT8H2TsIonPru4K8H+zMR
-eiFPCyEQtkA6qyI6BJyLm4SGcprSp6XEtHWRqSsjAgMBAAGjQjBAMA4GA1UdDwEB
-/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBTgqj8ljZ9EXME66C6u
-d0yEPmcM9DANBgkqhkiG9w0BAQsFAAOCAgEAuVevuBLaV4OPaAszHQNTVfSVcOQr
-PbA56/qJYv331hgELyE03fFo8NWWWt7CgKPBjcZq91l3rhVkz1t5BXdm6ozTaw3d
-8VkswTOlMIAVRQdFGjEitpIAq5lNOo93r6kiyi9jyhXWx8bwPWz8HA2YEGGeEaIi
-1wrykXprOQ4vMMM2SZ/g6Q8CRFA3lFV96p/2O7qUpUzpvD5RtOjKkjZUbVwlKNrd
-rRT90+7iIgXr0PK3aBLXWopBGsaSpVo7Y0VPv+E6dyIvXL9G+VoDhRNCX8reU9di
-taY1BMJH/5n9hN9czulegChB8n3nHpDYT3Y+gjwN/KUD+nsa2UUeYNrEjvn8K8l7
-lcUq/6qJ34IxD3L/DCfXCh5WAFAeDJDBlrXYFIW7pw0WwfgHJBu6haEaBQmAupVj
-yTrsJZ9/nbqkRxWbRHDxakvWOF5D8xh+UG7pWijmZeZ3Gzr9Hb4DJqPb1OG7fpYn
-Kx3upPvaJVQTA945xsMfTZDsjxtK0hzthZU4UHlG1sGQUDGpXJpuHfUzVounmdLy
-yCwzk5Iwx06MZTMQZBf9JBeW0Y3COmor6xOLRPIh80oat3df1+2IpHLlOR+Vnb5n
-wXARPbv0+Em34yaXOp/SX3z7wJl8OSngex2/DaeP0ik0biQVy96QXr8axGbqwua6
-OV+KmalBWQewLK8=
------END CERTIFICATE-----
-
-# Issuer: CN=Certainly Root E1 O=Certainly
-# Subject: CN=Certainly Root E1 O=Certainly
-# Label: "Certainly Root E1"
-# Serial: 8168531406727139161245376702891150584
-# MD5 Fingerprint: 0a:9e:ca:cd:3e:52:50:c6:36:f3:4b:a3:ed:a7:53:e9
-# SHA1 Fingerprint: f9:e1:6d:dc:01:89:cf:d5:82:45:63:3e:c5:37:7d:c2:eb:93:6f:2b
-# SHA256 Fingerprint: b4:58:5f:22:e4:ac:75:6a:4e:86:12:a1:36:1c:5d:9d:03:1a:93:fd:84:fe:bb:77:8f:a3:06:8b:0f:c4:2d:c2
------BEGIN CERTIFICATE-----
-MIIB9zCCAX2gAwIBAgIQBiUzsUcDMydc+Y2aub/M+DAKBggqhkjOPQQDAzA9MQsw
-CQYDVQQGEwJVUzESMBAGA1UEChMJQ2VydGFpbmx5MRowGAYDVQQDExFDZXJ0YWlu
-bHkgUm9vdCBFMTAeFw0yMTA0MDEwMDAwMDBaFw00NjA0MDEwMDAwMDBaMD0xCzAJ
-BgNVBAYTAlVTMRIwEAYDVQQKEwlDZXJ0YWlubHkxGjAYBgNVBAMTEUNlcnRhaW5s
-eSBSb290IEUxMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE3m/4fxzf7flHh4axpMCK
-+IKXgOqPyEpeKn2IaKcBYhSRJHpcnqMXfYqGITQYUBsQ3tA3SybHGWCA6TS9YBk2
-QNYphwk8kXr2vBMj3VlOBF7PyAIcGFPBMdjaIOlEjeR2o0IwQDAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU8ygYy2R17ikq6+2uI1g4
-hevIIgcwCgYIKoZIzj0EAwMDaAAwZQIxALGOWiDDshliTd6wT99u0nCK8Z9+aozm
-ut6Dacpps6kFtZaSF4fC0urQe87YQVt8rgIwRt7qy12a7DLCZRawTDBcMPPaTnOG
-BtjOiQRINzf43TNRnXCve1XYAS59BWQOhriR
------END CERTIFICATE-----
-
-# Issuer: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD.
-# Subject: CN=Security Communication RootCA3 O=SECOM Trust Systems CO.,LTD.
-# Label: "Security Communication RootCA3"
-# Serial: 16247922307909811815
-# MD5 Fingerprint: 1c:9a:16:ff:9e:5c:e0:4d:8a:14:01:f4:35:5d:29:26
-# SHA1 Fingerprint: c3:03:c8:22:74:92:e5:61:a2:9c:5f:79:91:2b:1e:44:13:91:30:3a
-# SHA256 Fingerprint: 24:a5:5c:2a:b0:51:44:2d:06:17:76:65:41:23:9a:4a:d0:32:d7:c5:51:75:aa:34:ff:de:2f:bc:4f:5c:52:94
------BEGIN CERTIFICATE-----
-MIIFfzCCA2egAwIBAgIJAOF8N0D9G/5nMA0GCSqGSIb3DQEBDAUAMF0xCzAJBgNV
-BAYTAkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMScw
-JQYDVQQDEx5TZWN1cml0eSBDb21tdW5pY2F0aW9uIFJvb3RDQTMwHhcNMTYwNjE2
-MDYxNzE2WhcNMzgwMTE4MDYxNzE2WjBdMQswCQYDVQQGEwJKUDElMCMGA1UEChMc
-U0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UEAxMeU2VjdXJpdHkg
-Q29tbXVuaWNhdGlvbiBSb290Q0EzMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIIC
-CgKCAgEA48lySfcw3gl8qUCBWNO0Ot26YQ+TUG5pPDXC7ltzkBtnTCHsXzW7OT4r
-CmDvu20rhvtxosis5FaU+cmvsXLUIKx00rgVrVH+hXShuRD+BYD5UpOzQD11EKzA
-lrenfna84xtSGc4RHwsENPXY9Wk8d/Nk9A2qhd7gCVAEF5aEt8iKvE1y/By7z/MG
-TfmfZPd+pmaGNXHIEYBMwXFAWB6+oHP2/D5Q4eAvJj1+XCO1eXDe+uDRpdYMQXF7
-9+qMHIjH7Iv10S9VlkZ8WjtYO/u62C21Jdp6Ts9EriGmnpjKIG58u4iFW/vAEGK7
-8vknR+/RiTlDxN/e4UG/VHMgly1s2vPUB6PmudhvrvyMGS7TZ2crldtYXLVqAvO4
-g160a75BflcJdURQVc1aEWEhCmHCqYj9E7wtiS/NYeCVvsq1e+F7NGcLH7YMx3we
-GVPKp7FKFSBWFHA9K4IsD50VHUeAR/94mQ4xr28+j+2GaR57GIgUssL8gjMunEst
-+3A7caoreyYn8xrC3PsXuKHqy6C0rtOUfnrQq8PsOC0RLoi/1D+tEjtCrI8Cbn3M
-0V9hvqG8OmpI6iZVIhZdXw3/JzOfGAN0iltSIEdrRU0id4xVJ/CvHozJgyJUt5rQ
-T9nO/NkuHJYosQLTA70lUhw0Zk8jq/R3gpYd0VcwCBEF/VfR2ccCAwEAAaNCMEAw
-HQYDVR0OBBYEFGQUfPxYchamCik0FW8qy7z8r6irMA4GA1UdDwEB/wQEAwIBBjAP
-BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDAUAA4ICAQDcAiMI4u8hOscNtybS
-YpOnpSNyByCCYN8Y11StaSWSntkUz5m5UoHPrmyKO1o5yGwBQ8IibQLwYs1OY0PA
-FNr0Y/Dq9HHuTofjcan0yVflLl8cebsjqodEV+m9NU1Bu0soo5iyG9kLFwfl9+qd
-9XbXv8S2gVj/yP9kaWJ5rW4OH3/uHWnlt3Jxs/6lATWUVCvAUm2PVcTJ0rjLyjQI
-UYWg9by0F1jqClx6vWPGOi//lkkZhOpn2ASxYfQAW0q3nHE3GYV5v4GwxxMOdnE+
-OoAGrgYWp421wsTL/0ClXI2lyTrtcoHKXJg80jQDdwj98ClZXSEIx2C/pHF7uNke
-gr4Jr2VvKKu/S7XuPghHJ6APbw+LP6yVGPO5DtxnVW5inkYO0QR4ynKudtml+LLf
-iAlhi+8kTtFZP1rUPcmTPCtk9YENFpb3ksP+MW/oKjJ0DvRMmEoYDjBU1cXrvMUV
-nuiZIesnKwkK2/HmcBhWuwzkvvnoEKQTkrgc4NtnHVMDpCKn3F2SEDzq//wbEBrD
-2NCcnWXL0CsnMQMeNuE9dnUM/0Umud1RvCPHX9jYhxBAEg09ODfnRDwYwFMJZI//
-1ZqmfHAuc1Uh6N//g7kdPjIe1qZ9LPFm6Vwdp6POXiUyK+OVrCoHzrQoeIY8Laad
-TdJ0MN1kURXbg4NR16/9M51NZg==
------END CERTIFICATE-----
-
-# Issuer: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD.
-# Subject: CN=Security Communication ECC RootCA1 O=SECOM Trust Systems CO.,LTD.
-# Label: "Security Communication ECC RootCA1"
-# Serial: 15446673492073852651
-# MD5 Fingerprint: 7e:43:b0:92:68:ec:05:43:4c:98:ab:5d:35:2e:7e:86
-# SHA1 Fingerprint: b8:0e:26:a9:bf:d2:b2:3b:c0:ef:46:c9:ba:c7:bb:f6:1d:0d:41:41
-# SHA256 Fingerprint: e7:4f:bd:a5:5b:d5:64:c4:73:a3:6b:44:1a:a7:99:c8:a6:8e:07:74:40:e8:28:8b:9f:a1:e5:0e:4b:ba:ca:11
------BEGIN CERTIFICATE-----
-MIICODCCAb6gAwIBAgIJANZdm7N4gS7rMAoGCCqGSM49BAMDMGExCzAJBgNVBAYT
-AkpQMSUwIwYDVQQKExxTRUNPTSBUcnVzdCBTeXN0ZW1zIENPLixMVEQuMSswKQYD
-VQQDEyJTZWN1cml0eSBDb21tdW5pY2F0aW9uIEVDQyBSb290Q0ExMB4XDTE2MDYx
-NjA1MTUyOFoXDTM4MDExODA1MTUyOFowYTELMAkGA1UEBhMCSlAxJTAjBgNVBAoT
-HFNFQ09NIFRydXN0IFN5c3RlbXMgQ08uLExURC4xKzApBgNVBAMTIlNlY3VyaXR5
-IENvbW11bmljYXRpb24gRUNDIFJvb3RDQTEwdjAQBgcqhkjOPQIBBgUrgQQAIgNi
-AASkpW9gAwPDvTH00xecK4R1rOX9PVdu12O/5gSJko6BnOPpR27KkBLIE+Cnnfdl
-dB9sELLo5OnvbYUymUSxXv3MdhDYW72ixvnWQuRXdtyQwjWpS4g8EkdtXP9JTxpK
-ULGjQjBAMB0GA1UdDgQWBBSGHOf+LaVKiwj+KBH6vqNm+GBZLzAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjAVXUI9/Lbu
-9zuxNuie9sRGKEkz0FhDKmMpzE2xtHqiuQ04pV1IKv3LsnNdo4gIxwwCMQDAqy0O
-be0YottT6SXbVQjgUMzfRGEWgqtJsLKB7HOHeLRMsmIbEvoWTSVLY70eN9k=
------END CERTIFICATE-----
-
-# Issuer: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY
-# Subject: CN=BJCA Global Root CA1 O=BEIJING CERTIFICATE AUTHORITY
-# Label: "BJCA Global Root CA1"
-# Serial: 113562791157148395269083148143378328608
-# MD5 Fingerprint: 42:32:99:76:43:33:36:24:35:07:82:9b:28:f9:d0:90
-# SHA1 Fingerprint: d5:ec:8d:7b:4c:ba:79:f4:e7:e8:cb:9d:6b:ae:77:83:10:03:21:6a
-# SHA256 Fingerprint: f3:89:6f:88:fe:7c:0a:88:27:66:a7:fa:6a:d2:74:9f:b5:7a:7f:3e:98:fb:76:9c:1f:a7:b0:9c:2c:44:d5:ae
------BEGIN CERTIFICATE-----
-MIIFdDCCA1ygAwIBAgIQVW9l47TZkGobCdFsPsBsIDANBgkqhkiG9w0BAQsFADBU
-MQswCQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRI
-T1JJVFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0ExMB4XDTE5MTIxOTAz
-MTYxN1oXDTQ0MTIxMjAzMTYxN1owVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJF
-SUpJTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2Jh
-bCBSb290IENBMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAPFmCL3Z
-xRVhy4QEQaVpN3cdwbB7+sN3SJATcmTRuHyQNZ0YeYjjlwE8R4HyDqKYDZ4/N+AZ
-spDyRhySsTphzvq3Rp4Dhtczbu33RYx2N95ulpH3134rhxfVizXuhJFyV9xgw8O5
-58dnJCNPYwpj9mZ9S1WnP3hkSWkSl+BMDdMJoDIwOvqfwPKcxRIqLhy1BDPapDgR
-at7GGPZHOiJBhyL8xIkoVNiMpTAK+BcWyqw3/XmnkRd4OJmtWO2y3syJfQOcs4ll
-5+M7sSKGjwZteAf9kRJ/sGsciQ35uMt0WwfCyPQ10WRjeulumijWML3mG90Vr4Tq
-nMfK9Q7q8l0ph49pczm+LiRvRSGsxdRpJQaDrXpIhRMsDQa4bHlW/KNnMoH1V6XK
-V0Jp6VwkYe/iMBhORJhVb3rCk9gZtt58R4oRTklH2yiUAguUSiz5EtBP6DF+bHq/
-pj+bOT0CFqMYs2esWz8sgytnOYFcuX6U1WTdno9uruh8W7TXakdI136z1C2OVnZO
-z2nxbkRs1CTqjSShGL+9V/6pmTW12xB3uD1IutbB5/EjPtffhZ0nPNRAvQoMvfXn
-jSXWgXSHRtQpdaJCbPdzied9v3pKH9MiyRVVz99vfFXQpIsHETdfg6YmV6YBW37+
-WGgHqel62bno/1Afq8K0wM7o6v0PvY1NuLxxAgMBAAGjQjBAMB0GA1UdDgQWBBTF
-7+3M2I0hxkjk49cULqcWk+WYATAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjANBgkqhkiG9w0BAQsFAAOCAgEAUoKsITQfI/Ki2Pm4rzc2IInRNwPWaZ+4
-YRC6ojGYWUfo0Q0lHhVBDOAqVdVXUsv45Mdpox1NcQJeXyFFYEhcCY5JEMEE3Kli
-awLwQ8hOnThJdMkycFRtwUf8jrQ2ntScvd0g1lPJGKm1Vrl2i5VnZu69mP6u775u
-+2D2/VnGKhs/I0qUJDAnyIm860Qkmss9vk/Ves6OF8tiwdneHg56/0OGNFK8YT88
-X7vZdrRTvJez/opMEi4r89fO4aL/3Xtw+zuhTaRjAv04l5U/BXCga99igUOLtFkN
-SoxUnMW7gZ/NfaXvCyUeOiDbHPwfmGcCCtRzRBPbUYQaVQNW4AB+dAb/OMRyHdOo
-P2gxXdMJxy6MW2Pg6Nwe0uxhHvLe5e/2mXZgLR6UcnHGCyoyx5JO1UbXHfmpGQrI
-+pXObSOYqgs4rZpWDW+N8TEAiMEXnM0ZNjX+VVOg4DwzX5Ze4jLp3zO7Bkqp2IRz
-znfSxqxx4VyjHQy7Ct9f4qNx2No3WqB4K/TUfet27fJhcKVlmtOJNBir+3I+17Q9
-eVzYH6Eze9mCUAyTF6ps3MKCuwJXNq+YJyo5UOGwifUll35HaBC07HPKs5fRJNz2
-YqAo07WjuGS3iGJCz51TzZm+ZGiPTx4SSPfSKcOYKMryMguTjClPPGAyzQWWYezy
-r/6zcCwupvI=
------END CERTIFICATE-----
-
-# Issuer: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY
-# Subject: CN=BJCA Global Root CA2 O=BEIJING CERTIFICATE AUTHORITY
-# Label: "BJCA Global Root CA2"
-# Serial: 58605626836079930195615843123109055211
-# MD5 Fingerprint: 5e:0a:f6:47:5f:a6:14:e8:11:01:95:3f:4d:01:eb:3c
-# SHA1 Fingerprint: f4:27:86:eb:6e:b8:6d:88:31:67:02:fb:ba:66:a4:53:00:aa:7a:a6
-# SHA256 Fingerprint: 57:4d:f6:93:1e:27:80:39:66:7b:72:0a:fd:c1:60:0f:c2:7e:b6:6d:d3:09:29:79:fb:73:85:64:87:21:28:82
------BEGIN CERTIFICATE-----
-MIICJTCCAaugAwIBAgIQLBcIfWQqwP6FGFkGz7RK6zAKBggqhkjOPQQDAzBUMQsw
-CQYDVQQGEwJDTjEmMCQGA1UECgwdQkVJSklORyBDRVJUSUZJQ0FURSBBVVRIT1JJ
-VFkxHTAbBgNVBAMMFEJKQ0EgR2xvYmFsIFJvb3QgQ0EyMB4XDTE5MTIxOTAzMTgy
-MVoXDTQ0MTIxMjAzMTgyMVowVDELMAkGA1UEBhMCQ04xJjAkBgNVBAoMHUJFSUpJ
-TkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZMR0wGwYDVQQDDBRCSkNBIEdsb2JhbCBS
-b290IENBMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABJ3LgJGNU2e1uVCxA/jlSR9B
-IgmwUVJY1is0j8USRhTFiy8shP8sbqjV8QnjAyEUxEM9fMEsxEtqSs3ph+B99iK+
-+kpRuDCK/eHeGBIK9ke35xe/J4rUQUyWPGCWwf0VHKNCMEAwHQYDVR0OBBYEFNJK
-sVF/BvDRgh9Obl+rg/xI1LCRMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
-AgEGMAoGCCqGSM49BAMDA2gAMGUCMBq8W9f+qdJUDkpd0m2xQNz0Q9XSSpkZElaA
-94M04TVOSG0ED1cxMDAtsaqdAzjbBgIxAMvMh1PLet8gUXOQwKhbYdDFUDn9hf7B
-43j4ptZLvZuHjw/l1lOWqzzIQNph91Oj9w==
------END CERTIFICATE-----
-
-# Issuer: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited
-# Subject: CN=Sectigo Public Server Authentication Root E46 O=Sectigo Limited
-# Label: "Sectigo Public Server Authentication Root E46"
-# Serial: 88989738453351742415770396670917916916
-# MD5 Fingerprint: 28:23:f8:b2:98:5c:37:16:3b:3e:46:13:4e:b0:b3:01
-# SHA1 Fingerprint: ec:8a:39:6c:40:f0:2e:bc:42:75:d4:9f:ab:1c:1a:5b:67:be:d2:9a
-# SHA256 Fingerprint: c9:0f:26:f0:fb:1b:40:18:b2:22:27:51:9b:5c:a2:b5:3e:2c:a5:b3:be:5c:f1:8e:fe:1b:ef:47:38:0c:53:83
------BEGIN CERTIFICATE-----
-MIICOjCCAcGgAwIBAgIQQvLM2htpN0RfFf51KBC49DAKBggqhkjOPQQDAzBfMQsw
-CQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1T
-ZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwHhcN
-MjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEYMBYG
-A1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1YmxpYyBT
-ZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBFNDYwdjAQBgcqhkjOPQIBBgUrgQQA
-IgNiAAR2+pmpbiDt+dd34wc7qNs9Xzjoq1WmVk/WSOrsfy2qw7LFeeyZYX8QeccC
-WvkEN/U0NSt3zn8gj1KjAIns1aeibVvjS5KToID1AZTc8GgHHs3u/iVStSBDHBv+
-6xnOQ6OjQjBAMB0GA1UdDgQWBBTRItpMWfFLXyY4qp3W7usNw/upYTAOBgNVHQ8B
-Af8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNnADBkAjAn7qRa
-qCG76UeXlImldCBteU/IvZNeWBj7LRoAasm4PdCkT0RHlAFWovgzJQxC36oCMB3q
-4S6ILuH5px0CMk7yn2xVdOOurvulGu7t0vzCAxHrRVxgED1cf5kDW21USAGKcw==
------END CERTIFICATE-----
-
-# Issuer: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited
-# Subject: CN=Sectigo Public Server Authentication Root R46 O=Sectigo Limited
-# Label: "Sectigo Public Server Authentication Root R46"
-# Serial: 156256931880233212765902055439220583700
-# MD5 Fingerprint: 32:10:09:52:00:d5:7e:6c:43:df:15:c0:b1:16:93:e5
-# SHA1 Fingerprint: ad:98:f9:f3:e4:7d:75:3b:65:d4:82:b3:a4:52:17:bb:6e:f5:e4:38
-# SHA256 Fingerprint: 7b:b6:47:a6:2a:ee:ac:88:bf:25:7a:a5:22:d0:1f:fe:a3:95:e0:ab:45:c7:3f:93:f6:56:54:ec:38:f2:5a:06
------BEGIN CERTIFICATE-----
-MIIFijCCA3KgAwIBAgIQdY39i658BwD6qSWn4cetFDANBgkqhkiG9w0BAQwFADBf
-MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQD
-Ey1TZWN0aWdvIFB1YmxpYyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYw
-HhcNMjEwMzIyMDAwMDAwWhcNNDYwMzIxMjM1OTU5WjBfMQswCQYDVQQGEwJHQjEY
-MBYGA1UEChMPU2VjdGlnbyBMaW1pdGVkMTYwNAYDVQQDEy1TZWN0aWdvIFB1Ymxp
-YyBTZXJ2ZXIgQXV0aGVudGljYXRpb24gUm9vdCBSNDYwggIiMA0GCSqGSIb3DQEB
-AQUAA4ICDwAwggIKAoICAQCTvtU2UnXYASOgHEdCSe5jtrch/cSV1UgrJnwUUxDa
-ef0rty2k1Cz66jLdScK5vQ9IPXtamFSvnl0xdE8H/FAh3aTPaE8bEmNtJZlMKpnz
-SDBh+oF8HqcIStw+KxwfGExxqjWMrfhu6DtK2eWUAtaJhBOqbchPM8xQljeSM9xf
-iOefVNlI8JhD1mb9nxc4Q8UBUQvX4yMPFF1bFOdLvt30yNoDN9HWOaEhUTCDsG3X
-ME6WW5HwcCSrv0WBZEMNvSE6Lzzpng3LILVCJ8zab5vuZDCQOc2TZYEhMbUjUDM3
-IuM47fgxMMxF/mL50V0yeUKH32rMVhlATc6qu/m1dkmU8Sf4kaWD5QazYw6A3OAS
-VYCmO2a0OYctyPDQ0RTp5A1NDvZdV3LFOxxHVp3i1fuBYYzMTYCQNFu31xR13NgE
-SJ/AwSiItOkcyqex8Va3e0lMWeUgFaiEAin6OJRpmkkGj80feRQXEgyDet4fsZfu
-+Zd4KKTIRJLpfSYFplhym3kT2BFfrsU4YjRosoYwjviQYZ4ybPUHNs2iTG7sijbt
-8uaZFURww3y8nDnAtOFr94MlI1fZEoDlSfB1D++N6xybVCi0ITz8fAr/73trdf+L
-HaAZBav6+CuBQug4urv7qv094PPK306Xlynt8xhW6aWWrL3DkJiy4Pmi1KZHQ3xt
-zwIDAQABo0IwQDAdBgNVHQ4EFgQUVnNYZJX5khqwEioEYnmhQBWIIUkwDgYDVR0P
-AQH/BAQDAgGGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEMBQADggIBAC9c
-mTz8Bl6MlC5w6tIyMY208FHVvArzZJ8HXtXBc2hkeqK5Duj5XYUtqDdFqij0lgVQ
-YKlJfp/imTYpE0RHap1VIDzYm/EDMrraQKFz6oOht0SmDpkBm+S8f74TlH7Kph52
-gDY9hAaLMyZlbcp+nv4fjFg4exqDsQ+8FxG75gbMY/qB8oFM2gsQa6H61SilzwZA
-Fv97fRheORKkU55+MkIQpiGRqRxOF3yEvJ+M0ejf5lG5Nkc/kLnHvALcWxxPDkjB
-JYOcCj+esQMzEhonrPcibCTRAUH4WAP+JWgiH5paPHxsnnVI84HxZmduTILA7rpX
-DhjvLpr3Etiga+kFpaHpaPi8TD8SHkXoUsCjvxInebnMMTzD9joiFgOgyY9mpFui
-TdaBJQbpdqQACj7LzTWb4OE4y2BThihCQRxEV+ioratF4yUQvNs+ZUH7G6aXD+u5
-dHn5HrwdVw1Hr8Mvn4dGp+smWg9WY7ViYG4A++MnESLn/pmPNPW56MORcr3Ywx65
-LvKRRFHQV80MNNVIIb/bE/FmJUNS0nAiNs2fxBx1IK1jcmMGDw4nztJqDby1ORrp
-0XZ60Vzk50lJLVU3aPAaOpg+VBeHVOmmJ1CJeyAvP/+/oYtKR5j/K3tJPsMpRmAY
-QqszKbrAKbkTidOIijlBO8n9pu0f9GBj39ItVQGL
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation
-# Subject: CN=SSL.com TLS RSA Root CA 2022 O=SSL Corporation
-# Label: "SSL.com TLS RSA Root CA 2022"
-# Serial: 148535279242832292258835760425842727825
-# MD5 Fingerprint: d8:4e:c6:59:30:d8:fe:a0:d6:7a:5a:2c:2c:69:78:da
-# SHA1 Fingerprint: ec:2c:83:40:72:af:26:95:10:ff:0e:f2:03:ee:31:70:f6:78:9d:ca
-# SHA256 Fingerprint: 8f:af:7d:2e:2c:b4:70:9b:b8:e0:b3:36:66:bf:75:a5:dd:45:b5:de:48:0f:8e:a8:d4:bf:e6:be:bc:17:f2:ed
------BEGIN CERTIFICATE-----
-MIIFiTCCA3GgAwIBAgIQb77arXO9CEDii02+1PdbkTANBgkqhkiG9w0BAQsFADBO
-MQswCQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQD
-DBxTU0wuY29tIFRMUyBSU0EgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzQyMloX
-DTQ2MDgxOTE2MzQyMVowTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jw
-b3JhdGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgUlNBIFJvb3QgQ0EgMjAyMjCC
-AiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANCkCXJPQIgSYT41I57u9nTP
-L3tYPc48DRAokC+X94xI2KDYJbFMsBFMF3NQ0CJKY7uB0ylu1bUJPiYYf7ISf5OY
-t6/wNr/y7hienDtSxUcZXXTzZGbVXcdotL8bHAajvI9AI7YexoS9UcQbOcGV0ins
-S657Lb85/bRi3pZ7QcacoOAGcvvwB5cJOYF0r/c0WRFXCsJbwST0MXMwgsadugL3
-PnxEX4MN8/HdIGkWCVDi1FW24IBydm5MR7d1VVm0U3TZlMZBrViKMWYPHqIbKUBO
-L9975hYsLfy/7PO0+r4Y9ptJ1O4Fbtk085zx7AGL0SDGD6C1vBdOSHtRwvzpXGk3
-R2azaPgVKPC506QVzFpPulJwoxJF3ca6TvvC0PeoUidtbnm1jPx7jMEWTO6Af77w
-dr5BUxIzrlo4QqvXDz5BjXYHMtWrifZOZ9mxQnUjbvPNQrL8VfVThxc7wDNY8VLS
-+YCk8OjwO4s4zKTGkH8PnP2L0aPP2oOnaclQNtVcBdIKQXTbYxE3waWglksejBYS
-d66UNHsef8JmAOSqg+qKkK3ONkRN0VHpvB/zagX9wHQfJRlAUW7qglFA35u5CCoG
-AtUjHBPW6dvbxrB6y3snm/vg1UYk7RBLY0ulBY+6uB0rpvqR4pJSvezrZ5dtmi2f
-gTIFZzL7SAg/2SW4BCUvAgMBAAGjYzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0j
-BBgwFoAU+y437uOEeicuzRk1sTN8/9REQrkwHQYDVR0OBBYEFPsuN+7jhHonLs0Z
-NbEzfP/UREK5MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAjYlt
-hEUY8U+zoO9opMAdrDC8Z2awms22qyIZZtM7QbUQnRC6cm4pJCAcAZli05bg4vsM
-QtfhWsSWTVTNj8pDU/0quOr4ZcoBwq1gaAafORpR2eCNJvkLTqVTJXojpBzOCBvf
-R4iyrT7gJ4eLSYwfqUdYe5byiB0YrrPRpgqU+tvT5TgKa3kSM/tKWTcWQA673vWJ
-DPFs0/dRa1419dvAJuoSc06pkZCmF8NsLzjUo3KUQyxi4U5cMj29TH0ZR6LDSeeW
-P4+a0zvkEdiLA9z2tmBVGKaBUfPhqBVq6+AL8BQx1rmMRTqoENjwuSfr98t67wVy
-lrXEj5ZzxOhWc5y8aVFjvO9nHEMaX3cZHxj4HCUp+UmZKbaSPaKDN7EgkaibMOlq
-bLQjk2UEqxHzDh1TJElTHaE/nUiSEeJ9DU/1172iWD54nR4fK/4huxoTtrEoZP2w
-AgDHbICivRZQIA9ygV/MlP+7mea6kMvq+cYMwq7FGc4zoWtcu358NFcXrfA/rs3q
-r5nsLFR+jM4uElZI7xc7P0peYNLcdDa8pUNjyw9bowJWCZ4kLOGGgYz+qxcs+sji
-Mho6/4UIyYOf8kpIEFR3N+2ivEC+5BB09+Rbu7nzifmPQdjH5FCQNYA+HLhNkNPU
-98OwoX6EyneSMSy4kLGCenROmxMmtNVQZlR4rmA=
------END CERTIFICATE-----
-
-# Issuer: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation
-# Subject: CN=SSL.com TLS ECC Root CA 2022 O=SSL Corporation
-# Label: "SSL.com TLS ECC Root CA 2022"
-# Serial: 26605119622390491762507526719404364228
-# MD5 Fingerprint: 99:d7:5c:f1:51:36:cc:e9:ce:d9:19:2e:77:71:56:c5
-# SHA1 Fingerprint: 9f:5f:d9:1a:54:6d:f5:0c:71:f0:ee:7a:bd:17:49:98:84:73:e2:39
-# SHA256 Fingerprint: c3:2f:fd:9f:46:f9:36:d1:6c:36:73:99:09:59:43:4b:9a:d6:0a:af:bb:9e:7c:f3:36:54:f1:44:cc:1b:a1:43
------BEGIN CERTIFICATE-----
-MIICOjCCAcCgAwIBAgIQFAP1q/s3ixdAW+JDsqXRxDAKBggqhkjOPQQDAzBOMQsw
-CQYDVQQGEwJVUzEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMSUwIwYDVQQDDBxT
-U0wuY29tIFRMUyBFQ0MgUm9vdCBDQSAyMDIyMB4XDTIyMDgyNTE2MzM0OFoXDTQ2
-MDgxOTE2MzM0N1owTjELMAkGA1UEBhMCVVMxGDAWBgNVBAoMD1NTTCBDb3Jwb3Jh
-dGlvbjElMCMGA1UEAwwcU1NMLmNvbSBUTFMgRUNDIFJvb3QgQ0EgMjAyMjB2MBAG
-ByqGSM49AgEGBSuBBAAiA2IABEUpNXP6wrgjzhR9qLFNoFs27iosU8NgCTWyJGYm
-acCzldZdkkAZDsalE3D07xJRKF3nzL35PIXBz5SQySvOkkJYWWf9lCcQZIxPBLFN
-SeR7T5v15wj4A4j3p8OSSxlUgaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSME
-GDAWgBSJjy+j6CugFFR781a4Jl9nOAuc0DAdBgNVHQ4EFgQUiY8vo+groBRUe/NW
-uCZfZzgLnNAwDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMDA2gAMGUCMFXjIlbp
-15IkWE8elDIPDAI2wv2sdDJO4fscgIijzPvX6yv/N33w7deedWo1dlJF4AIxAMeN
-b0Igj762TVntd00pxCAgRWSGOlDGxK0tk/UYfXLtqc/ErFc2KAhl3zx5Zn6g6g==
------END CERTIFICATE-----
-
-# Issuer: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos
-# Subject: CN=Atos TrustedRoot Root CA ECC TLS 2021 O=Atos
-# Label: "Atos TrustedRoot Root CA ECC TLS 2021"
-# Serial: 81873346711060652204712539181482831616
-# MD5 Fingerprint: 16:9f:ad:f1:70:ad:79:d6:ed:29:b4:d1:c5:79:70:a8
-# SHA1 Fingerprint: 9e:bc:75:10:42:b3:02:f3:81:f4:f7:30:62:d4:8f:c3:a7:51:b2:dd
-# SHA256 Fingerprint: b2:fa:e5:3e:14:cc:d7:ab:92:12:06:47:01:ae:27:9c:1d:89:88:fa:cb:77:5f:a8:a0:08:91:4e:66:39:88:a8
------BEGIN CERTIFICATE-----
-MIICFTCCAZugAwIBAgIQPZg7pmY9kGP3fiZXOATvADAKBggqhkjOPQQDAzBMMS4w
-LAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgRUNDIFRMUyAyMDIxMQ0w
-CwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTI2MjNaFw00MTA0
-MTcwOTI2MjJaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBDQSBF
-Q0MgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMHYwEAYHKoZI
-zj0CAQYFK4EEACIDYgAEloZYKDcKZ9Cg3iQZGeHkBQcfl+3oZIK59sRxUM6KDP/X
-tXa7oWyTbIOiaG6l2b4siJVBzV3dscqDY4PMwL502eCdpO5KTlbgmClBk1IQ1SQ4
-AjJn8ZQSb+/Xxd4u/RmAo0IwQDAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBR2
-KCXWfeBmmnoJsmo7jjPXNtNPojAOBgNVHQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMD
-aAAwZQIwW5kp85wxtolrbNa9d+F851F+uDrNozZffPc8dz7kUK2o59JZDCaOMDtu
-CCrCp1rIAjEAmeMM56PDr9NJLkaCI2ZdyQAUEv049OGYa3cpetskz2VAv9LcjBHo
-9H1/IISpQuQo
------END CERTIFICATE-----
-
-# Issuer: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos
-# Subject: CN=Atos TrustedRoot Root CA RSA TLS 2021 O=Atos
-# Label: "Atos TrustedRoot Root CA RSA TLS 2021"
-# Serial: 111436099570196163832749341232207667876
-# MD5 Fingerprint: d4:d3:46:b8:9a:c0:9c:76:5d:9e:3a:c3:b9:99:31:d2
-# SHA1 Fingerprint: 18:52:3b:0d:06:37:e4:d6:3a:df:23:e4:98:fb:5b:16:fb:86:74:48
-# SHA256 Fingerprint: 81:a9:08:8e:a5:9f:b3:64:c5:48:a6:f8:55:59:09:9b:6f:04:05:ef:bf:18:e5:32:4e:c9:f4:57:ba:00:11:2f
------BEGIN CERTIFICATE-----
-MIIFZDCCA0ygAwIBAgIQU9XP5hmTC/srBRLYwiqipDANBgkqhkiG9w0BAQwFADBM
-MS4wLAYDVQQDDCVBdG9zIFRydXN0ZWRSb290IFJvb3QgQ0EgUlNBIFRMUyAyMDIx
-MQ0wCwYDVQQKDARBdG9zMQswCQYDVQQGEwJERTAeFw0yMTA0MjIwOTIxMTBaFw00
-MTA0MTcwOTIxMDlaMEwxLjAsBgNVBAMMJUF0b3MgVHJ1c3RlZFJvb3QgUm9vdCBD
-QSBSU0EgVExTIDIwMjExDTALBgNVBAoMBEF0b3MxCzAJBgNVBAYTAkRFMIICIjAN
-BgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAtoAOxHm9BYx9sKOdTSJNy/BBl01Z
-4NH+VoyX8te9j2y3I49f1cTYQcvyAh5x5en2XssIKl4w8i1mx4QbZFc4nXUtVsYv
-Ye+W/CBGvevUez8/fEc4BKkbqlLfEzfTFRVOvV98r61jx3ncCHvVoOX3W3WsgFWZ
-kmGbzSoXfduP9LVq6hdKZChmFSlsAvFr1bqjM9xaZ6cF4r9lthawEO3NUDPJcFDs
-GY6wx/J0W2tExn2WuZgIWWbeKQGb9Cpt0xU6kGpn8bRrZtkh68rZYnxGEFzedUln
-nkL5/nWpo63/dgpnQOPF943HhZpZnmKaau1Fh5hnstVKPNe0OwANwI8f4UDErmwh
-3El+fsqyjW22v5MvoVw+j8rtgI5Y4dtXz4U2OLJxpAmMkokIiEjxQGMYsluMWuPD
-0xeqqxmjLBvk1cbiZnrXghmmOxYsL3GHX0WelXOTwkKBIROW1527k2gV+p2kHYzy
-geBYBr3JtuP2iV2J+axEoctr+hbxx1A9JNr3w+SH1VbxT5Aw+kUJWdo0zuATHAR8
-ANSbhqRAvNncTFd+rrcztl524WWLZt+NyteYr842mIycg5kDcPOvdO3GDjbnvezB
-c6eUWsuSZIKmAMFwoW4sKeFYV+xafJlrJaSQOoD0IJ2azsct+bJLKZWD6TWNp0lI
-pw9MGZHQ9b8Q4HECAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU
-dEmZ0f+0emhFdcN+tNzMzjkz2ggwDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB
-DAUAA4ICAQAjQ1MkYlxt/T7Cz1UAbMVWiLkO3TriJQ2VSpfKgInuKs1l+NsW4AmS
-4BjHeJi78+xCUvuppILXTdiK/ORO/auQxDh1MoSf/7OwKwIzNsAQkG8dnK/haZPs
-o0UvFJ/1TCplQ3IM98P4lYsU84UgYt1UU90s3BiVaU+DR3BAM1h3Egyi61IxHkzJ
-qM7F78PRreBrAwA0JrRUITWXAdxfG/F851X6LWh3e9NpzNMOa7pNdkTWwhWaJuyw
-xfW70Xp0wmzNxbVe9kzmWy2B27O3Opee7c9GslA9hGCZcbUztVdF5kJHdWoOsAgM
-rr3e97sPWD2PAzHoPYJQyi9eDF20l74gNAf0xBLh7tew2VktafcxBPTy+av5EzH4
-AXcOPUIjJsyacmdRIXrMPIWo6iFqO9taPKU0nprALN+AnCng33eU0aKAQv9qTFsR
-0PXNor6uzFFcw9VUewyu1rkGd4Di7wcaaMxZUa1+XGdrudviB0JbuAEFWDlN5LuY
-o7Ey7Nmj1m+UI/87tyll5gfp77YZ6ufCOB0yiJA8EytuzO+rdwY0d4RPcuSBhPm5
-dDTedk+SKlOxJTnbPP/lPqYO5Wue/9vsL3SD3460s6neFE3/MaNFcyT6lSnMEpcE
-oji2jbDwN/zIIX8/syQbPYtuzE2wFg2WHYMfRsCbvUOZ58SWLs5fyQ==
------END CERTIFICATE-----
-
-# Issuer: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc.
-# Subject: CN=TrustAsia Global Root CA G3 O=TrustAsia Technologies, Inc.
-# Label: "TrustAsia Global Root CA G3"
-# Serial: 576386314500428537169965010905813481816650257167
-# MD5 Fingerprint: 30:42:1b:b7:bb:81:75:35:e4:16:4f:53:d2:94:de:04
-# SHA1 Fingerprint: 63:cf:b6:c1:27:2b:56:e4:88:8e:1c:23:9a:b6:2e:81:47:24:c3:c7
-# SHA256 Fingerprint: e0:d3:22:6a:eb:11:63:c2:e4:8f:f9:be:3b:50:b4:c6:43:1b:e7:bb:1e:ac:c5:c3:6b:5d:5e:c5:09:03:9a:08
------BEGIN CERTIFICATE-----
-MIIFpTCCA42gAwIBAgIUZPYOZXdhaqs7tOqFhLuxibhxkw8wDQYJKoZIhvcNAQEM
-BQAwWjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dp
-ZXMsIEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHMzAe
-Fw0yMTA1MjAwMjEwMTlaFw00NjA1MTkwMjEwMTlaMFoxCzAJBgNVBAYTAkNOMSUw
-IwYDVQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtU
-cnVzdEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzMwggIiMA0GCSqGSIb3DQEBAQUAA4IC
-DwAwggIKAoICAQDAMYJhkuSUGwoqZdC+BqmHO1ES6nBBruL7dOoKjbmzTNyPtxNS
-T1QY4SxzlZHFZjtqz6xjbYdT8PfxObegQ2OwxANdV6nnRM7EoYNl9lA+sX4WuDqK
-AtCWHwDNBSHvBm3dIZwZQ0WhxeiAysKtQGIXBsaqvPPW5vxQfmZCHzyLpnl5hkA1
-nyDvP+uLRx+PjsXUjrYsyUQE49RDdT/VP68czH5GX6zfZBCK70bwkPAPLfSIC7Ep
-qq+FqklYqL9joDiR5rPmd2jE+SoZhLsO4fWvieylL1AgdB4SQXMeJNnKziyhWTXA
-yB1GJ2Faj/lN03J5Zh6fFZAhLf3ti1ZwA0pJPn9pMRJpxx5cynoTi+jm9WAPzJMs
-hH/x/Gr8m0ed262IPfN2dTPXS6TIi/n1Q1hPy8gDVI+lhXgEGvNz8teHHUGf59gX
-zhqcD0r83ERoVGjiQTz+LISGNzzNPy+i2+f3VANfWdP3kXjHi3dqFuVJhZBFcnAv
-kV34PmVACxmZySYgWmjBNb9Pp1Hx2BErW+Canig7CjoKH8GB5S7wprlppYiU5msT
-f9FkPz2ccEblooV7WIQn3MSAPmeamseaMQ4w7OYXQJXZRe0Blqq/DPNL0WP3E1jA
-uPP6Z92bfW1K/zJMtSU7/xxnD4UiWQWRkUF3gdCFTIcQcf+eQxuulXUtgQIDAQAB
-o2MwYTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFEDk5PIj7zjKsK5Xf/Ih
-MBY027ySMB0GA1UdDgQWBBRA5OTyI+84yrCuV3/yITAWNNu8kjAOBgNVHQ8BAf8E
-BAMCAQYwDQYJKoZIhvcNAQEMBQADggIBACY7UeFNOPMyGLS0XuFlXsSUT9SnYaP4
-wM8zAQLpw6o1D/GUE3d3NZ4tVlFEbuHGLige/9rsR82XRBf34EzC4Xx8MnpmyFq2
-XFNFV1pF1AWZLy4jVe5jaN/TG3inEpQGAHUNcoTpLrxaatXeL1nHo+zSh2bbt1S1
-JKv0Q3jbSwTEb93mPmY+KfJLaHEih6D4sTNjduMNhXJEIlU/HHzp/LgV6FL6qj6j
-ITk1dImmasI5+njPtqzn59ZW/yOSLlALqbUHM/Q4X6RJpstlcHboCoWASzY9M/eV
-VHUl2qzEc4Jl6VL1XP04lQJqaTDFHApXB64ipCz5xUG3uOyfT0gA+QEEVcys+TIx
-xHWVBqB/0Y0n3bOppHKH/lmLmnp0Ft0WpWIp6zqW3IunaFnT63eROfjXy9mPX1on
-AX1daBli2MjN9LdyR75bl87yraKZk62Uy5P2EgmVtqvXO9A/EcswFi55gORngS1d
-7XB4tmBZrOFdRWOPyN9yaFvqHbgB8X7754qz41SgOAngPN5C8sLtLpvzHzW2Ntjj
-gKGLzZlkD8Kqq7HK9W+eQ42EVJmzbsASZthwEPEGNTNDqJwuuhQxzhB/HIbjj9LV
-+Hfsm6vxL2PZQl/gZ4FkkfGXL/xuJvYz+NO1+MRiqzFRJQJ6+N1rZdVtTTDIZbpo
-FGWsJwt0ivKH
------END CERTIFICATE-----
-
-# Issuer: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc.
-# Subject: CN=TrustAsia Global Root CA G4 O=TrustAsia Technologies, Inc.
-# Label: "TrustAsia Global Root CA G4"
-# Serial: 451799571007117016466790293371524403291602933463
-# MD5 Fingerprint: 54:dd:b2:d7:5f:d8:3e:ed:7c:e0:0b:2e:cc:ed:eb:eb
-# SHA1 Fingerprint: 57:73:a5:61:5d:80:b2:e6:ac:38:82:fc:68:07:31:ac:9f:b5:92:5a
-# SHA256 Fingerprint: be:4b:56:cb:50:56:c0:13:6a:52:6d:f4:44:50:8d:aa:36:a0:b5:4f:42:e4:ac:38:f7:2a:f4:70:e4:79:65:4c
------BEGIN CERTIFICATE-----
-MIICVTCCAdygAwIBAgIUTyNkuI6XY57GU4HBdk7LKnQV1tcwCgYIKoZIzj0EAwMw
-WjELMAkGA1UEBhMCQ04xJTAjBgNVBAoMHFRydXN0QXNpYSBUZWNobm9sb2dpZXMs
-IEluYy4xJDAiBgNVBAMMG1RydXN0QXNpYSBHbG9iYWwgUm9vdCBDQSBHNDAeFw0y
-MTA1MjAwMjEwMjJaFw00NjA1MTkwMjEwMjJaMFoxCzAJBgNVBAYTAkNOMSUwIwYD
-VQQKDBxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQDDBtUcnVz
-dEFzaWEgR2xvYmFsIFJvb3QgQ0EgRzQwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAATx
-s8045CVD5d4ZCbuBeaIVXxVjAd7Cq92zphtnS4CDr5nLrBfbK5bKfFJV4hrhPVbw
-LxYI+hW8m7tH5j/uqOFMjPXTNvk4XatwmkcN4oFBButJ+bAp3TPsUKV/eSm4IJij
-YzBhMA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUpbtKl86zK3+kMd6Xg1mD
-pm9xy94wHQYDVR0OBBYEFKW7SpfOsyt/pDHel4NZg6ZvccveMA4GA1UdDwEB/wQE
-AwIBBjAKBggqhkjOPQQDAwNnADBkAjBe8usGzEkxn0AAbbd+NvBNEU/zy4k6LHiR
-UKNbwMp1JvK/kF0LgoxgKJ/GcJpo5PECMFxYDlZ2z1jD1xCMuo6u47xkdUfFVZDj
-/bpV6wfEU6s3qe4hsiFbYI89MvHVI5TWWA==
------END CERTIFICATE-----
-
-# Issuer: CN=CommScope Public Trust ECC Root-01 O=CommScope
-# Subject: CN=CommScope Public Trust ECC Root-01 O=CommScope
-# Label: "CommScope Public Trust ECC Root-01"
-# Serial: 385011430473757362783587124273108818652468453534
-# MD5 Fingerprint: 3a:40:a7:fc:03:8c:9c:38:79:2f:3a:a2:6c:b6:0a:16
-# SHA1 Fingerprint: 07:86:c0:d8:dd:8e:c0:80:98:06:98:d0:58:7a:ef:de:a6:cc:a2:5d
-# SHA256 Fingerprint: 11:43:7c:da:7b:b4:5e:41:36:5f:45:b3:9a:38:98:6b:0d:e0:0d:ef:34:8e:0c:7b:b0:87:36:33:80:0b:c3:8b
------BEGIN CERTIFICATE-----
-MIICHTCCAaOgAwIBAgIUQ3CCd89NXTTxyq4yLzf39H91oJ4wCgYIKoZIzj0EAwMw
-TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
-bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMTAeFw0yMTA0MjgxNzM1NDNa
-Fw00NjA0MjgxNzM1NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
-cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDEw
-djAQBgcqhkjOPQIBBgUrgQQAIgNiAARLNumuV16ocNfQj3Rid8NeeqrltqLxeP0C
-flfdkXmcbLlSiFS8LwS+uM32ENEp7LXQoMPwiXAZu1FlxUOcw5tjnSCDPgYLpkJE
-hRGnSjot6dZoL0hOUysHP029uax3OVejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
-VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBSOB2LAUN3GGQYARnQE9/OufXVNMDAKBggq
-hkjOPQQDAwNoADBlAjEAnDPfQeMjqEI2Jpc1XHvr20v4qotzVRVcrHgpD7oh2MSg
-2NED3W3ROT3Ek2DS43KyAjB8xX6I01D1HiXo+k515liWpDVfG2XqYZpwI7UNo5uS
-Um9poIyNStDuiw7LR47QjRE=
------END CERTIFICATE-----
-
-# Issuer: CN=CommScope Public Trust ECC Root-02 O=CommScope
-# Subject: CN=CommScope Public Trust ECC Root-02 O=CommScope
-# Label: "CommScope Public Trust ECC Root-02"
-# Serial: 234015080301808452132356021271193974922492992893
-# MD5 Fingerprint: 59:b0:44:d5:65:4d:b8:5c:55:19:92:02:b6:d1:94:b2
-# SHA1 Fingerprint: 3c:3f:ef:57:0f:fe:65:93:86:9e:a0:fe:b0:f6:ed:8e:d1:13:c7:e5
-# SHA256 Fingerprint: 2f:fb:7f:81:3b:bb:b3:c8:9a:b4:e8:16:2d:0f:16:d7:15:09:a8:30:cc:9d:73:c2:62:e5:14:08:75:d1:ad:4a
------BEGIN CERTIFICATE-----
-MIICHDCCAaOgAwIBAgIUKP2ZYEFHpgE6yhR7H+/5aAiDXX0wCgYIKoZIzj0EAwMw
-TjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwiQ29t
-bVNjb3BlIFB1YmxpYyBUcnVzdCBFQ0MgUm9vdC0wMjAeFw0yMTA0MjgxNzQ0NTRa
-Fw00NjA0MjgxNzQ0NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21tU2Nv
-cGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgRUNDIFJvb3QtMDIw
-djAQBgcqhkjOPQIBBgUrgQQAIgNiAAR4MIHoYx7l63FRD/cHB8o5mXxO1Q/MMDAL
-j2aTPs+9xYa9+bG3tD60B8jzljHz7aRP+KNOjSkVWLjVb3/ubCK1sK9IRQq9qEmU
-v4RDsNuESgMjGWdqb8FuvAY5N9GIIvejQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYD
-VR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTmGHX/72DehKT1RsfeSlXjMjZ59TAKBggq
-hkjOPQQDAwNnADBkAjAmc0l6tqvmSfR9Uj/UQQSugEODZXW5hYA4O9Zv5JOGq4/n
-ich/m35rChJVYaoR4HkCMHfoMXGsPHED1oQmHhS48zs73u1Z/GtMMH9ZzkXpc2AV
-mkzw5l4lIhVtwodZ0LKOag==
------END CERTIFICATE-----
-
-# Issuer: CN=CommScope Public Trust RSA Root-01 O=CommScope
-# Subject: CN=CommScope Public Trust RSA Root-01 O=CommScope
-# Label: "CommScope Public Trust RSA Root-01"
-# Serial: 354030733275608256394402989253558293562031411421
-# MD5 Fingerprint: 0e:b4:15:bc:87:63:5d:5d:02:73:d4:26:38:68:73:d8
-# SHA1 Fingerprint: 6d:0a:5f:f7:b4:23:06:b4:85:b3:b7:97:64:fc:ac:75:f5:33:f2:93
-# SHA256 Fingerprint: 02:bd:f9:6e:2a:45:dd:9b:f1:8f:c7:e1:db:df:21:a0:37:9b:a3:c9:c2:61:03:44:cf:d8:d6:06:fe:c1:ed:81
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIUPgNJgXUWdDGOTKvVxZAplsU5EN0wDQYJKoZIhvcNAQEL
-BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
-Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMTAeFw0yMTA0MjgxNjQ1
-NTRaFw00NjA0MjgxNjQ1NTNaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
-U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
-MDEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwSGWjDR1C45FtnYSk
-YZYSwu3D2iM0GXb26v1VWvZVAVMP8syMl0+5UMuzAURWlv2bKOx7dAvnQmtVzslh
-suitQDy6uUEKBU8bJoWPQ7VAtYXR1HHcg0Hz9kXHgKKEUJdGzqAMxGBWBB0HW0al
-DrJLpA6lfO741GIDuZNqihS4cPgugkY4Iw50x2tBt9Apo52AsH53k2NC+zSDO3Oj
-WiE260f6GBfZumbCk6SP/F2krfxQapWsvCQz0b2If4b19bJzKo98rwjyGpg/qYFl
-P8GMicWWMJoKz/TUyDTtnS+8jTiGU+6Xn6myY5QXjQ/cZip8UlF1y5mO6D1cv547
-KI2DAg+pn3LiLCuz3GaXAEDQpFSOm117RTYm1nJD68/A6g3czhLmfTifBSeolz7p
-UcZsBSjBAg/pGG3svZwG1KdJ9FQFa2ww8esD1eo9anbCyxooSU1/ZOD6K9pzg4H/
-kQO9lLvkuI6cMmPNn7togbGEW682v3fuHX/3SZtS7NJ3Wn2RnU3COS3kuoL4b/JO
-Hg9O5j9ZpSPcPYeoKFgo0fEbNttPxP/hjFtyjMcmAyejOQoBqsCyMWCDIqFPEgkB
-Ea801M/XrmLTBQe0MXXgDW1XT2mH+VepuhX2yFJtocucH+X8eKg1mp9BFM6ltM6U
-CBwJrVbl2rZJmkrqYxhTnCwuwwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUN12mmnQywsL5x6YVEFm45P3luG0wDQYJ
-KoZIhvcNAQELBQADggIBAK+nz97/4L1CjU3lIpbfaOp9TSp90K09FlxD533Ahuh6
-NWPxzIHIxgvoLlI1pKZJkGNRrDSsBTtXAOnTYtPZKdVUvhwQkZyybf5Z/Xn36lbQ
-nmhUQo8mUuJM3y+Xpi/SB5io82BdS5pYV4jvguX6r2yBS5KPQJqTRlnLX3gWsWc+
-QgvfKNmwrZggvkN80V4aCRckjXtdlemrwWCrWxhkgPut4AZ9HcpZuPN4KWfGVh2v
-trV0KnahP/t1MJ+UXjulYPPLXAziDslg+MkfFoom3ecnf+slpoq9uC02EJqxWE2a
-aE9gVOX2RhOOiKy8IUISrcZKiX2bwdgt6ZYD9KJ0DLwAHb/WNyVntHKLr4W96ioD
-j8z7PEQkguIBpQtZtjSNMgsSDesnwv1B10A8ckYpwIzqug/xBpMu95yo9GA+o/E4
-Xo4TwbM6l4c/ksp4qRyv0LAbJh6+cOx69TOY6lz/KwsETkPdY34Op054A5U+1C0w
-lREQKC6/oAI+/15Z0wUOlV9TRe9rh9VIzRamloPh37MG88EU26fsHItdkJANclHn
-YfkUyq+Dj7+vsQpZXdxc1+SWrVtgHdqul7I52Qb1dgAT+GhMIbA1xNxVssnBQVoc
-icCMb3SgazNNtQEo/a2tiRc7ppqEvOuM6sRxJKi6KfkIsidWNTJf6jn7MZrVGczw
------END CERTIFICATE-----
-
-# Issuer: CN=CommScope Public Trust RSA Root-02 O=CommScope
-# Subject: CN=CommScope Public Trust RSA Root-02 O=CommScope
-# Label: "CommScope Public Trust RSA Root-02"
-# Serial: 480062499834624527752716769107743131258796508494
-# MD5 Fingerprint: e1:29:f9:62:7b:76:e2:96:6d:f3:d4:d7:0f:ae:1f:aa
-# SHA1 Fingerprint: ea:b0:e2:52:1b:89:93:4c:11:68:f2:d8:9a:ac:22:4c:a3:8a:57:ae
-# SHA256 Fingerprint: ff:e9:43:d7:93:42:4b:4f:7c:44:0c:1c:3d:64:8d:53:63:f3:4b:82:dc:87:aa:7a:9f:11:8f:c5:de:e1:01:f1
------BEGIN CERTIFICATE-----
-MIIFbDCCA1SgAwIBAgIUVBa/O345lXGN0aoApYYNK496BU4wDQYJKoZIhvcNAQEL
-BQAwTjELMAkGA1UEBhMCVVMxEjAQBgNVBAoMCUNvbW1TY29wZTErMCkGA1UEAwwi
-Q29tbVNjb3BlIFB1YmxpYyBUcnVzdCBSU0EgUm9vdC0wMjAeFw0yMTA0MjgxNzE2
-NDNaFw00NjA0MjgxNzE2NDJaME4xCzAJBgNVBAYTAlVTMRIwEAYDVQQKDAlDb21t
-U2NvcGUxKzApBgNVBAMMIkNvbW1TY29wZSBQdWJsaWMgVHJ1c3QgUlNBIFJvb3Qt
-MDIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDh+g77aAASyE3VrCLE
-NQE7xVTlWXZjpX/rwcRqmL0yjReA61260WI9JSMZNRTpf4mnG2I81lDnNJUDMrG0
-kyI9p+Kx7eZ7Ti6Hmw0zdQreqjXnfuU2mKKuJZ6VszKWpCtYHu8//mI0SFHRtI1C
-rWDaSWqVcN3SAOLMV2MCe5bdSZdbkk6V0/nLKR8YSvgBKtJjCW4k6YnS5cciTNxz
-hkcAqg2Ijq6FfUrpuzNPDlJwnZXjfG2WWy09X6GDRl224yW4fKcZgBzqZUPckXk2
-LHR88mcGyYnJ27/aaL8j7dxrrSiDeS/sOKUNNwFnJ5rpM9kzXzehxfCrPfp4sOcs
-n/Y+n2Dg70jpkEUeBVF4GiwSLFworA2iI540jwXmojPOEXcT1A6kHkIfhs1w/tku
-FT0du7jyU1fbzMZ0KZwYszZ1OC4PVKH4kh+Jlk+71O6d6Ts2QrUKOyrUZHk2EOH5
-kQMreyBUzQ0ZGshBMjTRsJnhkB4BQDa1t/qp5Xd1pCKBXbCL5CcSD1SIxtuFdOa3
-wNemKfrb3vOTlycEVS8KbzfFPROvCgCpLIscgSjX74Yxqa7ybrjKaixUR9gqiC6v
-wQcQeKwRoi9C8DfF8rhW3Q5iLc4tVn5V8qdE9isy9COoR+jUKgF4z2rDN6ieZdIs
-5fq6M8EGRPbmz6UNp2YINIos8wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUR9DnsSL/nSz12Vdgs7GxcJXvYXowDQYJ
-KoZIhvcNAQELBQADggIBAIZpsU0v6Z9PIpNojuQhmaPORVMbc0RTAIFhzTHjCLqB
-KCh6krm2qMhDnscTJk3C2OVVnJJdUNjCK9v+5qiXz1I6JMNlZFxHMaNlNRPDk7n3
-+VGXu6TwYofF1gbTl4MgqX67tiHCpQ2EAOHyJxCDut0DgdXdaMNmEMjRdrSzbyme
-APnCKfWxkxlSaRosTKCL4BWaMS/TiJVZbuXEs1DIFAhKm4sTg7GkcrI7djNB3Nyq
-pgdvHSQSn8h2vS/ZjvQs7rfSOBAkNlEv41xdgSGn2rtO/+YHqP65DSdsu3BaVXoT
-6fEqSWnHX4dXTEN5bTpl6TBcQe7rd6VzEojov32u5cSoHw2OHG1QAk8mGEPej1WF
-sQs3BWDJVTkSBKEqz3EWnzZRSb9wO55nnPt7eck5HHisd5FUmrh1CoFSl+NmYWvt
-PjgelmFV4ZFUjO2MJB+ByRCac5krFk5yAD9UG/iNuovnFNa2RU9g7Jauwy8CTl2d
-lklyALKrdVwPaFsdZcJfMw8eD/A7hvWwTruc9+olBdytoptLFwG+Qt81IR2tq670
-v64fG9PiO/yzcnMcmyiQiRM9HcEARwmWmjgb3bHPDcK0RPOWlc4yOo80nOAXx17O
-rg3bhzjlP1v9mxnhMUF6cKojawHhRUzNlM47ni3niAIi9G7oyOzWPPO5std3eqx7
------END CERTIFICATE-----
-
-# Issuer: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH
-# Subject: CN=Telekom Security TLS ECC Root 2020 O=Deutsche Telekom Security GmbH
-# Label: "Telekom Security TLS ECC Root 2020"
-# Serial: 72082518505882327255703894282316633856
-# MD5 Fingerprint: c1:ab:fe:6a:10:2c:03:8d:bc:1c:22:32:c0:85:a7:fd
-# SHA1 Fingerprint: c0:f8:96:c5:a9:3b:01:06:21:07:da:18:42:48:bc:e9:9d:88:d5:ec
-# SHA256 Fingerprint: 57:8a:f4:de:d0:85:3f:4e:59:98:db:4a:ea:f9:cb:ea:8d:94:5f:60:b6:20:a3:8d:1a:3c:13:b2:bc:7b:a8:e1
------BEGIN CERTIFICATE-----
-MIICQjCCAcmgAwIBAgIQNjqWjMlcsljN0AFdxeVXADAKBggqhkjOPQQDAzBjMQsw
-CQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0eSBH
-bWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBFQ0MgUm9vdCAyMDIw
-MB4XDTIwMDgyNTA3NDgyMFoXDTQ1MDgyNTIzNTk1OVowYzELMAkGA1UEBhMCREUx
-JzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkGA1UE
-AwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgRUNDIFJvb3QgMjAyMDB2MBAGByqGSM49
-AgEGBSuBBAAiA2IABM6//leov9Wq9xCazbzREaK9Z0LMkOsVGJDZos0MKiXrPk/O
-tdKPD/M12kOLAoC+b1EkHQ9rK8qfwm9QMuU3ILYg/4gND21Ju9sGpIeQkpT0CdDP
-f8iAC8GXs7s1J8nCG6NCMEAwHQYDVR0OBBYEFONyzG6VmUex5rNhTNHLq+O6zd6f
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMAoGCCqGSM49BAMDA2cA
-MGQCMHVSi7ekEE+uShCLsoRbQuHmKjYC2qBuGT8lv9pZMo7k+5Dck2TOrbRBR2Di
-z6fLHgIwN0GMZt9Ba9aDAEH9L1r3ULRn0SyocddDypwnJJGDSA3PzfdUga/sf+Rn
-27iQ7t0l
------END CERTIFICATE-----
-
-# Issuer: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH
-# Subject: CN=Telekom Security TLS RSA Root 2023 O=Deutsche Telekom Security GmbH
-# Label: "Telekom Security TLS RSA Root 2023"
-# Serial: 44676229530606711399881795178081572759
-# MD5 Fingerprint: bf:5b:eb:54:40:cd:48:71:c4:20:8d:7d:de:0a:42:f2
-# SHA1 Fingerprint: 54:d3:ac:b3:bd:57:56:f6:85:9d:ce:e5:c3:21:e2:d4:ad:83:d0:93
-# SHA256 Fingerprint: ef:c6:5c:ad:bb:59:ad:b6:ef:e8:4d:a2:23:11:b3:56:24:b7:1b:3b:1e:a0:da:8b:66:55:17:4e:c8:97:86:46
------BEGIN CERTIFICATE-----
-MIIFszCCA5ugAwIBAgIQIZxULej27HF3+k7ow3BXlzANBgkqhkiG9w0BAQwFADBj
-MQswCQYDVQQGEwJERTEnMCUGA1UECgweRGV1dHNjaGUgVGVsZWtvbSBTZWN1cml0
-eSBHbWJIMSswKQYDVQQDDCJUZWxla29tIFNlY3VyaXR5IFRMUyBSU0EgUm9vdCAy
-MDIzMB4XDTIzMDMyODEyMTY0NVoXDTQ4MDMyNzIzNTk1OVowYzELMAkGA1UEBhMC
-REUxJzAlBgNVBAoMHkRldXRzY2hlIFRlbGVrb20gU2VjdXJpdHkgR21iSDErMCkG
-A1UEAwwiVGVsZWtvbSBTZWN1cml0eSBUTFMgUlNBIFJvb3QgMjAyMzCCAiIwDQYJ
-KoZIhvcNAQEBBQADggIPADCCAgoCggIBAO01oYGA88tKaVvC+1GDrib94W7zgRJ9
-cUD/h3VCKSHtgVIs3xLBGYSJwb3FKNXVS2xE1kzbB5ZKVXrKNoIENqil/Cf2SfHV
-cp6R+SPWcHu79ZvB7JPPGeplfohwoHP89v+1VmLhc2o0mD6CuKyVU/QBoCcHcqMA
-U6DksquDOFczJZSfvkgdmOGjup5czQRxUX11eKvzWarE4GC+j4NSuHUaQTXtvPM6
-Y+mpFEXX5lLRbtLevOP1Czvm4MS9Q2QTps70mDdsipWol8hHD/BeEIvnHRz+sTug
-BTNoBUGCwQMrAcjnj02r6LX2zWtEtefdi+zqJbQAIldNsLGyMcEWzv/9FIS3R/qy
-8XDe24tsNlikfLMR0cN3f1+2JeANxdKz+bi4d9s3cXFH42AYTyS2dTd4uaNir73J
-co4vzLuu2+QVUhkHM/tqty1LkCiCc/4YizWN26cEar7qwU02OxY2kTLvtkCJkUPg
-8qKrBC7m8kwOFjQgrIfBLX7JZkcXFBGk8/ehJImr2BrIoVyxo/eMbcgByU/J7MT8
-rFEz0ciD0cmfHdRHNCk+y7AO+oMLKFjlKdw/fKifybYKu6boRhYPluV75Gp6SG12
-mAWl3G0eQh5C2hrgUve1g8Aae3g1LDj1H/1Joy7SWWO/gLCMk3PLNaaZlSJhZQNg
-+y+TS/qanIA7AgMBAAGjYzBhMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtqeX
-gj10hZv3PJ+TmpV5dVKMbUcwDwYDVR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBS2
-p5eCPXSFm/c8n5OalXl1UoxtRzANBgkqhkiG9w0BAQwFAAOCAgEAqMxhpr51nhVQ
-pGv7qHBFfLp+sVr8WyP6Cnf4mHGCDG3gXkaqk/QeoMPhk9tLrbKmXauw1GLLXrtm
-9S3ul0A8Yute1hTWjOKWi0FpkzXmuZlrYrShF2Y0pmtjxrlO8iLpWA1WQdH6DErw
-M807u20hOq6OcrXDSvvpfeWxm4bu4uB9tPcy/SKE8YXJN3nptT+/XOR0so8RYgDd
-GGah2XsjX/GO1WfoVNpbOms2b/mBsTNHM3dA+VKq3dSDz4V4mZqTuXNnQkYRIer+
-CqkbGmVps4+uFrb2S1ayLfmlyOw7YqPta9BO1UAJpB+Y1zqlklkg5LB9zVtzaL1t
-xKITDmcZuI1CfmwMmm6gJC3VRRvcxAIU/oVbZZfKTpBQCHpCNfnqwmbU+AGuHrS+
-w6jv/naaoqYfRvaE7fzbzsQCzndILIyy7MMAo+wsVRjBfhnu4S/yrYObnqsZ38aK
-L4x35bcF7DvB7L6Gs4a8wPfc5+pbrrLMtTWGS9DiP7bY+A4A7l3j941Y/8+LN+lj
-X273CXE2whJdV/LItM3z7gLfEdxquVeEHVlNjM7IDiPCtyaaEBRx/pOyiriA8A4Q
-ntOoUAw3gi/q4Iqd4Sw5/7W0cwDk90imc6y/st53BIe0o82bNSQ3+pCTE4FCxpgm
-dTdmQRCsu/WU48IxK63nI1bMNSWSs1A=
------END CERTIFICATE-----
-
-# Issuer: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA
-# Subject: CN=FIRMAPROFESIONAL CA ROOT-A WEB O=Firmaprofesional SA
-# Label: "FIRMAPROFESIONAL CA ROOT-A WEB"
-# Serial: 65916896770016886708751106294915943533
-# MD5 Fingerprint: 82:b2:ad:45:00:82:b0:66:63:f8:5f:c3:67:4e:ce:a3
-# SHA1 Fingerprint: a8:31:11:74:a6:14:15:0d:ca:77:dd:0e:e4:0c:5d:58:fc:a0:72:a5
-# SHA256 Fingerprint: be:f2:56:da:f2:6e:9c:69:bd:ec:16:02:35:97:98:f3:ca:f7:18:21:a0:3e:01:82:57:c5:3c:65:61:7f:3d:4a
------BEGIN CERTIFICATE-----
-MIICejCCAgCgAwIBAgIQMZch7a+JQn81QYehZ1ZMbTAKBggqhkjOPQQDAzBuMQsw
-CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE
-YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB
-IFJPT1QtQSBXRUIwHhcNMjIwNDA2MDkwMTM2WhcNNDcwMzMxMDkwMTM2WjBuMQsw
-CQYDVQQGEwJFUzEcMBoGA1UECgwTRmlybWFwcm9mZXNpb25hbCBTQTEYMBYGA1UE
-YQwPVkFURVMtQTYyNjM0MDY4MScwJQYDVQQDDB5GSVJNQVBST0ZFU0lPTkFMIENB
-IFJPT1QtQSBXRUIwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARHU+osEaR3xyrq89Zf
-e9MEkVz6iMYiuYMQYneEMy3pA4jU4DP37XcsSmDq5G+tbbT4TIqk5B/K6k84Si6C
-cyvHZpsKjECcfIr28jlgst7L7Ljkb+qbXbdTkBgyVcUgt5SjYzBhMA8GA1UdEwEB
-/wQFMAMBAf8wHwYDVR0jBBgwFoAUk+FDY1w8ndYn81LsF7Kpryz3dvgwHQYDVR0O
-BBYEFJPhQ2NcPJ3WJ/NS7Beyqa8s93b4MA4GA1UdDwEB/wQEAwIBBjAKBggqhkjO
-PQQDAwNoADBlAjAdfKR7w4l1M+E7qUW/Runpod3JIha3RxEL2Jq68cgLcFBTApFw
-hVmpHqTm6iMxoAACMQD94vizrxa5HnPEluPBMBnYfubDl94cT7iJLzPrSA8Z94dG
-XSaQpYXFuXqUPoeovQA=
------END CERTIFICATE-----
diff --git a/.venv/lib/python3.12/site-packages/certifi/core.py b/.venv/lib/python3.12/site-packages/certifi/core.py
deleted file mode 100644
index 91f538b..0000000
--- a/.venv/lib/python3.12/site-packages/certifi/core.py
+++ /dev/null
@@ -1,114 +0,0 @@
-"""
-certifi.py
-~~~~~~~~~~
-
-This module returns the installation location of cacert.pem or its contents.
-"""
-import sys
-import atexit
-
-def exit_cacert_ctx() -> None:
- _CACERT_CTX.__exit__(None, None, None) # type: ignore[union-attr]
-
-
-if sys.version_info >= (3, 11):
-
- from importlib.resources import as_file, files
-
- _CACERT_CTX = None
- _CACERT_PATH = None
-
- def where() -> str:
- # This is slightly terrible, but we want to delay extracting the file
- # in cases where we're inside of a zipimport situation until someone
- # actually calls where(), but we don't want to re-extract the file
- # on every call of where(), so we'll do it once then store it in a
- # global variable.
- global _CACERT_CTX
- global _CACERT_PATH
- if _CACERT_PATH is None:
- # This is slightly janky, the importlib.resources API wants you to
- # manage the cleanup of this file, so it doesn't actually return a
- # path, it returns a context manager that will give you the path
- # when you enter it and will do any cleanup when you leave it. In
- # the common case of not needing a temporary file, it will just
- # return the file system location and the __exit__() is a no-op.
- #
- # We also have to hold onto the actual context manager, because
- # it will do the cleanup whenever it gets garbage collected, so
- # we will also store that at the global level as well.
- _CACERT_CTX = as_file(files("certifi").joinpath("cacert.pem"))
- _CACERT_PATH = str(_CACERT_CTX.__enter__())
- atexit.register(exit_cacert_ctx)
-
- return _CACERT_PATH
-
- def contents() -> str:
- return files("certifi").joinpath("cacert.pem").read_text(encoding="ascii")
-
-elif sys.version_info >= (3, 7):
-
- from importlib.resources import path as get_path, read_text
-
- _CACERT_CTX = None
- _CACERT_PATH = None
-
- def where() -> str:
- # This is slightly terrible, but we want to delay extracting the
- # file in cases where we're inside of a zipimport situation until
- # someone actually calls where(), but we don't want to re-extract
- # the file on every call of where(), so we'll do it once then store
- # it in a global variable.
- global _CACERT_CTX
- global _CACERT_PATH
- if _CACERT_PATH is None:
- # This is slightly janky, the importlib.resources API wants you
- # to manage the cleanup of this file, so it doesn't actually
- # return a path, it returns a context manager that will give
- # you the path when you enter it and will do any cleanup when
- # you leave it. In the common case of not needing a temporary
- # file, it will just return the file system location and the
- # __exit__() is a no-op.
- #
- # We also have to hold onto the actual context manager, because
- # it will do the cleanup whenever it gets garbage collected, so
- # we will also store that at the global level as well.
- _CACERT_CTX = get_path("certifi", "cacert.pem")
- _CACERT_PATH = str(_CACERT_CTX.__enter__())
- atexit.register(exit_cacert_ctx)
-
- return _CACERT_PATH
-
- def contents() -> str:
- return read_text("certifi", "cacert.pem", encoding="ascii")
-
-else:
- import os
- import types
- from typing import Union
-
- Package = Union[types.ModuleType, str]
- Resource = Union[str, "os.PathLike"]
-
- # This fallback will work for Python versions prior to 3.7 that lack the
- # importlib.resources module but relies on the existing `where` function
- # so won't address issues with environments like PyOxidizer that don't set
- # __file__ on modules.
- def read_text(
- package: Package,
- resource: Resource,
- encoding: str = 'utf-8',
- errors: str = 'strict'
- ) -> str:
- with open(where(), encoding=encoding) as data:
- return data.read()
-
- # If we don't have importlib.resources, then we will just do the old logic
- # of assuming we're on the filesystem and munge the path directly.
- def where() -> str:
- f = os.path.dirname(__file__)
-
- return os.path.join(f, "cacert.pem")
-
- def contents() -> str:
- return read_text("certifi", "cacert.pem", encoding="ascii")
diff --git a/.venv/lib/python3.12/site-packages/certifi/py.typed b/.venv/lib/python3.12/site-packages/certifi/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE
deleted file mode 100644
index ad82355..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2019 TAHRI Ahmed R.
-
-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.
\ No newline at end of file
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/METADATA b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/METADATA
deleted file mode 100644
index 822550e..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/METADATA
+++ /dev/null
@@ -1,683 +0,0 @@
-Metadata-Version: 2.1
-Name: charset-normalizer
-Version: 3.3.2
-Summary: The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet.
-Home-page: https://github.com/Ousret/charset_normalizer
-Author: Ahmed TAHRI
-Author-email: ahmed.tahri@cloudnursery.dev
-License: MIT
-Project-URL: Bug Reports, https://github.com/Ousret/charset_normalizer/issues
-Project-URL: Documentation, https://charset-normalizer.readthedocs.io/en/latest
-Keywords: encoding,charset,charset-detector,detector,normalization,unicode,chardet,detect
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Intended Audience :: Developers
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Text Processing :: Linguistic
-Classifier: Topic :: Utilities
-Classifier: Typing :: Typed
-Requires-Python: >=3.7.0
-Description-Content-Type: text/markdown
-License-File: LICENSE
-Provides-Extra: unicode_backport
-
-
Charset Detection, for Everyone 👋
-
-
- The Real First Universal Charset Detector
-
-
-
-
-
-
-
-
-
-
-
- Featured Packages
-
-
-
-
-
-
-
-
- In other language (unofficial port - by the community)
-
-
-
-
-
-> A library that helps you read text from an unknown charset encoding. Motivated by `chardet`,
-> I'm trying to resolve the issue by taking a new approach.
-> All IANA character set names for which the Python core library provides codecs are supported.
-
-
- >>>>> 👉 Try Me Online Now, Then Adopt Me 👈 <<<<<
-
-
-This project offers you an alternative to **Universal Charset Encoding Detector**, also known as **Chardet**.
-
-| Feature | [Chardet](https://github.com/chardet/chardet) | Charset Normalizer | [cChardet](https://github.com/PyYoshi/cChardet) |
-|--------------------------------------------------|:---------------------------------------------:|:--------------------------------------------------------------------------------------------------:|:-----------------------------------------------:|
-| `Fast` | ❌ | ✅ | ✅ |
-| `Universal**` | ❌ | ✅ | ❌ |
-| `Reliable` **without** distinguishable standards | ❌ | ✅ | ✅ |
-| `Reliable` **with** distinguishable standards | ✅ | ✅ | ✅ |
-| `License` | LGPL-2.1 _restrictive_ | MIT | MPL-1.1 _restrictive_ |
-| `Native Python` | ✅ | ✅ | ❌ |
-| `Detect spoken language` | ❌ | ✅ | N/A |
-| `UnicodeDecodeError Safety` | ❌ | ✅ | ❌ |
-| `Whl Size (min)` | 193.6 kB | 42 kB | ~200 kB |
-| `Supported Encoding` | 33 | 🎉 [99](https://charset-normalizer.readthedocs.io/en/latest/user/support.html#supported-encodings) | 40 |
-
-
-
-
-
-*\*\* : They are clearly using specific code for a specific encoding even if covering most of used one*
-Did you got there because of the logs? See [https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html](https://charset-normalizer.readthedocs.io/en/latest/user/miscellaneous.html)
-
-## ⚡ Performance
-
-This package offer better performance than its counterpart Chardet. Here are some numbers.
-
-| Package | Accuracy | Mean per file (ms) | File per sec (est) |
-|-----------------------------------------------|:--------:|:------------------:|:------------------:|
-| [chardet](https://github.com/chardet/chardet) | 86 % | 200 ms | 5 file/sec |
-| charset-normalizer | **98 %** | **10 ms** | 100 file/sec |
-
-| Package | 99th percentile | 95th percentile | 50th percentile |
-|-----------------------------------------------|:---------------:|:---------------:|:---------------:|
-| [chardet](https://github.com/chardet/chardet) | 1200 ms | 287 ms | 23 ms |
-| charset-normalizer | 100 ms | 50 ms | 5 ms |
-
-Chardet's performance on larger file (1MB+) are very poor. Expect huge difference on large payload.
-
-> Stats are generated using 400+ files using default parameters. More details on used files, see GHA workflows.
-> And yes, these results might change at any time. The dataset can be updated to include more files.
-> The actual delays heavily depends on your CPU capabilities. The factors should remain the same.
-> Keep in mind that the stats are generous and that Chardet accuracy vs our is measured using Chardet initial capability
-> (eg. Supported Encoding) Challenge-them if you want.
-
-## ✨ Installation
-
-Using pip:
-
-```sh
-pip install charset-normalizer -U
-```
-
-## 🚀 Basic Usage
-
-### CLI
-This package comes with a CLI.
-
-```
-usage: normalizer [-h] [-v] [-a] [-n] [-m] [-r] [-f] [-t THRESHOLD]
- file [file ...]
-
-The Real First Universal Charset Detector. Discover originating encoding used
-on text file. Normalize text to unicode.
-
-positional arguments:
- files File(s) to be analysed
-
-optional arguments:
- -h, --help show this help message and exit
- -v, --verbose Display complementary information about file if any.
- Stdout will contain logs about the detection process.
- -a, --with-alternative
- Output complementary possibilities if any. Top-level
- JSON WILL be a list.
- -n, --normalize Permit to normalize input file. If not set, program
- does not write anything.
- -m, --minimal Only output the charset detected to STDOUT. Disabling
- JSON output.
- -r, --replace Replace file when trying to normalize it instead of
- creating a new one.
- -f, --force Replace file without asking if you are sure, use this
- flag with caution.
- -t THRESHOLD, --threshold THRESHOLD
- Define a custom maximum amount of chaos allowed in
- decoded content. 0. <= chaos <= 1.
- --version Show version information and exit.
-```
-
-```bash
-normalizer ./data/sample.1.fr.srt
-```
-
-or
-
-```bash
-python -m charset_normalizer ./data/sample.1.fr.srt
-```
-
-🎉 Since version 1.4.0 the CLI produce easily usable stdout result in JSON format.
-
-```json
-{
- "path": "/home/default/projects/charset_normalizer/data/sample.1.fr.srt",
- "encoding": "cp1252",
- "encoding_aliases": [
- "1252",
- "windows_1252"
- ],
- "alternative_encodings": [
- "cp1254",
- "cp1256",
- "cp1258",
- "iso8859_14",
- "iso8859_15",
- "iso8859_16",
- "iso8859_3",
- "iso8859_9",
- "latin_1",
- "mbcs"
- ],
- "language": "French",
- "alphabets": [
- "Basic Latin",
- "Latin-1 Supplement"
- ],
- "has_sig_or_bom": false,
- "chaos": 0.149,
- "coherence": 97.152,
- "unicode_path": null,
- "is_preferred": true
-}
-```
-
-### Python
-*Just print out normalized text*
-```python
-from charset_normalizer import from_path
-
-results = from_path('./my_subtitle.srt')
-
-print(str(results.best()))
-```
-
-*Upgrade your code without effort*
-```python
-from charset_normalizer import detect
-```
-
-The above code will behave the same as **chardet**. We ensure that we offer the best (reasonable) BC result possible.
-
-See the docs for advanced usage : [readthedocs.io](https://charset-normalizer.readthedocs.io/en/latest/)
-
-## 😇 Why
-
-When I started using Chardet, I noticed that it was not suited to my expectations, and I wanted to propose a
-reliable alternative using a completely different method. Also! I never back down on a good challenge!
-
-I **don't care** about the **originating charset** encoding, because **two different tables** can
-produce **two identical rendered string.**
-What I want is to get readable text, the best I can.
-
-In a way, **I'm brute forcing text decoding.** How cool is that ? 😎
-
-Don't confuse package **ftfy** with charset-normalizer or chardet. ftfy goal is to repair unicode string whereas charset-normalizer to convert raw file in unknown encoding to unicode.
-
-## 🍰 How
-
- - Discard all charset encoding table that could not fit the binary content.
- - Measure noise, or the mess once opened (by chunks) with a corresponding charset encoding.
- - Extract matches with the lowest mess detected.
- - Additionally, we measure coherence / probe for a language.
-
-**Wait a minute**, what is noise/mess and coherence according to **YOU ?**
-
-*Noise :* I opened hundred of text files, **written by humans**, with the wrong encoding table. **I observed**, then
-**I established** some ground rules about **what is obvious** when **it seems like** a mess.
- I know that my interpretation of what is noise is probably incomplete, feel free to contribute in order to
- improve or rewrite it.
-
-*Coherence :* For each language there is on earth, we have computed ranked letter appearance occurrences (the best we can). So I thought
-that intel is worth something here. So I use those records against decoded text to check if I can detect intelligent design.
-
-## ⚡ Known limitations
-
- - Language detection is unreliable when text contains two or more languages sharing identical letters. (eg. HTML (english tags) + Turkish content (Sharing Latin characters))
- - Every charset detector heavily depends on sufficient content. In common cases, do not bother run detection on very tiny content.
-
-## ⚠️ About Python EOLs
-
-**If you are running:**
-
-- Python >=2.7,<3.5: Unsupported
-- Python 3.5: charset-normalizer < 2.1
-- Python 3.6: charset-normalizer < 3.1
-- Python 3.7: charset-normalizer < 4.0
-
-Upgrade your Python interpreter as soon as possible.
-
-## 👤 Contributing
-
-Contributions, issues and feature requests are very much welcome.
-Feel free to check [issues page](https://github.com/ousret/charset_normalizer/issues) if you want to contribute.
-
-## 📝 License
-
-Copyright © [Ahmed TAHRI @Ousret](https://github.com/Ousret).
-This project is [MIT](https://github.com/Ousret/charset_normalizer/blob/master/LICENSE) licensed.
-
-Characters frequencies used in this project © 2012 [Denny Vrandečić](http://simia.net/letters/)
-
-## 💼 For Enterprise
-
-Professional support for charset-normalizer is available as part of the [Tidelift
-Subscription][1]. Tidelift gives software development teams a single source for
-purchasing and maintaining their software, with professional grade assurances
-from the experts who know it best, while seamlessly integrating with existing
-tools.
-
-[1]: https://tidelift.com/subscription/pkg/pypi-charset-normalizer?utm_source=pypi-charset-normalizer&utm_medium=readme
-
-# Changelog
-All notable changes to charset-normalizer will be documented in this file. This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
-
-## [3.3.2](https://github.com/Ousret/charset_normalizer/compare/3.3.1...3.3.2) (2023-10-31)
-
-### Fixed
-- Unintentional memory usage regression when using large payload that match several encoding (#376)
-- Regression on some detection case showcased in the documentation (#371)
-
-### Added
-- Noise (md) probe that identify malformed arabic representation due to the presence of letters in isolated form (credit to my wife)
-
-## [3.3.1](https://github.com/Ousret/charset_normalizer/compare/3.3.0...3.3.1) (2023-10-22)
-
-### Changed
-- Optional mypyc compilation upgraded to version 1.6.1 for Python >= 3.8
-- Improved the general detection reliability based on reports from the community
-
-## [3.3.0](https://github.com/Ousret/charset_normalizer/compare/3.2.0...3.3.0) (2023-09-30)
-
-### Added
-- Allow to execute the CLI (e.g. normalizer) through `python -m charset_normalizer.cli` or `python -m charset_normalizer`
-- Support for 9 forgotten encoding that are supported by Python but unlisted in `encoding.aliases` as they have no alias (#323)
-
-### Removed
-- (internal) Redundant utils.is_ascii function and unused function is_private_use_only
-- (internal) charset_normalizer.assets is moved inside charset_normalizer.constant
-
-### Changed
-- (internal) Unicode code blocks in constants are updated using the latest v15.0.0 definition to improve detection
-- Optional mypyc compilation upgraded to version 1.5.1 for Python >= 3.8
-
-### Fixed
-- Unable to properly sort CharsetMatch when both chaos/noise and coherence were close due to an unreachable condition in \_\_lt\_\_ (#350)
-
-## [3.2.0](https://github.com/Ousret/charset_normalizer/compare/3.1.0...3.2.0) (2023-06-07)
-
-### Changed
-- Typehint for function `from_path` no longer enforce `PathLike` as its first argument
-- Minor improvement over the global detection reliability
-
-### Added
-- Introduce function `is_binary` that relies on main capabilities, and optimized to detect binaries
-- Propagate `enable_fallback` argument throughout `from_bytes`, `from_path`, and `from_fp` that allow a deeper control over the detection (default True)
-- Explicit support for Python 3.12
-
-### Fixed
-- Edge case detection failure where a file would contain 'very-long' camel cased word (Issue #289)
-
-## [3.1.0](https://github.com/Ousret/charset_normalizer/compare/3.0.1...3.1.0) (2023-03-06)
-
-### Added
-- Argument `should_rename_legacy` for legacy function `detect` and disregard any new arguments without errors (PR #262)
-
-### Removed
-- Support for Python 3.6 (PR #260)
-
-### Changed
-- Optional speedup provided by mypy/c 1.0.1
-
-## [3.0.1](https://github.com/Ousret/charset_normalizer/compare/3.0.0...3.0.1) (2022-11-18)
-
-### Fixed
-- Multi-bytes cutter/chunk generator did not always cut correctly (PR #233)
-
-### Changed
-- Speedup provided by mypy/c 0.990 on Python >= 3.7
-
-## [3.0.0](https://github.com/Ousret/charset_normalizer/compare/2.1.1...3.0.0) (2022-10-20)
-
-### Added
-- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results
-- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES
-- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio
-- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)
-
-### Changed
-- Build with static metadata using 'build' frontend
-- Make the language detection stricter
-- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1
-
-### Fixed
-- CLI with opt --normalize fail when using full path for files
-- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it
-- Sphinx warnings when generating the documentation
-
-### Removed
-- Coherence detector no longer return 'Simple English' instead return 'English'
-- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'
-- Breaking: Method `first()` and `best()` from CharsetMatch
-- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII)
-- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches
-- Breaking: Top-level function `normalize`
-- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch
-- Support for the backport `unicodedata2`
-
-## [3.0.0rc1](https://github.com/Ousret/charset_normalizer/compare/3.0.0b2...3.0.0rc1) (2022-10-18)
-
-### Added
-- Extend the capability of explain=True when cp_isolation contains at most two entries (min one), will log in details of the Mess-detector results
-- Support for alternative language frequency set in charset_normalizer.assets.FREQUENCIES
-- Add parameter `language_threshold` in `from_bytes`, `from_path` and `from_fp` to adjust the minimum expected coherence ratio
-
-### Changed
-- Build with static metadata using 'build' frontend
-- Make the language detection stricter
-
-### Fixed
-- CLI with opt --normalize fail when using full path for files
-- TooManyAccentuatedPlugin induce false positive on the mess detection when too few alpha character have been fed to it
-
-### Removed
-- Coherence detector no longer return 'Simple English' instead return 'English'
-- Coherence detector no longer return 'Classical Chinese' instead return 'Chinese'
-
-## [3.0.0b2](https://github.com/Ousret/charset_normalizer/compare/3.0.0b1...3.0.0b2) (2022-08-21)
-
-### Added
-- `normalizer --version` now specify if current version provide extra speedup (meaning mypyc compilation whl)
-
-### Removed
-- Breaking: Method `first()` and `best()` from CharsetMatch
-- UTF-7 will no longer appear as "detected" without a recognized SIG/mark (is unreliable/conflict with ASCII)
-
-### Fixed
-- Sphinx warnings when generating the documentation
-
-## [3.0.0b1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...3.0.0b1) (2022-08-15)
-
-### Changed
-- Optional: Module `md.py` can be compiled using Mypyc to provide an extra speedup up to 4x faster than v2.1
-
-### Removed
-- Breaking: Class aliases CharsetDetector, CharsetDoctor, CharsetNormalizerMatch and CharsetNormalizerMatches
-- Breaking: Top-level function `normalize`
-- Breaking: Properties `chaos_secondary_pass`, `coherence_non_latin` and `w_counter` from CharsetMatch
-- Support for the backport `unicodedata2`
-
-## [2.1.1](https://github.com/Ousret/charset_normalizer/compare/2.1.0...2.1.1) (2022-08-19)
-
-### Deprecated
-- Function `normalize` scheduled for removal in 3.0
-
-### Changed
-- Removed useless call to decode in fn is_unprintable (#206)
-
-### Fixed
-- Third-party library (i18n xgettext) crashing not recognizing utf_8 (PEP 263) with underscore from [@aleksandernovikov](https://github.com/aleksandernovikov) (#204)
-
-## [2.1.0](https://github.com/Ousret/charset_normalizer/compare/2.0.12...2.1.0) (2022-06-19)
-
-### Added
-- Output the Unicode table version when running the CLI with `--version` (PR #194)
-
-### Changed
-- Re-use decoded buffer for single byte character sets from [@nijel](https://github.com/nijel) (PR #175)
-- Fixing some performance bottlenecks from [@deedy5](https://github.com/deedy5) (PR #183)
-
-### Fixed
-- Workaround potential bug in cpython with Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space (PR #175)
-- CLI default threshold aligned with the API threshold from [@oleksandr-kuzmenko](https://github.com/oleksandr-kuzmenko) (PR #181)
-
-### Removed
-- Support for Python 3.5 (PR #192)
-
-### Deprecated
-- Use of backport unicodedata from `unicodedata2` as Python is quickly catching up, scheduled for removal in 3.0 (PR #194)
-
-## [2.0.12](https://github.com/Ousret/charset_normalizer/compare/2.0.11...2.0.12) (2022-02-12)
-
-### Fixed
-- ASCII miss-detection on rare cases (PR #170)
-
-## [2.0.11](https://github.com/Ousret/charset_normalizer/compare/2.0.10...2.0.11) (2022-01-30)
-
-### Added
-- Explicit support for Python 3.11 (PR #164)
-
-### Changed
-- The logging behavior have been completely reviewed, now using only TRACE and DEBUG levels (PR #163 #165)
-
-## [2.0.10](https://github.com/Ousret/charset_normalizer/compare/2.0.9...2.0.10) (2022-01-04)
-
-### Fixed
-- Fallback match entries might lead to UnicodeDecodeError for large bytes sequence (PR #154)
-
-### Changed
-- Skipping the language-detection (CD) on ASCII (PR #155)
-
-## [2.0.9](https://github.com/Ousret/charset_normalizer/compare/2.0.8...2.0.9) (2021-12-03)
-
-### Changed
-- Moderating the logging impact (since 2.0.8) for specific environments (PR #147)
-
-### Fixed
-- Wrong logging level applied when setting kwarg `explain` to True (PR #146)
-
-## [2.0.8](https://github.com/Ousret/charset_normalizer/compare/2.0.7...2.0.8) (2021-11-24)
-### Changed
-- Improvement over Vietnamese detection (PR #126)
-- MD improvement on trailing data and long foreign (non-pure latin) data (PR #124)
-- Efficiency improvements in cd/alphabet_languages from [@adbar](https://github.com/adbar) (PR #122)
-- call sum() without an intermediary list following PEP 289 recommendations from [@adbar](https://github.com/adbar) (PR #129)
-- Code style as refactored by Sourcery-AI (PR #131)
-- Minor adjustment on the MD around european words (PR #133)
-- Remove and replace SRTs from assets / tests (PR #139)
-- Initialize the library logger with a `NullHandler` by default from [@nmaynes](https://github.com/nmaynes) (PR #135)
-- Setting kwarg `explain` to True will add provisionally (bounded to function lifespan) a specific stream handler (PR #135)
-
-### Fixed
-- Fix large (misleading) sequence giving UnicodeDecodeError (PR #137)
-- Avoid using too insignificant chunk (PR #137)
-
-### Added
-- Add and expose function `set_logging_handler` to configure a specific StreamHandler from [@nmaynes](https://github.com/nmaynes) (PR #135)
-- Add `CHANGELOG.md` entries, format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) (PR #141)
-
-## [2.0.7](https://github.com/Ousret/charset_normalizer/compare/2.0.6...2.0.7) (2021-10-11)
-### Added
-- Add support for Kazakh (Cyrillic) language detection (PR #109)
-
-### Changed
-- Further, improve inferring the language from a given single-byte code page (PR #112)
-- Vainly trying to leverage PEP263 when PEP3120 is not supported (PR #116)
-- Refactoring for potential performance improvements in loops from [@adbar](https://github.com/adbar) (PR #113)
-- Various detection improvement (MD+CD) (PR #117)
-
-### Removed
-- Remove redundant logging entry about detected language(s) (PR #115)
-
-### Fixed
-- Fix a minor inconsistency between Python 3.5 and other versions regarding language detection (PR #117 #102)
-
-## [2.0.6](https://github.com/Ousret/charset_normalizer/compare/2.0.5...2.0.6) (2021-09-18)
-### Fixed
-- Unforeseen regression with the loss of the backward-compatibility with some older minor of Python 3.5.x (PR #100)
-- Fix CLI crash when using --minimal output in certain cases (PR #103)
-
-### Changed
-- Minor improvement to the detection efficiency (less than 1%) (PR #106 #101)
-
-## [2.0.5](https://github.com/Ousret/charset_normalizer/compare/2.0.4...2.0.5) (2021-09-14)
-### Changed
-- The project now comply with: flake8, mypy, isort and black to ensure a better overall quality (PR #81)
-- The BC-support with v1.x was improved, the old staticmethods are restored (PR #82)
-- The Unicode detection is slightly improved (PR #93)
-- Add syntax sugar \_\_bool\_\_ for results CharsetMatches list-container (PR #91)
-
-### Removed
-- The project no longer raise warning on tiny content given for detection, will be simply logged as warning instead (PR #92)
-
-### Fixed
-- In some rare case, the chunks extractor could cut in the middle of a multi-byte character and could mislead the mess detection (PR #95)
-- Some rare 'space' characters could trip up the UnprintablePlugin/Mess detection (PR #96)
-- The MANIFEST.in was not exhaustive (PR #78)
-
-## [2.0.4](https://github.com/Ousret/charset_normalizer/compare/2.0.3...2.0.4) (2021-07-30)
-### Fixed
-- The CLI no longer raise an unexpected exception when no encoding has been found (PR #70)
-- Fix accessing the 'alphabets' property when the payload contains surrogate characters (PR #68)
-- The logger could mislead (explain=True) on detected languages and the impact of one MBCS match (PR #72)
-- Submatch factoring could be wrong in rare edge cases (PR #72)
-- Multiple files given to the CLI were ignored when publishing results to STDOUT. (After the first path) (PR #72)
-- Fix line endings from CRLF to LF for certain project files (PR #67)
-
-### Changed
-- Adjust the MD to lower the sensitivity, thus improving the global detection reliability (PR #69 #76)
-- Allow fallback on specified encoding if any (PR #71)
-
-## [2.0.3](https://github.com/Ousret/charset_normalizer/compare/2.0.2...2.0.3) (2021-07-16)
-### Changed
-- Part of the detection mechanism has been improved to be less sensitive, resulting in more accurate detection results. Especially ASCII. (PR #63)
-- According to the community wishes, the detection will fall back on ASCII or UTF-8 in a last-resort case. (PR #64)
-
-## [2.0.2](https://github.com/Ousret/charset_normalizer/compare/2.0.1...2.0.2) (2021-07-15)
-### Fixed
-- Empty/Too small JSON payload miss-detection fixed. Report from [@tseaver](https://github.com/tseaver) (PR #59)
-
-### Changed
-- Don't inject unicodedata2 into sys.modules from [@akx](https://github.com/akx) (PR #57)
-
-## [2.0.1](https://github.com/Ousret/charset_normalizer/compare/2.0.0...2.0.1) (2021-07-13)
-### Fixed
-- Make it work where there isn't a filesystem available, dropping assets frequencies.json. Report from [@sethmlarson](https://github.com/sethmlarson). (PR #55)
-- Using explain=False permanently disable the verbose output in the current runtime (PR #47)
-- One log entry (language target preemptive) was not show in logs when using explain=True (PR #47)
-- Fix undesired exception (ValueError) on getitem of instance CharsetMatches (PR #52)
-
-### Changed
-- Public function normalize default args values were not aligned with from_bytes (PR #53)
-
-### Added
-- You may now use charset aliases in cp_isolation and cp_exclusion arguments (PR #47)
-
-## [2.0.0](https://github.com/Ousret/charset_normalizer/compare/1.4.1...2.0.0) (2021-07-02)
-### Changed
-- 4x to 5 times faster than the previous 1.4.0 release. At least 2x faster than Chardet.
-- Accent has been made on UTF-8 detection, should perform rather instantaneous.
-- The backward compatibility with Chardet has been greatly improved. The legacy detect function returns an identical charset name whenever possible.
-- The detection mechanism has been slightly improved, now Turkish content is detected correctly (most of the time)
-- The program has been rewritten to ease the readability and maintainability. (+Using static typing)+
-- utf_7 detection has been reinstated.
-
-### Removed
-- This package no longer require anything when used with Python 3.5 (Dropped cached_property)
-- Removed support for these languages: Catalan, Esperanto, Kazakh, Baque, Volapük, Azeri, Galician, Nynorsk, Macedonian, and Serbocroatian.
-- The exception hook on UnicodeDecodeError has been removed.
-
-### Deprecated
-- Methods coherence_non_latin, w_counter, chaos_secondary_pass of the class CharsetMatch are now deprecated and scheduled for removal in v3.0
-
-### Fixed
-- The CLI output used the relative path of the file(s). Should be absolute.
-
-## [1.4.1](https://github.com/Ousret/charset_normalizer/compare/1.4.0...1.4.1) (2021-05-28)
-### Fixed
-- Logger configuration/usage no longer conflict with others (PR #44)
-
-## [1.4.0](https://github.com/Ousret/charset_normalizer/compare/1.3.9...1.4.0) (2021-05-21)
-### Removed
-- Using standard logging instead of using the package loguru.
-- Dropping nose test framework in favor of the maintained pytest.
-- Choose to not use dragonmapper package to help with gibberish Chinese/CJK text.
-- Require cached_property only for Python 3.5 due to constraint. Dropping for every other interpreter version.
-- Stop support for UTF-7 that does not contain a SIG.
-- Dropping PrettyTable, replaced with pure JSON output in CLI.
-
-### Fixed
-- BOM marker in a CharsetNormalizerMatch instance could be False in rare cases even if obviously present. Due to the sub-match factoring process.
-- Not searching properly for the BOM when trying utf32/16 parent codec.
-
-### Changed
-- Improving the package final size by compressing frequencies.json.
-- Huge improvement over the larges payload.
-
-### Added
-- CLI now produces JSON consumable output.
-- Return ASCII if given sequences fit. Given reasonable confidence.
-
-## [1.3.9](https://github.com/Ousret/charset_normalizer/compare/1.3.8...1.3.9) (2021-05-13)
-
-### Fixed
-- In some very rare cases, you may end up getting encode/decode errors due to a bad bytes payload (PR #40)
-
-## [1.3.8](https://github.com/Ousret/charset_normalizer/compare/1.3.7...1.3.8) (2021-05-12)
-
-### Fixed
-- Empty given payload for detection may cause an exception if trying to access the `alphabets` property. (PR #39)
-
-## [1.3.7](https://github.com/Ousret/charset_normalizer/compare/1.3.6...1.3.7) (2021-05-12)
-
-### Fixed
-- The legacy detect function should return UTF-8-SIG if sig is present in the payload. (PR #38)
-
-## [1.3.6](https://github.com/Ousret/charset_normalizer/compare/1.3.5...1.3.6) (2021-02-09)
-
-### Changed
-- Amend the previous release to allow prettytable 2.0 (PR #35)
-
-## [1.3.5](https://github.com/Ousret/charset_normalizer/compare/1.3.4...1.3.5) (2021-02-08)
-
-### Fixed
-- Fix error while using the package with a python pre-release interpreter (PR #33)
-
-### Changed
-- Dependencies refactoring, constraints revised.
-
-### Added
-- Add python 3.9 and 3.10 to the supported interpreters
-
-MIT License
-
-Copyright (c) 2019 TAHRI Ahmed R.
-
-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.
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/RECORD b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/RECORD
deleted file mode 100644
index 134cd2f..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/RECORD
+++ /dev/null
@@ -1,35 +0,0 @@
-../../../bin/normalizer,sha256=TGGzGCiTm-yLw6gQOEfPQonWoeOkPWp5W4b1RAbka20,260
-charset_normalizer-3.3.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-charset_normalizer-3.3.2.dist-info/LICENSE,sha256=6zGgxaT7Cbik4yBV0lweX5w1iidS_vPNcgIT0cz-4kE,1070
-charset_normalizer-3.3.2.dist-info/METADATA,sha256=cfLhl5A6SI-F0oclm8w8ux9wshL1nipdeCdVnYb4AaA,33550
-charset_normalizer-3.3.2.dist-info/RECORD,,
-charset_normalizer-3.3.2.dist-info/WHEEL,sha256=4ZiCdXIWMxJyEClivrQv1QAHZpQh8kVYU92_ZAVwaok,152
-charset_normalizer-3.3.2.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65
-charset_normalizer-3.3.2.dist-info/top_level.txt,sha256=7ASyzePr8_xuZWJsnqJjIBtyV8vhEo0wBCv1MPRRi3Q,19
-charset_normalizer/__init__.py,sha256=UzI3xC8PhmcLRMzSgPb6minTmRq0kWznnCBJ8ZCc2XI,1577
-charset_normalizer/__main__.py,sha256=JxY8bleaENOFlLRb9HfoeZCzAMnn2A1oGR5Xm2eyqg0,73
-charset_normalizer/__pycache__/__init__.cpython-312.pyc,,
-charset_normalizer/__pycache__/__main__.cpython-312.pyc,,
-charset_normalizer/__pycache__/api.cpython-312.pyc,,
-charset_normalizer/__pycache__/cd.cpython-312.pyc,,
-charset_normalizer/__pycache__/constant.cpython-312.pyc,,
-charset_normalizer/__pycache__/legacy.cpython-312.pyc,,
-charset_normalizer/__pycache__/md.cpython-312.pyc,,
-charset_normalizer/__pycache__/models.cpython-312.pyc,,
-charset_normalizer/__pycache__/utils.cpython-312.pyc,,
-charset_normalizer/__pycache__/version.cpython-312.pyc,,
-charset_normalizer/api.py,sha256=WOlWjy6wT8SeMYFpaGbXZFN1TMXa-s8vZYfkL4G29iQ,21097
-charset_normalizer/cd.py,sha256=xwZliZcTQFA3jU0c00PRiu9MNxXTFxQkFLWmMW24ZzI,12560
-charset_normalizer/cli/__init__.py,sha256=D5ERp8P62llm2FuoMzydZ7d9rs8cvvLXqE-1_6oViPc,100
-charset_normalizer/cli/__main__.py,sha256=2F-xURZJzo063Ye-2RLJ2wcmURpbKeAzKwpiws65dAs,9744
-charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc,,
-charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc,,
-charset_normalizer/constant.py,sha256=p0IsOVcEbPWYPOdWhnhRbjK1YVBy6fs05C5vKC-zoxU,40481
-charset_normalizer/legacy.py,sha256=T-QuVMsMeDiQEk8WSszMrzVJg_14AMeSkmHdRYhdl1k,2071
-charset_normalizer/md.cpython-312-x86_64-linux-gnu.so,sha256=W654QTU3QZI6eWJ0fanScAr0_O6sL0I61fyRSdC-39Y,16064
-charset_normalizer/md.py,sha256=NkSuVLK13_a8c7BxZ4cGIQ5vOtGIWOdh22WZEvjp-7U,19624
-charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so,sha256=IlObIV4dmRhFV8V7H-zK4rTxPzTSi9JmrWZD26JQfxI,272640
-charset_normalizer/models.py,sha256=I5i0s4aKCCgLPY2tUY3pwkgFA-BUbbNxQ7hVkVTt62s,11624
-charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-charset_normalizer/utils.py,sha256=teiosMqzKjXyAHXnGdjSBOgnBZwx-SkBbCLrx0UXy8M,11894
-charset_normalizer/version.py,sha256=iHKUfHD3kDRSyrh_BN2ojh43TA5-UZQjvbVIEFfpHDs,79
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL
deleted file mode 100644
index d1b3f1d..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL
+++ /dev/null
@@ -1,6 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.41.2)
-Root-Is-Purelib: false
-Tag: cp312-cp312-manylinux_2_17_x86_64
-Tag: cp312-cp312-manylinux2014_x86_64
-
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt
deleted file mode 100644
index 65619e7..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt
+++ /dev/null
@@ -1,2 +0,0 @@
-[console_scripts]
-normalizer = charset_normalizer.cli:cli_detect
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt b/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt
deleted file mode 100644
index 66958f0..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-charset_normalizer
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__init__.py b/.venv/lib/python3.12/site-packages/charset_normalizer/__init__.py
deleted file mode 100644
index 55991fc..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/__init__.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- coding: utf-8 -*-
-"""
-Charset-Normalizer
-~~~~~~~~~~~~~~
-The Real First Universal Charset Detector.
-A library that helps you read text from an unknown charset encoding.
-Motivated by chardet, This package is trying to resolve the issue by taking a new approach.
-All IANA character set names for which the Python core library provides codecs are supported.
-
-Basic usage:
- >>> from charset_normalizer import from_bytes
- >>> results = from_bytes('Bсеки човек има право на образование. Oбразованието!'.encode('utf_8'))
- >>> best_guess = results.best()
- >>> str(best_guess)
- 'Bсеки човек има право на образование. Oбразованието!'
-
-Others methods and usages are available - see the full documentation
-at .
-:copyright: (c) 2021 by Ahmed TAHRI
-:license: MIT, see LICENSE for more details.
-"""
-import logging
-
-from .api import from_bytes, from_fp, from_path, is_binary
-from .legacy import detect
-from .models import CharsetMatch, CharsetMatches
-from .utils import set_logging_handler
-from .version import VERSION, __version__
-
-__all__ = (
- "from_fp",
- "from_path",
- "from_bytes",
- "is_binary",
- "detect",
- "CharsetMatch",
- "CharsetMatches",
- "__version__",
- "VERSION",
- "set_logging_handler",
-)
-
-# Attach a NullHandler to the top level logger by default
-# https://docs.python.org/3.3/howto/logging.html#configuring-logging-for-a-library
-
-logging.getLogger("charset_normalizer").addHandler(logging.NullHandler())
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__main__.py b/.venv/lib/python3.12/site-packages/charset_normalizer/__main__.py
deleted file mode 100644
index beae2ef..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/__main__.py
+++ /dev/null
@@ -1,4 +0,0 @@
-from .cli import cli_detect
-
-if __name__ == "__main__":
- cli_detect()
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index a97259a..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc
deleted file mode 100644
index 0b24403..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/__main__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc
deleted file mode 100644
index 4ccbcdb..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/api.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc
deleted file mode 100644
index 19dd405..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/cd.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc
deleted file mode 100644
index 90edd16..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/constant.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc
deleted file mode 100644
index d575cee..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/legacy.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc
deleted file mode 100644
index 3b2df9d..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/md.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc
deleted file mode 100644
index bbf4542..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/models.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc
deleted file mode 100644
index f28a8ca..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/utils.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc
deleted file mode 100644
index 5c92f3f..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/__pycache__/version.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/api.py b/.venv/lib/python3.12/site-packages/charset_normalizer/api.py
deleted file mode 100644
index 0ba08e3..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/api.py
+++ /dev/null
@@ -1,626 +0,0 @@
-import logging
-from os import PathLike
-from typing import BinaryIO, List, Optional, Set, Union
-
-from .cd import (
- coherence_ratio,
- encoding_languages,
- mb_encoding_languages,
- merge_coherence_ratios,
-)
-from .constant import IANA_SUPPORTED, TOO_BIG_SEQUENCE, TOO_SMALL_SEQUENCE, TRACE
-from .md import mess_ratio
-from .models import CharsetMatch, CharsetMatches
-from .utils import (
- any_specified_encoding,
- cut_sequence_chunks,
- iana_name,
- identify_sig_or_bom,
- is_cp_similar,
- is_multi_byte_encoding,
- should_strip_sig_or_bom,
-)
-
-# Will most likely be controversial
-# logging.addLevelName(TRACE, "TRACE")
-logger = logging.getLogger("charset_normalizer")
-explain_handler = logging.StreamHandler()
-explain_handler.setFormatter(
- logging.Formatter("%(asctime)s | %(levelname)s | %(message)s")
-)
-
-
-def from_bytes(
- sequences: Union[bytes, bytearray],
- steps: int = 5,
- chunk_size: int = 512,
- threshold: float = 0.2,
- cp_isolation: Optional[List[str]] = None,
- cp_exclusion: Optional[List[str]] = None,
- preemptive_behaviour: bool = True,
- explain: bool = False,
- language_threshold: float = 0.1,
- enable_fallback: bool = True,
-) -> CharsetMatches:
- """
- Given a raw bytes sequence, return the best possibles charset usable to render str objects.
- If there is no results, it is a strong indicator that the source is binary/not text.
- By default, the process will extract 5 blocks of 512o each to assess the mess and coherence of a given sequence.
- And will give up a particular code page after 20% of measured mess. Those criteria are customizable at will.
-
- The preemptive behavior DOES NOT replace the traditional detection workflow, it prioritize a particular code page
- but never take it for granted. Can improve the performance.
-
- You may want to focus your attention to some code page or/and not others, use cp_isolation and cp_exclusion for that
- purpose.
-
- This function will strip the SIG in the payload/sequence every time except on UTF-16, UTF-32.
- By default the library does not setup any handler other than the NullHandler, if you choose to set the 'explain'
- toggle to True it will alter the logger configuration to add a StreamHandler that is suitable for debugging.
- Custom logging format and handler can be set manually.
- """
-
- if not isinstance(sequences, (bytearray, bytes)):
- raise TypeError(
- "Expected object of type bytes or bytearray, got: {0}".format(
- type(sequences)
- )
- )
-
- if explain:
- previous_logger_level: int = logger.level
- logger.addHandler(explain_handler)
- logger.setLevel(TRACE)
-
- length: int = len(sequences)
-
- if length == 0:
- logger.debug("Encoding detection on empty bytes, assuming utf_8 intention.")
- if explain:
- logger.removeHandler(explain_handler)
- logger.setLevel(previous_logger_level or logging.WARNING)
- return CharsetMatches([CharsetMatch(sequences, "utf_8", 0.0, False, [], "")])
-
- if cp_isolation is not None:
- logger.log(
- TRACE,
- "cp_isolation is set. use this flag for debugging purpose. "
- "limited list of encoding allowed : %s.",
- ", ".join(cp_isolation),
- )
- cp_isolation = [iana_name(cp, False) for cp in cp_isolation]
- else:
- cp_isolation = []
-
- if cp_exclusion is not None:
- logger.log(
- TRACE,
- "cp_exclusion is set. use this flag for debugging purpose. "
- "limited list of encoding excluded : %s.",
- ", ".join(cp_exclusion),
- )
- cp_exclusion = [iana_name(cp, False) for cp in cp_exclusion]
- else:
- cp_exclusion = []
-
- if length <= (chunk_size * steps):
- logger.log(
- TRACE,
- "override steps (%i) and chunk_size (%i) as content does not fit (%i byte(s) given) parameters.",
- steps,
- chunk_size,
- length,
- )
- steps = 1
- chunk_size = length
-
- if steps > 1 and length / steps < chunk_size:
- chunk_size = int(length / steps)
-
- is_too_small_sequence: bool = len(sequences) < TOO_SMALL_SEQUENCE
- is_too_large_sequence: bool = len(sequences) >= TOO_BIG_SEQUENCE
-
- if is_too_small_sequence:
- logger.log(
- TRACE,
- "Trying to detect encoding from a tiny portion of ({}) byte(s).".format(
- length
- ),
- )
- elif is_too_large_sequence:
- logger.log(
- TRACE,
- "Using lazy str decoding because the payload is quite large, ({}) byte(s).".format(
- length
- ),
- )
-
- prioritized_encodings: List[str] = []
-
- specified_encoding: Optional[str] = (
- any_specified_encoding(sequences) if preemptive_behaviour else None
- )
-
- if specified_encoding is not None:
- prioritized_encodings.append(specified_encoding)
- logger.log(
- TRACE,
- "Detected declarative mark in sequence. Priority +1 given for %s.",
- specified_encoding,
- )
-
- tested: Set[str] = set()
- tested_but_hard_failure: List[str] = []
- tested_but_soft_failure: List[str] = []
-
- fallback_ascii: Optional[CharsetMatch] = None
- fallback_u8: Optional[CharsetMatch] = None
- fallback_specified: Optional[CharsetMatch] = None
-
- results: CharsetMatches = CharsetMatches()
-
- sig_encoding, sig_payload = identify_sig_or_bom(sequences)
-
- if sig_encoding is not None:
- prioritized_encodings.append(sig_encoding)
- logger.log(
- TRACE,
- "Detected a SIG or BOM mark on first %i byte(s). Priority +1 given for %s.",
- len(sig_payload),
- sig_encoding,
- )
-
- prioritized_encodings.append("ascii")
-
- if "utf_8" not in prioritized_encodings:
- prioritized_encodings.append("utf_8")
-
- for encoding_iana in prioritized_encodings + IANA_SUPPORTED:
- if cp_isolation and encoding_iana not in cp_isolation:
- continue
-
- if cp_exclusion and encoding_iana in cp_exclusion:
- continue
-
- if encoding_iana in tested:
- continue
-
- tested.add(encoding_iana)
-
- decoded_payload: Optional[str] = None
- bom_or_sig_available: bool = sig_encoding == encoding_iana
- strip_sig_or_bom: bool = bom_or_sig_available and should_strip_sig_or_bom(
- encoding_iana
- )
-
- if encoding_iana in {"utf_16", "utf_32"} and not bom_or_sig_available:
- logger.log(
- TRACE,
- "Encoding %s won't be tested as-is because it require a BOM. Will try some sub-encoder LE/BE.",
- encoding_iana,
- )
- continue
- if encoding_iana in {"utf_7"} and not bom_or_sig_available:
- logger.log(
- TRACE,
- "Encoding %s won't be tested as-is because detection is unreliable without BOM/SIG.",
- encoding_iana,
- )
- continue
-
- try:
- is_multi_byte_decoder: bool = is_multi_byte_encoding(encoding_iana)
- except (ModuleNotFoundError, ImportError):
- logger.log(
- TRACE,
- "Encoding %s does not provide an IncrementalDecoder",
- encoding_iana,
- )
- continue
-
- try:
- if is_too_large_sequence and is_multi_byte_decoder is False:
- str(
- sequences[: int(50e4)]
- if strip_sig_or_bom is False
- else sequences[len(sig_payload) : int(50e4)],
- encoding=encoding_iana,
- )
- else:
- decoded_payload = str(
- sequences
- if strip_sig_or_bom is False
- else sequences[len(sig_payload) :],
- encoding=encoding_iana,
- )
- except (UnicodeDecodeError, LookupError) as e:
- if not isinstance(e, LookupError):
- logger.log(
- TRACE,
- "Code page %s does not fit given bytes sequence at ALL. %s",
- encoding_iana,
- str(e),
- )
- tested_but_hard_failure.append(encoding_iana)
- continue
-
- similar_soft_failure_test: bool = False
-
- for encoding_soft_failed in tested_but_soft_failure:
- if is_cp_similar(encoding_iana, encoding_soft_failed):
- similar_soft_failure_test = True
- break
-
- if similar_soft_failure_test:
- logger.log(
- TRACE,
- "%s is deemed too similar to code page %s and was consider unsuited already. Continuing!",
- encoding_iana,
- encoding_soft_failed,
- )
- continue
-
- r_ = range(
- 0 if not bom_or_sig_available else len(sig_payload),
- length,
- int(length / steps),
- )
-
- multi_byte_bonus: bool = (
- is_multi_byte_decoder
- and decoded_payload is not None
- and len(decoded_payload) < length
- )
-
- if multi_byte_bonus:
- logger.log(
- TRACE,
- "Code page %s is a multi byte encoding table and it appear that at least one character "
- "was encoded using n-bytes.",
- encoding_iana,
- )
-
- max_chunk_gave_up: int = int(len(r_) / 4)
-
- max_chunk_gave_up = max(max_chunk_gave_up, 2)
- early_stop_count: int = 0
- lazy_str_hard_failure = False
-
- md_chunks: List[str] = []
- md_ratios = []
-
- try:
- for chunk in cut_sequence_chunks(
- sequences,
- encoding_iana,
- r_,
- chunk_size,
- bom_or_sig_available,
- strip_sig_or_bom,
- sig_payload,
- is_multi_byte_decoder,
- decoded_payload,
- ):
- md_chunks.append(chunk)
-
- md_ratios.append(
- mess_ratio(
- chunk,
- threshold,
- explain is True and 1 <= len(cp_isolation) <= 2,
- )
- )
-
- if md_ratios[-1] >= threshold:
- early_stop_count += 1
-
- if (early_stop_count >= max_chunk_gave_up) or (
- bom_or_sig_available and strip_sig_or_bom is False
- ):
- break
- except (
- UnicodeDecodeError
- ) as e: # Lazy str loading may have missed something there
- logger.log(
- TRACE,
- "LazyStr Loading: After MD chunk decode, code page %s does not fit given bytes sequence at ALL. %s",
- encoding_iana,
- str(e),
- )
- early_stop_count = max_chunk_gave_up
- lazy_str_hard_failure = True
-
- # We might want to check the sequence again with the whole content
- # Only if initial MD tests passes
- if (
- not lazy_str_hard_failure
- and is_too_large_sequence
- and not is_multi_byte_decoder
- ):
- try:
- sequences[int(50e3) :].decode(encoding_iana, errors="strict")
- except UnicodeDecodeError as e:
- logger.log(
- TRACE,
- "LazyStr Loading: After final lookup, code page %s does not fit given bytes sequence at ALL. %s",
- encoding_iana,
- str(e),
- )
- tested_but_hard_failure.append(encoding_iana)
- continue
-
- mean_mess_ratio: float = sum(md_ratios) / len(md_ratios) if md_ratios else 0.0
- if mean_mess_ratio >= threshold or early_stop_count >= max_chunk_gave_up:
- tested_but_soft_failure.append(encoding_iana)
- logger.log(
- TRACE,
- "%s was excluded because of initial chaos probing. Gave up %i time(s). "
- "Computed mean chaos is %f %%.",
- encoding_iana,
- early_stop_count,
- round(mean_mess_ratio * 100, ndigits=3),
- )
- # Preparing those fallbacks in case we got nothing.
- if (
- enable_fallback
- and encoding_iana in ["ascii", "utf_8", specified_encoding]
- and not lazy_str_hard_failure
- ):
- fallback_entry = CharsetMatch(
- sequences, encoding_iana, threshold, False, [], decoded_payload
- )
- if encoding_iana == specified_encoding:
- fallback_specified = fallback_entry
- elif encoding_iana == "ascii":
- fallback_ascii = fallback_entry
- else:
- fallback_u8 = fallback_entry
- continue
-
- logger.log(
- TRACE,
- "%s passed initial chaos probing. Mean measured chaos is %f %%",
- encoding_iana,
- round(mean_mess_ratio * 100, ndigits=3),
- )
-
- if not is_multi_byte_decoder:
- target_languages: List[str] = encoding_languages(encoding_iana)
- else:
- target_languages = mb_encoding_languages(encoding_iana)
-
- if target_languages:
- logger.log(
- TRACE,
- "{} should target any language(s) of {}".format(
- encoding_iana, str(target_languages)
- ),
- )
-
- cd_ratios = []
-
- # We shall skip the CD when its about ASCII
- # Most of the time its not relevant to run "language-detection" on it.
- if encoding_iana != "ascii":
- for chunk in md_chunks:
- chunk_languages = coherence_ratio(
- chunk,
- language_threshold,
- ",".join(target_languages) if target_languages else None,
- )
-
- cd_ratios.append(chunk_languages)
-
- cd_ratios_merged = merge_coherence_ratios(cd_ratios)
-
- if cd_ratios_merged:
- logger.log(
- TRACE,
- "We detected language {} using {}".format(
- cd_ratios_merged, encoding_iana
- ),
- )
-
- results.append(
- CharsetMatch(
- sequences,
- encoding_iana,
- mean_mess_ratio,
- bom_or_sig_available,
- cd_ratios_merged,
- decoded_payload,
- )
- )
-
- if (
- encoding_iana in [specified_encoding, "ascii", "utf_8"]
- and mean_mess_ratio < 0.1
- ):
- logger.debug(
- "Encoding detection: %s is most likely the one.", encoding_iana
- )
- if explain:
- logger.removeHandler(explain_handler)
- logger.setLevel(previous_logger_level)
- return CharsetMatches([results[encoding_iana]])
-
- if encoding_iana == sig_encoding:
- logger.debug(
- "Encoding detection: %s is most likely the one as we detected a BOM or SIG within "
- "the beginning of the sequence.",
- encoding_iana,
- )
- if explain:
- logger.removeHandler(explain_handler)
- logger.setLevel(previous_logger_level)
- return CharsetMatches([results[encoding_iana]])
-
- if len(results) == 0:
- if fallback_u8 or fallback_ascii or fallback_specified:
- logger.log(
- TRACE,
- "Nothing got out of the detection process. Using ASCII/UTF-8/Specified fallback.",
- )
-
- if fallback_specified:
- logger.debug(
- "Encoding detection: %s will be used as a fallback match",
- fallback_specified.encoding,
- )
- results.append(fallback_specified)
- elif (
- (fallback_u8 and fallback_ascii is None)
- or (
- fallback_u8
- and fallback_ascii
- and fallback_u8.fingerprint != fallback_ascii.fingerprint
- )
- or (fallback_u8 is not None)
- ):
- logger.debug("Encoding detection: utf_8 will be used as a fallback match")
- results.append(fallback_u8)
- elif fallback_ascii:
- logger.debug("Encoding detection: ascii will be used as a fallback match")
- results.append(fallback_ascii)
-
- if results:
- logger.debug(
- "Encoding detection: Found %s as plausible (best-candidate) for content. With %i alternatives.",
- results.best().encoding, # type: ignore
- len(results) - 1,
- )
- else:
- logger.debug("Encoding detection: Unable to determine any suitable charset.")
-
- if explain:
- logger.removeHandler(explain_handler)
- logger.setLevel(previous_logger_level)
-
- return results
-
-
-def from_fp(
- fp: BinaryIO,
- steps: int = 5,
- chunk_size: int = 512,
- threshold: float = 0.20,
- cp_isolation: Optional[List[str]] = None,
- cp_exclusion: Optional[List[str]] = None,
- preemptive_behaviour: bool = True,
- explain: bool = False,
- language_threshold: float = 0.1,
- enable_fallback: bool = True,
-) -> CharsetMatches:
- """
- Same thing than the function from_bytes but using a file pointer that is already ready.
- Will not close the file pointer.
- """
- return from_bytes(
- fp.read(),
- steps,
- chunk_size,
- threshold,
- cp_isolation,
- cp_exclusion,
- preemptive_behaviour,
- explain,
- language_threshold,
- enable_fallback,
- )
-
-
-def from_path(
- path: Union[str, bytes, PathLike], # type: ignore[type-arg]
- steps: int = 5,
- chunk_size: int = 512,
- threshold: float = 0.20,
- cp_isolation: Optional[List[str]] = None,
- cp_exclusion: Optional[List[str]] = None,
- preemptive_behaviour: bool = True,
- explain: bool = False,
- language_threshold: float = 0.1,
- enable_fallback: bool = True,
-) -> CharsetMatches:
- """
- Same thing than the function from_bytes but with one extra step. Opening and reading given file path in binary mode.
- Can raise IOError.
- """
- with open(path, "rb") as fp:
- return from_fp(
- fp,
- steps,
- chunk_size,
- threshold,
- cp_isolation,
- cp_exclusion,
- preemptive_behaviour,
- explain,
- language_threshold,
- enable_fallback,
- )
-
-
-def is_binary(
- fp_or_path_or_payload: Union[PathLike, str, BinaryIO, bytes], # type: ignore[type-arg]
- steps: int = 5,
- chunk_size: int = 512,
- threshold: float = 0.20,
- cp_isolation: Optional[List[str]] = None,
- cp_exclusion: Optional[List[str]] = None,
- preemptive_behaviour: bool = True,
- explain: bool = False,
- language_threshold: float = 0.1,
- enable_fallback: bool = False,
-) -> bool:
- """
- Detect if the given input (file, bytes, or path) points to a binary file. aka. not a string.
- Based on the same main heuristic algorithms and default kwargs at the sole exception that fallbacks match
- are disabled to be stricter around ASCII-compatible but unlikely to be a string.
- """
- if isinstance(fp_or_path_or_payload, (str, PathLike)):
- guesses = from_path(
- fp_or_path_or_payload,
- steps=steps,
- chunk_size=chunk_size,
- threshold=threshold,
- cp_isolation=cp_isolation,
- cp_exclusion=cp_exclusion,
- preemptive_behaviour=preemptive_behaviour,
- explain=explain,
- language_threshold=language_threshold,
- enable_fallback=enable_fallback,
- )
- elif isinstance(
- fp_or_path_or_payload,
- (
- bytes,
- bytearray,
- ),
- ):
- guesses = from_bytes(
- fp_or_path_or_payload,
- steps=steps,
- chunk_size=chunk_size,
- threshold=threshold,
- cp_isolation=cp_isolation,
- cp_exclusion=cp_exclusion,
- preemptive_behaviour=preemptive_behaviour,
- explain=explain,
- language_threshold=language_threshold,
- enable_fallback=enable_fallback,
- )
- else:
- guesses = from_fp(
- fp_or_path_or_payload,
- steps=steps,
- chunk_size=chunk_size,
- threshold=threshold,
- cp_isolation=cp_isolation,
- cp_exclusion=cp_exclusion,
- preemptive_behaviour=preemptive_behaviour,
- explain=explain,
- language_threshold=language_threshold,
- enable_fallback=enable_fallback,
- )
-
- return not guesses
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/cd.py b/.venv/lib/python3.12/site-packages/charset_normalizer/cd.py
deleted file mode 100644
index 4ea6760..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/cd.py
+++ /dev/null
@@ -1,395 +0,0 @@
-import importlib
-from codecs import IncrementalDecoder
-from collections import Counter
-from functools import lru_cache
-from typing import Counter as TypeCounter, Dict, List, Optional, Tuple
-
-from .constant import (
- FREQUENCIES,
- KO_NAMES,
- LANGUAGE_SUPPORTED_COUNT,
- TOO_SMALL_SEQUENCE,
- ZH_NAMES,
-)
-from .md import is_suspiciously_successive_range
-from .models import CoherenceMatches
-from .utils import (
- is_accentuated,
- is_latin,
- is_multi_byte_encoding,
- is_unicode_range_secondary,
- unicode_range,
-)
-
-
-def encoding_unicode_range(iana_name: str) -> List[str]:
- """
- Return associated unicode ranges in a single byte code page.
- """
- if is_multi_byte_encoding(iana_name):
- raise IOError("Function not supported on multi-byte code page")
-
- decoder = importlib.import_module(
- "encodings.{}".format(iana_name)
- ).IncrementalDecoder
-
- p: IncrementalDecoder = decoder(errors="ignore")
- seen_ranges: Dict[str, int] = {}
- character_count: int = 0
-
- for i in range(0x40, 0xFF):
- chunk: str = p.decode(bytes([i]))
-
- if chunk:
- character_range: Optional[str] = unicode_range(chunk)
-
- if character_range is None:
- continue
-
- if is_unicode_range_secondary(character_range) is False:
- if character_range not in seen_ranges:
- seen_ranges[character_range] = 0
- seen_ranges[character_range] += 1
- character_count += 1
-
- return sorted(
- [
- character_range
- for character_range in seen_ranges
- if seen_ranges[character_range] / character_count >= 0.15
- ]
- )
-
-
-def unicode_range_languages(primary_range: str) -> List[str]:
- """
- Return inferred languages used with a unicode range.
- """
- languages: List[str] = []
-
- for language, characters in FREQUENCIES.items():
- for character in characters:
- if unicode_range(character) == primary_range:
- languages.append(language)
- break
-
- return languages
-
-
-@lru_cache()
-def encoding_languages(iana_name: str) -> List[str]:
- """
- Single-byte encoding language association. Some code page are heavily linked to particular language(s).
- This function does the correspondence.
- """
- unicode_ranges: List[str] = encoding_unicode_range(iana_name)
- primary_range: Optional[str] = None
-
- for specified_range in unicode_ranges:
- if "Latin" not in specified_range:
- primary_range = specified_range
- break
-
- if primary_range is None:
- return ["Latin Based"]
-
- return unicode_range_languages(primary_range)
-
-
-@lru_cache()
-def mb_encoding_languages(iana_name: str) -> List[str]:
- """
- Multi-byte encoding language association. Some code page are heavily linked to particular language(s).
- This function does the correspondence.
- """
- if (
- iana_name.startswith("shift_")
- or iana_name.startswith("iso2022_jp")
- or iana_name.startswith("euc_j")
- or iana_name == "cp932"
- ):
- return ["Japanese"]
- if iana_name.startswith("gb") or iana_name in ZH_NAMES:
- return ["Chinese"]
- if iana_name.startswith("iso2022_kr") or iana_name in KO_NAMES:
- return ["Korean"]
-
- return []
-
-
-@lru_cache(maxsize=LANGUAGE_SUPPORTED_COUNT)
-def get_target_features(language: str) -> Tuple[bool, bool]:
- """
- Determine main aspects from a supported language if it contains accents and if is pure Latin.
- """
- target_have_accents: bool = False
- target_pure_latin: bool = True
-
- for character in FREQUENCIES[language]:
- if not target_have_accents and is_accentuated(character):
- target_have_accents = True
- if target_pure_latin and is_latin(character) is False:
- target_pure_latin = False
-
- return target_have_accents, target_pure_latin
-
-
-def alphabet_languages(
- characters: List[str], ignore_non_latin: bool = False
-) -> List[str]:
- """
- Return associated languages associated to given characters.
- """
- languages: List[Tuple[str, float]] = []
-
- source_have_accents = any(is_accentuated(character) for character in characters)
-
- for language, language_characters in FREQUENCIES.items():
- target_have_accents, target_pure_latin = get_target_features(language)
-
- if ignore_non_latin and target_pure_latin is False:
- continue
-
- if target_have_accents is False and source_have_accents:
- continue
-
- character_count: int = len(language_characters)
-
- character_match_count: int = len(
- [c for c in language_characters if c in characters]
- )
-
- ratio: float = character_match_count / character_count
-
- if ratio >= 0.2:
- languages.append((language, ratio))
-
- languages = sorted(languages, key=lambda x: x[1], reverse=True)
-
- return [compatible_language[0] for compatible_language in languages]
-
-
-def characters_popularity_compare(
- language: str, ordered_characters: List[str]
-) -> float:
- """
- Determine if a ordered characters list (by occurrence from most appearance to rarest) match a particular language.
- The result is a ratio between 0. (absolutely no correspondence) and 1. (near perfect fit).
- Beware that is function is not strict on the match in order to ease the detection. (Meaning close match is 1.)
- """
- if language not in FREQUENCIES:
- raise ValueError("{} not available".format(language))
-
- character_approved_count: int = 0
- FREQUENCIES_language_set = set(FREQUENCIES[language])
-
- ordered_characters_count: int = len(ordered_characters)
- target_language_characters_count: int = len(FREQUENCIES[language])
-
- large_alphabet: bool = target_language_characters_count > 26
-
- for character, character_rank in zip(
- ordered_characters, range(0, ordered_characters_count)
- ):
- if character not in FREQUENCIES_language_set:
- continue
-
- character_rank_in_language: int = FREQUENCIES[language].index(character)
- expected_projection_ratio: float = (
- target_language_characters_count / ordered_characters_count
- )
- character_rank_projection: int = int(character_rank * expected_projection_ratio)
-
- if (
- large_alphabet is False
- and abs(character_rank_projection - character_rank_in_language) > 4
- ):
- continue
-
- if (
- large_alphabet is True
- and abs(character_rank_projection - character_rank_in_language)
- < target_language_characters_count / 3
- ):
- character_approved_count += 1
- continue
-
- characters_before_source: List[str] = FREQUENCIES[language][
- 0:character_rank_in_language
- ]
- characters_after_source: List[str] = FREQUENCIES[language][
- character_rank_in_language:
- ]
- characters_before: List[str] = ordered_characters[0:character_rank]
- characters_after: List[str] = ordered_characters[character_rank:]
-
- before_match_count: int = len(
- set(characters_before) & set(characters_before_source)
- )
-
- after_match_count: int = len(
- set(characters_after) & set(characters_after_source)
- )
-
- if len(characters_before_source) == 0 and before_match_count <= 4:
- character_approved_count += 1
- continue
-
- if len(characters_after_source) == 0 and after_match_count <= 4:
- character_approved_count += 1
- continue
-
- if (
- before_match_count / len(characters_before_source) >= 0.4
- or after_match_count / len(characters_after_source) >= 0.4
- ):
- character_approved_count += 1
- continue
-
- return character_approved_count / len(ordered_characters)
-
-
-def alpha_unicode_split(decoded_sequence: str) -> List[str]:
- """
- Given a decoded text sequence, return a list of str. Unicode range / alphabet separation.
- Ex. a text containing English/Latin with a bit a Hebrew will return two items in the resulting list;
- One containing the latin letters and the other hebrew.
- """
- layers: Dict[str, str] = {}
-
- for character in decoded_sequence:
- if character.isalpha() is False:
- continue
-
- character_range: Optional[str] = unicode_range(character)
-
- if character_range is None:
- continue
-
- layer_target_range: Optional[str] = None
-
- for discovered_range in layers:
- if (
- is_suspiciously_successive_range(discovered_range, character_range)
- is False
- ):
- layer_target_range = discovered_range
- break
-
- if layer_target_range is None:
- layer_target_range = character_range
-
- if layer_target_range not in layers:
- layers[layer_target_range] = character.lower()
- continue
-
- layers[layer_target_range] += character.lower()
-
- return list(layers.values())
-
-
-def merge_coherence_ratios(results: List[CoherenceMatches]) -> CoherenceMatches:
- """
- This function merge results previously given by the function coherence_ratio.
- The return type is the same as coherence_ratio.
- """
- per_language_ratios: Dict[str, List[float]] = {}
- for result in results:
- for sub_result in result:
- language, ratio = sub_result
- if language not in per_language_ratios:
- per_language_ratios[language] = [ratio]
- continue
- per_language_ratios[language].append(ratio)
-
- merge = [
- (
- language,
- round(
- sum(per_language_ratios[language]) / len(per_language_ratios[language]),
- 4,
- ),
- )
- for language in per_language_ratios
- ]
-
- return sorted(merge, key=lambda x: x[1], reverse=True)
-
-
-def filter_alt_coherence_matches(results: CoherenceMatches) -> CoherenceMatches:
- """
- We shall NOT return "English—" in CoherenceMatches because it is an alternative
- of "English". This function only keeps the best match and remove the em-dash in it.
- """
- index_results: Dict[str, List[float]] = dict()
-
- for result in results:
- language, ratio = result
- no_em_name: str = language.replace("—", "")
-
- if no_em_name not in index_results:
- index_results[no_em_name] = []
-
- index_results[no_em_name].append(ratio)
-
- if any(len(index_results[e]) > 1 for e in index_results):
- filtered_results: CoherenceMatches = []
-
- for language in index_results:
- filtered_results.append((language, max(index_results[language])))
-
- return filtered_results
-
- return results
-
-
-@lru_cache(maxsize=2048)
-def coherence_ratio(
- decoded_sequence: str, threshold: float = 0.1, lg_inclusion: Optional[str] = None
-) -> CoherenceMatches:
- """
- Detect ANY language that can be identified in given sequence. The sequence will be analysed by layers.
- A layer = Character extraction by alphabets/ranges.
- """
-
- results: List[Tuple[str, float]] = []
- ignore_non_latin: bool = False
-
- sufficient_match_count: int = 0
-
- lg_inclusion_list = lg_inclusion.split(",") if lg_inclusion is not None else []
- if "Latin Based" in lg_inclusion_list:
- ignore_non_latin = True
- lg_inclusion_list.remove("Latin Based")
-
- for layer in alpha_unicode_split(decoded_sequence):
- sequence_frequencies: TypeCounter[str] = Counter(layer)
- most_common = sequence_frequencies.most_common()
-
- character_count: int = sum(o for c, o in most_common)
-
- if character_count <= TOO_SMALL_SEQUENCE:
- continue
-
- popular_character_ordered: List[str] = [c for c, o in most_common]
-
- for language in lg_inclusion_list or alphabet_languages(
- popular_character_ordered, ignore_non_latin
- ):
- ratio: float = characters_popularity_compare(
- language, popular_character_ordered
- )
-
- if ratio < threshold:
- continue
- elif ratio >= 0.8:
- sufficient_match_count += 1
-
- results.append((language, round(ratio, 4)))
-
- if sufficient_match_count >= 3:
- break
-
- return sorted(
- filter_alt_coherence_matches(results), key=lambda x: x[1], reverse=True
- )
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py b/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py
deleted file mode 100644
index d95fedf..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__init__.py
+++ /dev/null
@@ -1,6 +0,0 @@
-from .__main__ import cli_detect, query_yes_no
-
-__all__ = (
- "cli_detect",
- "query_yes_no",
-)
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py b/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py
deleted file mode 100644
index f4bcbaa..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__main__.py
+++ /dev/null
@@ -1,296 +0,0 @@
-import argparse
-import sys
-from json import dumps
-from os.path import abspath, basename, dirname, join, realpath
-from platform import python_version
-from typing import List, Optional
-from unicodedata import unidata_version
-
-import charset_normalizer.md as md_module
-from charset_normalizer import from_fp
-from charset_normalizer.models import CliDetectionResult
-from charset_normalizer.version import __version__
-
-
-def query_yes_no(question: str, default: str = "yes") -> bool:
- """Ask a yes/no question via input() and return their answer.
-
- "question" is a string that is presented to the user.
- "default" is the presumed answer if the user just hits .
- It must be "yes" (the default), "no" or None (meaning
- an answer is required of the user).
-
- The "answer" return value is True for "yes" or False for "no".
-
- Credit goes to (c) https://stackoverflow.com/questions/3041986/apt-command-line-interface-like-yes-no-input
- """
- valid = {"yes": True, "y": True, "ye": True, "no": False, "n": False}
- if default is None:
- prompt = " [y/n] "
- elif default == "yes":
- prompt = " [Y/n] "
- elif default == "no":
- prompt = " [y/N] "
- else:
- raise ValueError("invalid default answer: '%s'" % default)
-
- while True:
- sys.stdout.write(question + prompt)
- choice = input().lower()
- if default is not None and choice == "":
- return valid[default]
- elif choice in valid:
- return valid[choice]
- else:
- sys.stdout.write("Please respond with 'yes' or 'no' " "(or 'y' or 'n').\n")
-
-
-def cli_detect(argv: Optional[List[str]] = None) -> int:
- """
- CLI assistant using ARGV and ArgumentParser
- :param argv:
- :return: 0 if everything is fine, anything else equal trouble
- """
- parser = argparse.ArgumentParser(
- description="The Real First Universal Charset Detector. "
- "Discover originating encoding used on text file. "
- "Normalize text to unicode."
- )
-
- parser.add_argument(
- "files", type=argparse.FileType("rb"), nargs="+", help="File(s) to be analysed"
- )
- parser.add_argument(
- "-v",
- "--verbose",
- action="store_true",
- default=False,
- dest="verbose",
- help="Display complementary information about file if any. "
- "Stdout will contain logs about the detection process.",
- )
- parser.add_argument(
- "-a",
- "--with-alternative",
- action="store_true",
- default=False,
- dest="alternatives",
- help="Output complementary possibilities if any. Top-level JSON WILL be a list.",
- )
- parser.add_argument(
- "-n",
- "--normalize",
- action="store_true",
- default=False,
- dest="normalize",
- help="Permit to normalize input file. If not set, program does not write anything.",
- )
- parser.add_argument(
- "-m",
- "--minimal",
- action="store_true",
- default=False,
- dest="minimal",
- help="Only output the charset detected to STDOUT. Disabling JSON output.",
- )
- parser.add_argument(
- "-r",
- "--replace",
- action="store_true",
- default=False,
- dest="replace",
- help="Replace file when trying to normalize it instead of creating a new one.",
- )
- parser.add_argument(
- "-f",
- "--force",
- action="store_true",
- default=False,
- dest="force",
- help="Replace file without asking if you are sure, use this flag with caution.",
- )
- parser.add_argument(
- "-t",
- "--threshold",
- action="store",
- default=0.2,
- type=float,
- dest="threshold",
- help="Define a custom maximum amount of chaos allowed in decoded content. 0. <= chaos <= 1.",
- )
- parser.add_argument(
- "--version",
- action="version",
- version="Charset-Normalizer {} - Python {} - Unicode {} - SpeedUp {}".format(
- __version__,
- python_version(),
- unidata_version,
- "OFF" if md_module.__file__.lower().endswith(".py") else "ON",
- ),
- help="Show version information and exit.",
- )
-
- args = parser.parse_args(argv)
-
- if args.replace is True and args.normalize is False:
- print("Use --replace in addition of --normalize only.", file=sys.stderr)
- return 1
-
- if args.force is True and args.replace is False:
- print("Use --force in addition of --replace only.", file=sys.stderr)
- return 1
-
- if args.threshold < 0.0 or args.threshold > 1.0:
- print("--threshold VALUE should be between 0. AND 1.", file=sys.stderr)
- return 1
-
- x_ = []
-
- for my_file in args.files:
- matches = from_fp(my_file, threshold=args.threshold, explain=args.verbose)
-
- best_guess = matches.best()
-
- if best_guess is None:
- print(
- 'Unable to identify originating encoding for "{}". {}'.format(
- my_file.name,
- "Maybe try increasing maximum amount of chaos."
- if args.threshold < 1.0
- else "",
- ),
- file=sys.stderr,
- )
- x_.append(
- CliDetectionResult(
- abspath(my_file.name),
- None,
- [],
- [],
- "Unknown",
- [],
- False,
- 1.0,
- 0.0,
- None,
- True,
- )
- )
- else:
- x_.append(
- CliDetectionResult(
- abspath(my_file.name),
- best_guess.encoding,
- best_guess.encoding_aliases,
- [
- cp
- for cp in best_guess.could_be_from_charset
- if cp != best_guess.encoding
- ],
- best_guess.language,
- best_guess.alphabets,
- best_guess.bom,
- best_guess.percent_chaos,
- best_guess.percent_coherence,
- None,
- True,
- )
- )
-
- if len(matches) > 1 and args.alternatives:
- for el in matches:
- if el != best_guess:
- x_.append(
- CliDetectionResult(
- abspath(my_file.name),
- el.encoding,
- el.encoding_aliases,
- [
- cp
- for cp in el.could_be_from_charset
- if cp != el.encoding
- ],
- el.language,
- el.alphabets,
- el.bom,
- el.percent_chaos,
- el.percent_coherence,
- None,
- False,
- )
- )
-
- if args.normalize is True:
- if best_guess.encoding.startswith("utf") is True:
- print(
- '"{}" file does not need to be normalized, as it already came from unicode.'.format(
- my_file.name
- ),
- file=sys.stderr,
- )
- if my_file.closed is False:
- my_file.close()
- continue
-
- dir_path = dirname(realpath(my_file.name))
- file_name = basename(realpath(my_file.name))
-
- o_: List[str] = file_name.split(".")
-
- if args.replace is False:
- o_.insert(-1, best_guess.encoding)
- if my_file.closed is False:
- my_file.close()
- elif (
- args.force is False
- and query_yes_no(
- 'Are you sure to normalize "{}" by replacing it ?'.format(
- my_file.name
- ),
- "no",
- )
- is False
- ):
- if my_file.closed is False:
- my_file.close()
- continue
-
- try:
- x_[0].unicode_path = join(dir_path, ".".join(o_))
-
- with open(x_[0].unicode_path, "w", encoding="utf-8") as fp:
- fp.write(str(best_guess))
- except IOError as e:
- print(str(e), file=sys.stderr)
- if my_file.closed is False:
- my_file.close()
- return 2
-
- if my_file.closed is False:
- my_file.close()
-
- if args.minimal is False:
- print(
- dumps(
- [el.__dict__ for el in x_] if len(x_) > 1 else x_[0].__dict__,
- ensure_ascii=True,
- indent=4,
- )
- )
- else:
- for my_file in args.files:
- print(
- ", ".join(
- [
- el.encoding or "undefined"
- for el in x_
- if el.path == abspath(my_file.name)
- ]
- )
- )
-
- return 0
-
-
-if __name__ == "__main__":
- cli_detect()
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index b391c4c..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc
deleted file mode 100644
index 8a75b40..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/cli/__pycache__/__main__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/constant.py b/.venv/lib/python3.12/site-packages/charset_normalizer/constant.py
deleted file mode 100644
index 8634904..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/constant.py
+++ /dev/null
@@ -1,1995 +0,0 @@
-# -*- coding: utf-8 -*-
-from codecs import BOM_UTF8, BOM_UTF16_BE, BOM_UTF16_LE, BOM_UTF32_BE, BOM_UTF32_LE
-from encodings.aliases import aliases
-from re import IGNORECASE, compile as re_compile
-from typing import Dict, List, Set, Union
-
-# Contain for each eligible encoding a list of/item bytes SIG/BOM
-ENCODING_MARKS: Dict[str, Union[bytes, List[bytes]]] = {
- "utf_8": BOM_UTF8,
- "utf_7": [
- b"\x2b\x2f\x76\x38",
- b"\x2b\x2f\x76\x39",
- b"\x2b\x2f\x76\x2b",
- b"\x2b\x2f\x76\x2f",
- b"\x2b\x2f\x76\x38\x2d",
- ],
- "gb18030": b"\x84\x31\x95\x33",
- "utf_32": [BOM_UTF32_BE, BOM_UTF32_LE],
- "utf_16": [BOM_UTF16_BE, BOM_UTF16_LE],
-}
-
-TOO_SMALL_SEQUENCE: int = 32
-TOO_BIG_SEQUENCE: int = int(10e6)
-
-UTF8_MAXIMAL_ALLOCATION: int = 1_112_064
-
-# Up-to-date Unicode ucd/15.0.0
-UNICODE_RANGES_COMBINED: Dict[str, range] = {
- "Control character": range(32),
- "Basic Latin": range(32, 128),
- "Latin-1 Supplement": range(128, 256),
- "Latin Extended-A": range(256, 384),
- "Latin Extended-B": range(384, 592),
- "IPA Extensions": range(592, 688),
- "Spacing Modifier Letters": range(688, 768),
- "Combining Diacritical Marks": range(768, 880),
- "Greek and Coptic": range(880, 1024),
- "Cyrillic": range(1024, 1280),
- "Cyrillic Supplement": range(1280, 1328),
- "Armenian": range(1328, 1424),
- "Hebrew": range(1424, 1536),
- "Arabic": range(1536, 1792),
- "Syriac": range(1792, 1872),
- "Arabic Supplement": range(1872, 1920),
- "Thaana": range(1920, 1984),
- "NKo": range(1984, 2048),
- "Samaritan": range(2048, 2112),
- "Mandaic": range(2112, 2144),
- "Syriac Supplement": range(2144, 2160),
- "Arabic Extended-B": range(2160, 2208),
- "Arabic Extended-A": range(2208, 2304),
- "Devanagari": range(2304, 2432),
- "Bengali": range(2432, 2560),
- "Gurmukhi": range(2560, 2688),
- "Gujarati": range(2688, 2816),
- "Oriya": range(2816, 2944),
- "Tamil": range(2944, 3072),
- "Telugu": range(3072, 3200),
- "Kannada": range(3200, 3328),
- "Malayalam": range(3328, 3456),
- "Sinhala": range(3456, 3584),
- "Thai": range(3584, 3712),
- "Lao": range(3712, 3840),
- "Tibetan": range(3840, 4096),
- "Myanmar": range(4096, 4256),
- "Georgian": range(4256, 4352),
- "Hangul Jamo": range(4352, 4608),
- "Ethiopic": range(4608, 4992),
- "Ethiopic Supplement": range(4992, 5024),
- "Cherokee": range(5024, 5120),
- "Unified Canadian Aboriginal Syllabics": range(5120, 5760),
- "Ogham": range(5760, 5792),
- "Runic": range(5792, 5888),
- "Tagalog": range(5888, 5920),
- "Hanunoo": range(5920, 5952),
- "Buhid": range(5952, 5984),
- "Tagbanwa": range(5984, 6016),
- "Khmer": range(6016, 6144),
- "Mongolian": range(6144, 6320),
- "Unified Canadian Aboriginal Syllabics Extended": range(6320, 6400),
- "Limbu": range(6400, 6480),
- "Tai Le": range(6480, 6528),
- "New Tai Lue": range(6528, 6624),
- "Khmer Symbols": range(6624, 6656),
- "Buginese": range(6656, 6688),
- "Tai Tham": range(6688, 6832),
- "Combining Diacritical Marks Extended": range(6832, 6912),
- "Balinese": range(6912, 7040),
- "Sundanese": range(7040, 7104),
- "Batak": range(7104, 7168),
- "Lepcha": range(7168, 7248),
- "Ol Chiki": range(7248, 7296),
- "Cyrillic Extended-C": range(7296, 7312),
- "Georgian Extended": range(7312, 7360),
- "Sundanese Supplement": range(7360, 7376),
- "Vedic Extensions": range(7376, 7424),
- "Phonetic Extensions": range(7424, 7552),
- "Phonetic Extensions Supplement": range(7552, 7616),
- "Combining Diacritical Marks Supplement": range(7616, 7680),
- "Latin Extended Additional": range(7680, 7936),
- "Greek Extended": range(7936, 8192),
- "General Punctuation": range(8192, 8304),
- "Superscripts and Subscripts": range(8304, 8352),
- "Currency Symbols": range(8352, 8400),
- "Combining Diacritical Marks for Symbols": range(8400, 8448),
- "Letterlike Symbols": range(8448, 8528),
- "Number Forms": range(8528, 8592),
- "Arrows": range(8592, 8704),
- "Mathematical Operators": range(8704, 8960),
- "Miscellaneous Technical": range(8960, 9216),
- "Control Pictures": range(9216, 9280),
- "Optical Character Recognition": range(9280, 9312),
- "Enclosed Alphanumerics": range(9312, 9472),
- "Box Drawing": range(9472, 9600),
- "Block Elements": range(9600, 9632),
- "Geometric Shapes": range(9632, 9728),
- "Miscellaneous Symbols": range(9728, 9984),
- "Dingbats": range(9984, 10176),
- "Miscellaneous Mathematical Symbols-A": range(10176, 10224),
- "Supplemental Arrows-A": range(10224, 10240),
- "Braille Patterns": range(10240, 10496),
- "Supplemental Arrows-B": range(10496, 10624),
- "Miscellaneous Mathematical Symbols-B": range(10624, 10752),
- "Supplemental Mathematical Operators": range(10752, 11008),
- "Miscellaneous Symbols and Arrows": range(11008, 11264),
- "Glagolitic": range(11264, 11360),
- "Latin Extended-C": range(11360, 11392),
- "Coptic": range(11392, 11520),
- "Georgian Supplement": range(11520, 11568),
- "Tifinagh": range(11568, 11648),
- "Ethiopic Extended": range(11648, 11744),
- "Cyrillic Extended-A": range(11744, 11776),
- "Supplemental Punctuation": range(11776, 11904),
- "CJK Radicals Supplement": range(11904, 12032),
- "Kangxi Radicals": range(12032, 12256),
- "Ideographic Description Characters": range(12272, 12288),
- "CJK Symbols and Punctuation": range(12288, 12352),
- "Hiragana": range(12352, 12448),
- "Katakana": range(12448, 12544),
- "Bopomofo": range(12544, 12592),
- "Hangul Compatibility Jamo": range(12592, 12688),
- "Kanbun": range(12688, 12704),
- "Bopomofo Extended": range(12704, 12736),
- "CJK Strokes": range(12736, 12784),
- "Katakana Phonetic Extensions": range(12784, 12800),
- "Enclosed CJK Letters and Months": range(12800, 13056),
- "CJK Compatibility": range(13056, 13312),
- "CJK Unified Ideographs Extension A": range(13312, 19904),
- "Yijing Hexagram Symbols": range(19904, 19968),
- "CJK Unified Ideographs": range(19968, 40960),
- "Yi Syllables": range(40960, 42128),
- "Yi Radicals": range(42128, 42192),
- "Lisu": range(42192, 42240),
- "Vai": range(42240, 42560),
- "Cyrillic Extended-B": range(42560, 42656),
- "Bamum": range(42656, 42752),
- "Modifier Tone Letters": range(42752, 42784),
- "Latin Extended-D": range(42784, 43008),
- "Syloti Nagri": range(43008, 43056),
- "Common Indic Number Forms": range(43056, 43072),
- "Phags-pa": range(43072, 43136),
- "Saurashtra": range(43136, 43232),
- "Devanagari Extended": range(43232, 43264),
- "Kayah Li": range(43264, 43312),
- "Rejang": range(43312, 43360),
- "Hangul Jamo Extended-A": range(43360, 43392),
- "Javanese": range(43392, 43488),
- "Myanmar Extended-B": range(43488, 43520),
- "Cham": range(43520, 43616),
- "Myanmar Extended-A": range(43616, 43648),
- "Tai Viet": range(43648, 43744),
- "Meetei Mayek Extensions": range(43744, 43776),
- "Ethiopic Extended-A": range(43776, 43824),
- "Latin Extended-E": range(43824, 43888),
- "Cherokee Supplement": range(43888, 43968),
- "Meetei Mayek": range(43968, 44032),
- "Hangul Syllables": range(44032, 55216),
- "Hangul Jamo Extended-B": range(55216, 55296),
- "High Surrogates": range(55296, 56192),
- "High Private Use Surrogates": range(56192, 56320),
- "Low Surrogates": range(56320, 57344),
- "Private Use Area": range(57344, 63744),
- "CJK Compatibility Ideographs": range(63744, 64256),
- "Alphabetic Presentation Forms": range(64256, 64336),
- "Arabic Presentation Forms-A": range(64336, 65024),
- "Variation Selectors": range(65024, 65040),
- "Vertical Forms": range(65040, 65056),
- "Combining Half Marks": range(65056, 65072),
- "CJK Compatibility Forms": range(65072, 65104),
- "Small Form Variants": range(65104, 65136),
- "Arabic Presentation Forms-B": range(65136, 65280),
- "Halfwidth and Fullwidth Forms": range(65280, 65520),
- "Specials": range(65520, 65536),
- "Linear B Syllabary": range(65536, 65664),
- "Linear B Ideograms": range(65664, 65792),
- "Aegean Numbers": range(65792, 65856),
- "Ancient Greek Numbers": range(65856, 65936),
- "Ancient Symbols": range(65936, 66000),
- "Phaistos Disc": range(66000, 66048),
- "Lycian": range(66176, 66208),
- "Carian": range(66208, 66272),
- "Coptic Epact Numbers": range(66272, 66304),
- "Old Italic": range(66304, 66352),
- "Gothic": range(66352, 66384),
- "Old Permic": range(66384, 66432),
- "Ugaritic": range(66432, 66464),
- "Old Persian": range(66464, 66528),
- "Deseret": range(66560, 66640),
- "Shavian": range(66640, 66688),
- "Osmanya": range(66688, 66736),
- "Osage": range(66736, 66816),
- "Elbasan": range(66816, 66864),
- "Caucasian Albanian": range(66864, 66928),
- "Vithkuqi": range(66928, 67008),
- "Linear A": range(67072, 67456),
- "Latin Extended-F": range(67456, 67520),
- "Cypriot Syllabary": range(67584, 67648),
- "Imperial Aramaic": range(67648, 67680),
- "Palmyrene": range(67680, 67712),
- "Nabataean": range(67712, 67760),
- "Hatran": range(67808, 67840),
- "Phoenician": range(67840, 67872),
- "Lydian": range(67872, 67904),
- "Meroitic Hieroglyphs": range(67968, 68000),
- "Meroitic Cursive": range(68000, 68096),
- "Kharoshthi": range(68096, 68192),
- "Old South Arabian": range(68192, 68224),
- "Old North Arabian": range(68224, 68256),
- "Manichaean": range(68288, 68352),
- "Avestan": range(68352, 68416),
- "Inscriptional Parthian": range(68416, 68448),
- "Inscriptional Pahlavi": range(68448, 68480),
- "Psalter Pahlavi": range(68480, 68528),
- "Old Turkic": range(68608, 68688),
- "Old Hungarian": range(68736, 68864),
- "Hanifi Rohingya": range(68864, 68928),
- "Rumi Numeral Symbols": range(69216, 69248),
- "Yezidi": range(69248, 69312),
- "Arabic Extended-C": range(69312, 69376),
- "Old Sogdian": range(69376, 69424),
- "Sogdian": range(69424, 69488),
- "Old Uyghur": range(69488, 69552),
- "Chorasmian": range(69552, 69600),
- "Elymaic": range(69600, 69632),
- "Brahmi": range(69632, 69760),
- "Kaithi": range(69760, 69840),
- "Sora Sompeng": range(69840, 69888),
- "Chakma": range(69888, 69968),
- "Mahajani": range(69968, 70016),
- "Sharada": range(70016, 70112),
- "Sinhala Archaic Numbers": range(70112, 70144),
- "Khojki": range(70144, 70224),
- "Multani": range(70272, 70320),
- "Khudawadi": range(70320, 70400),
- "Grantha": range(70400, 70528),
- "Newa": range(70656, 70784),
- "Tirhuta": range(70784, 70880),
- "Siddham": range(71040, 71168),
- "Modi": range(71168, 71264),
- "Mongolian Supplement": range(71264, 71296),
- "Takri": range(71296, 71376),
- "Ahom": range(71424, 71504),
- "Dogra": range(71680, 71760),
- "Warang Citi": range(71840, 71936),
- "Dives Akuru": range(71936, 72032),
- "Nandinagari": range(72096, 72192),
- "Zanabazar Square": range(72192, 72272),
- "Soyombo": range(72272, 72368),
- "Unified Canadian Aboriginal Syllabics Extended-A": range(72368, 72384),
- "Pau Cin Hau": range(72384, 72448),
- "Devanagari Extended-A": range(72448, 72544),
- "Bhaiksuki": range(72704, 72816),
- "Marchen": range(72816, 72896),
- "Masaram Gondi": range(72960, 73056),
- "Gunjala Gondi": range(73056, 73136),
- "Makasar": range(73440, 73472),
- "Kawi": range(73472, 73568),
- "Lisu Supplement": range(73648, 73664),
- "Tamil Supplement": range(73664, 73728),
- "Cuneiform": range(73728, 74752),
- "Cuneiform Numbers and Punctuation": range(74752, 74880),
- "Early Dynastic Cuneiform": range(74880, 75088),
- "Cypro-Minoan": range(77712, 77824),
- "Egyptian Hieroglyphs": range(77824, 78896),
- "Egyptian Hieroglyph Format Controls": range(78896, 78944),
- "Anatolian Hieroglyphs": range(82944, 83584),
- "Bamum Supplement": range(92160, 92736),
- "Mro": range(92736, 92784),
- "Tangsa": range(92784, 92880),
- "Bassa Vah": range(92880, 92928),
- "Pahawh Hmong": range(92928, 93072),
- "Medefaidrin": range(93760, 93856),
- "Miao": range(93952, 94112),
- "Ideographic Symbols and Punctuation": range(94176, 94208),
- "Tangut": range(94208, 100352),
- "Tangut Components": range(100352, 101120),
- "Khitan Small Script": range(101120, 101632),
- "Tangut Supplement": range(101632, 101760),
- "Kana Extended-B": range(110576, 110592),
- "Kana Supplement": range(110592, 110848),
- "Kana Extended-A": range(110848, 110896),
- "Small Kana Extension": range(110896, 110960),
- "Nushu": range(110960, 111360),
- "Duployan": range(113664, 113824),
- "Shorthand Format Controls": range(113824, 113840),
- "Znamenny Musical Notation": range(118528, 118736),
- "Byzantine Musical Symbols": range(118784, 119040),
- "Musical Symbols": range(119040, 119296),
- "Ancient Greek Musical Notation": range(119296, 119376),
- "Kaktovik Numerals": range(119488, 119520),
- "Mayan Numerals": range(119520, 119552),
- "Tai Xuan Jing Symbols": range(119552, 119648),
- "Counting Rod Numerals": range(119648, 119680),
- "Mathematical Alphanumeric Symbols": range(119808, 120832),
- "Sutton SignWriting": range(120832, 121520),
- "Latin Extended-G": range(122624, 122880),
- "Glagolitic Supplement": range(122880, 122928),
- "Cyrillic Extended-D": range(122928, 123024),
- "Nyiakeng Puachue Hmong": range(123136, 123216),
- "Toto": range(123536, 123584),
- "Wancho": range(123584, 123648),
- "Nag Mundari": range(124112, 124160),
- "Ethiopic Extended-B": range(124896, 124928),
- "Mende Kikakui": range(124928, 125152),
- "Adlam": range(125184, 125280),
- "Indic Siyaq Numbers": range(126064, 126144),
- "Ottoman Siyaq Numbers": range(126208, 126288),
- "Arabic Mathematical Alphabetic Symbols": range(126464, 126720),
- "Mahjong Tiles": range(126976, 127024),
- "Domino Tiles": range(127024, 127136),
- "Playing Cards": range(127136, 127232),
- "Enclosed Alphanumeric Supplement": range(127232, 127488),
- "Enclosed Ideographic Supplement": range(127488, 127744),
- "Miscellaneous Symbols and Pictographs": range(127744, 128512),
- "Emoticons range(Emoji)": range(128512, 128592),
- "Ornamental Dingbats": range(128592, 128640),
- "Transport and Map Symbols": range(128640, 128768),
- "Alchemical Symbols": range(128768, 128896),
- "Geometric Shapes Extended": range(128896, 129024),
- "Supplemental Arrows-C": range(129024, 129280),
- "Supplemental Symbols and Pictographs": range(129280, 129536),
- "Chess Symbols": range(129536, 129648),
- "Symbols and Pictographs Extended-A": range(129648, 129792),
- "Symbols for Legacy Computing": range(129792, 130048),
- "CJK Unified Ideographs Extension B": range(131072, 173792),
- "CJK Unified Ideographs Extension C": range(173824, 177984),
- "CJK Unified Ideographs Extension D": range(177984, 178208),
- "CJK Unified Ideographs Extension E": range(178208, 183984),
- "CJK Unified Ideographs Extension F": range(183984, 191472),
- "CJK Compatibility Ideographs Supplement": range(194560, 195104),
- "CJK Unified Ideographs Extension G": range(196608, 201552),
- "CJK Unified Ideographs Extension H": range(201552, 205744),
- "Tags": range(917504, 917632),
- "Variation Selectors Supplement": range(917760, 918000),
- "Supplementary Private Use Area-A": range(983040, 1048576),
- "Supplementary Private Use Area-B": range(1048576, 1114112),
-}
-
-
-UNICODE_SECONDARY_RANGE_KEYWORD: List[str] = [
- "Supplement",
- "Extended",
- "Extensions",
- "Modifier",
- "Marks",
- "Punctuation",
- "Symbols",
- "Forms",
- "Operators",
- "Miscellaneous",
- "Drawing",
- "Block",
- "Shapes",
- "Supplemental",
- "Tags",
-]
-
-RE_POSSIBLE_ENCODING_INDICATION = re_compile(
- r"(?:(?:encoding)|(?:charset)|(?:coding))(?:[\:= ]{1,10})(?:[\"\']?)([a-zA-Z0-9\-_]+)(?:[\"\']?)",
- IGNORECASE,
-)
-
-IANA_NO_ALIASES = [
- "cp720",
- "cp737",
- "cp856",
- "cp874",
- "cp875",
- "cp1006",
- "koi8_r",
- "koi8_t",
- "koi8_u",
-]
-
-IANA_SUPPORTED: List[str] = sorted(
- filter(
- lambda x: x.endswith("_codec") is False
- and x not in {"rot_13", "tactis", "mbcs"},
- list(set(aliases.values())) + IANA_NO_ALIASES,
- )
-)
-
-IANA_SUPPORTED_COUNT: int = len(IANA_SUPPORTED)
-
-# pre-computed code page that are similar using the function cp_similarity.
-IANA_SUPPORTED_SIMILAR: Dict[str, List[str]] = {
- "cp037": ["cp1026", "cp1140", "cp273", "cp500"],
- "cp1026": ["cp037", "cp1140", "cp273", "cp500"],
- "cp1125": ["cp866"],
- "cp1140": ["cp037", "cp1026", "cp273", "cp500"],
- "cp1250": ["iso8859_2"],
- "cp1251": ["kz1048", "ptcp154"],
- "cp1252": ["iso8859_15", "iso8859_9", "latin_1"],
- "cp1253": ["iso8859_7"],
- "cp1254": ["iso8859_15", "iso8859_9", "latin_1"],
- "cp1257": ["iso8859_13"],
- "cp273": ["cp037", "cp1026", "cp1140", "cp500"],
- "cp437": ["cp850", "cp858", "cp860", "cp861", "cp862", "cp863", "cp865"],
- "cp500": ["cp037", "cp1026", "cp1140", "cp273"],
- "cp850": ["cp437", "cp857", "cp858", "cp865"],
- "cp857": ["cp850", "cp858", "cp865"],
- "cp858": ["cp437", "cp850", "cp857", "cp865"],
- "cp860": ["cp437", "cp861", "cp862", "cp863", "cp865"],
- "cp861": ["cp437", "cp860", "cp862", "cp863", "cp865"],
- "cp862": ["cp437", "cp860", "cp861", "cp863", "cp865"],
- "cp863": ["cp437", "cp860", "cp861", "cp862", "cp865"],
- "cp865": ["cp437", "cp850", "cp857", "cp858", "cp860", "cp861", "cp862", "cp863"],
- "cp866": ["cp1125"],
- "iso8859_10": ["iso8859_14", "iso8859_15", "iso8859_4", "iso8859_9", "latin_1"],
- "iso8859_11": ["tis_620"],
- "iso8859_13": ["cp1257"],
- "iso8859_14": [
- "iso8859_10",
- "iso8859_15",
- "iso8859_16",
- "iso8859_3",
- "iso8859_9",
- "latin_1",
- ],
- "iso8859_15": [
- "cp1252",
- "cp1254",
- "iso8859_10",
- "iso8859_14",
- "iso8859_16",
- "iso8859_3",
- "iso8859_9",
- "latin_1",
- ],
- "iso8859_16": [
- "iso8859_14",
- "iso8859_15",
- "iso8859_2",
- "iso8859_3",
- "iso8859_9",
- "latin_1",
- ],
- "iso8859_2": ["cp1250", "iso8859_16", "iso8859_4"],
- "iso8859_3": ["iso8859_14", "iso8859_15", "iso8859_16", "iso8859_9", "latin_1"],
- "iso8859_4": ["iso8859_10", "iso8859_2", "iso8859_9", "latin_1"],
- "iso8859_7": ["cp1253"],
- "iso8859_9": [
- "cp1252",
- "cp1254",
- "cp1258",
- "iso8859_10",
- "iso8859_14",
- "iso8859_15",
- "iso8859_16",
- "iso8859_3",
- "iso8859_4",
- "latin_1",
- ],
- "kz1048": ["cp1251", "ptcp154"],
- "latin_1": [
- "cp1252",
- "cp1254",
- "cp1258",
- "iso8859_10",
- "iso8859_14",
- "iso8859_15",
- "iso8859_16",
- "iso8859_3",
- "iso8859_4",
- "iso8859_9",
- ],
- "mac_iceland": ["mac_roman", "mac_turkish"],
- "mac_roman": ["mac_iceland", "mac_turkish"],
- "mac_turkish": ["mac_iceland", "mac_roman"],
- "ptcp154": ["cp1251", "kz1048"],
- "tis_620": ["iso8859_11"],
-}
-
-
-CHARDET_CORRESPONDENCE: Dict[str, str] = {
- "iso2022_kr": "ISO-2022-KR",
- "iso2022_jp": "ISO-2022-JP",
- "euc_kr": "EUC-KR",
- "tis_620": "TIS-620",
- "utf_32": "UTF-32",
- "euc_jp": "EUC-JP",
- "koi8_r": "KOI8-R",
- "iso8859_1": "ISO-8859-1",
- "iso8859_2": "ISO-8859-2",
- "iso8859_5": "ISO-8859-5",
- "iso8859_6": "ISO-8859-6",
- "iso8859_7": "ISO-8859-7",
- "iso8859_8": "ISO-8859-8",
- "utf_16": "UTF-16",
- "cp855": "IBM855",
- "mac_cyrillic": "MacCyrillic",
- "gb2312": "GB2312",
- "gb18030": "GB18030",
- "cp932": "CP932",
- "cp866": "IBM866",
- "utf_8": "utf-8",
- "utf_8_sig": "UTF-8-SIG",
- "shift_jis": "SHIFT_JIS",
- "big5": "Big5",
- "cp1250": "windows-1250",
- "cp1251": "windows-1251",
- "cp1252": "Windows-1252",
- "cp1253": "windows-1253",
- "cp1255": "windows-1255",
- "cp1256": "windows-1256",
- "cp1254": "Windows-1254",
- "cp949": "CP949",
-}
-
-
-COMMON_SAFE_ASCII_CHARACTERS: Set[str] = {
- "<",
- ">",
- "=",
- ":",
- "/",
- "&",
- ";",
- "{",
- "}",
- "[",
- "]",
- ",",
- "|",
- '"',
- "-",
-}
-
-
-KO_NAMES: Set[str] = {"johab", "cp949", "euc_kr"}
-ZH_NAMES: Set[str] = {"big5", "cp950", "big5hkscs", "hz"}
-
-# Logging LEVEL below DEBUG
-TRACE: int = 5
-
-
-# Language label that contain the em dash "—"
-# character are to be considered alternative seq to origin
-FREQUENCIES: Dict[str, List[str]] = {
- "English": [
- "e",
- "a",
- "t",
- "i",
- "o",
- "n",
- "s",
- "r",
- "h",
- "l",
- "d",
- "c",
- "u",
- "m",
- "f",
- "p",
- "g",
- "w",
- "y",
- "b",
- "v",
- "k",
- "x",
- "j",
- "z",
- "q",
- ],
- "English—": [
- "e",
- "a",
- "t",
- "i",
- "o",
- "n",
- "s",
- "r",
- "h",
- "l",
- "d",
- "c",
- "m",
- "u",
- "f",
- "p",
- "g",
- "w",
- "b",
- "y",
- "v",
- "k",
- "j",
- "x",
- "z",
- "q",
- ],
- "German": [
- "e",
- "n",
- "i",
- "r",
- "s",
- "t",
- "a",
- "d",
- "h",
- "u",
- "l",
- "g",
- "o",
- "c",
- "m",
- "b",
- "f",
- "k",
- "w",
- "z",
- "p",
- "v",
- "ü",
- "ä",
- "ö",
- "j",
- ],
- "French": [
- "e",
- "a",
- "s",
- "n",
- "i",
- "t",
- "r",
- "l",
- "u",
- "o",
- "d",
- "c",
- "p",
- "m",
- "é",
- "v",
- "g",
- "f",
- "b",
- "h",
- "q",
- "à",
- "x",
- "è",
- "y",
- "j",
- ],
- "Dutch": [
- "e",
- "n",
- "a",
- "i",
- "r",
- "t",
- "o",
- "d",
- "s",
- "l",
- "g",
- "h",
- "v",
- "m",
- "u",
- "k",
- "c",
- "p",
- "b",
- "w",
- "j",
- "z",
- "f",
- "y",
- "x",
- "ë",
- ],
- "Italian": [
- "e",
- "i",
- "a",
- "o",
- "n",
- "l",
- "t",
- "r",
- "s",
- "c",
- "d",
- "u",
- "p",
- "m",
- "g",
- "v",
- "f",
- "b",
- "z",
- "h",
- "q",
- "è",
- "à",
- "k",
- "y",
- "ò",
- ],
- "Polish": [
- "a",
- "i",
- "o",
- "e",
- "n",
- "r",
- "z",
- "w",
- "s",
- "c",
- "t",
- "k",
- "y",
- "d",
- "p",
- "m",
- "u",
- "l",
- "j",
- "ł",
- "g",
- "b",
- "h",
- "ą",
- "ę",
- "ó",
- ],
- "Spanish": [
- "e",
- "a",
- "o",
- "n",
- "s",
- "r",
- "i",
- "l",
- "d",
- "t",
- "c",
- "u",
- "m",
- "p",
- "b",
- "g",
- "v",
- "f",
- "y",
- "ó",
- "h",
- "q",
- "í",
- "j",
- "z",
- "á",
- ],
- "Russian": [
- "о",
- "а",
- "е",
- "и",
- "н",
- "с",
- "т",
- "р",
- "в",
- "л",
- "к",
- "м",
- "д",
- "п",
- "у",
- "г",
- "я",
- "ы",
- "з",
- "б",
- "й",
- "ь",
- "ч",
- "х",
- "ж",
- "ц",
- ],
- # Jap-Kanji
- "Japanese": [
- "人",
- "一",
- "大",
- "亅",
- "丁",
- "丨",
- "竹",
- "笑",
- "口",
- "日",
- "今",
- "二",
- "彳",
- "行",
- "十",
- "土",
- "丶",
- "寸",
- "寺",
- "時",
- "乙",
- "丿",
- "乂",
- "气",
- "気",
- "冂",
- "巾",
- "亠",
- "市",
- "目",
- "儿",
- "見",
- "八",
- "小",
- "凵",
- "県",
- "月",
- "彐",
- "門",
- "間",
- "木",
- "東",
- "山",
- "出",
- "本",
- "中",
- "刀",
- "分",
- "耳",
- "又",
- "取",
- "最",
- "言",
- "田",
- "心",
- "思",
- "刂",
- "前",
- "京",
- "尹",
- "事",
- "生",
- "厶",
- "云",
- "会",
- "未",
- "来",
- "白",
- "冫",
- "楽",
- "灬",
- "馬",
- "尸",
- "尺",
- "駅",
- "明",
- "耂",
- "者",
- "了",
- "阝",
- "都",
- "高",
- "卜",
- "占",
- "厂",
- "广",
- "店",
- "子",
- "申",
- "奄",
- "亻",
- "俺",
- "上",
- "方",
- "冖",
- "学",
- "衣",
- "艮",
- "食",
- "自",
- ],
- # Jap-Katakana
- "Japanese—": [
- "ー",
- "ン",
- "ス",
- "・",
- "ル",
- "ト",
- "リ",
- "イ",
- "ア",
- "ラ",
- "ッ",
- "ク",
- "ド",
- "シ",
- "レ",
- "ジ",
- "タ",
- "フ",
- "ロ",
- "カ",
- "テ",
- "マ",
- "ィ",
- "グ",
- "バ",
- "ム",
- "プ",
- "オ",
- "コ",
- "デ",
- "ニ",
- "ウ",
- "メ",
- "サ",
- "ビ",
- "ナ",
- "ブ",
- "ャ",
- "エ",
- "ュ",
- "チ",
- "キ",
- "ズ",
- "ダ",
- "パ",
- "ミ",
- "ェ",
- "ョ",
- "ハ",
- "セ",
- "ベ",
- "ガ",
- "モ",
- "ツ",
- "ネ",
- "ボ",
- "ソ",
- "ノ",
- "ァ",
- "ヴ",
- "ワ",
- "ポ",
- "ペ",
- "ピ",
- "ケ",
- "ゴ",
- "ギ",
- "ザ",
- "ホ",
- "ゲ",
- "ォ",
- "ヤ",
- "ヒ",
- "ユ",
- "ヨ",
- "ヘ",
- "ゼ",
- "ヌ",
- "ゥ",
- "ゾ",
- "ヶ",
- "ヂ",
- "ヲ",
- "ヅ",
- "ヵ",
- "ヱ",
- "ヰ",
- "ヮ",
- "ヽ",
- "゠",
- "ヾ",
- "ヷ",
- "ヿ",
- "ヸ",
- "ヹ",
- "ヺ",
- ],
- # Jap-Hiragana
- "Japanese——": [
- "の",
- "に",
- "る",
- "た",
- "と",
- "は",
- "し",
- "い",
- "を",
- "で",
- "て",
- "が",
- "な",
- "れ",
- "か",
- "ら",
- "さ",
- "っ",
- "り",
- "す",
- "あ",
- "も",
- "こ",
- "ま",
- "う",
- "く",
- "よ",
- "き",
- "ん",
- "め",
- "お",
- "け",
- "そ",
- "つ",
- "だ",
- "や",
- "え",
- "ど",
- "わ",
- "ち",
- "み",
- "せ",
- "じ",
- "ば",
- "へ",
- "び",
- "ず",
- "ろ",
- "ほ",
- "げ",
- "む",
- "べ",
- "ひ",
- "ょ",
- "ゆ",
- "ぶ",
- "ご",
- "ゃ",
- "ね",
- "ふ",
- "ぐ",
- "ぎ",
- "ぼ",
- "ゅ",
- "づ",
- "ざ",
- "ぞ",
- "ぬ",
- "ぜ",
- "ぱ",
- "ぽ",
- "ぷ",
- "ぴ",
- "ぃ",
- "ぁ",
- "ぇ",
- "ぺ",
- "ゞ",
- "ぢ",
- "ぉ",
- "ぅ",
- "ゐ",
- "ゝ",
- "ゑ",
- "゛",
- "゜",
- "ゎ",
- "ゔ",
- "゚",
- "ゟ",
- "゙",
- "ゕ",
- "ゖ",
- ],
- "Portuguese": [
- "a",
- "e",
- "o",
- "s",
- "i",
- "r",
- "d",
- "n",
- "t",
- "m",
- "u",
- "c",
- "l",
- "p",
- "g",
- "v",
- "b",
- "f",
- "h",
- "ã",
- "q",
- "é",
- "ç",
- "á",
- "z",
- "í",
- ],
- "Swedish": [
- "e",
- "a",
- "n",
- "r",
- "t",
- "s",
- "i",
- "l",
- "d",
- "o",
- "m",
- "k",
- "g",
- "v",
- "h",
- "f",
- "u",
- "p",
- "ä",
- "c",
- "b",
- "ö",
- "å",
- "y",
- "j",
- "x",
- ],
- "Chinese": [
- "的",
- "一",
- "是",
- "不",
- "了",
- "在",
- "人",
- "有",
- "我",
- "他",
- "这",
- "个",
- "们",
- "中",
- "来",
- "上",
- "大",
- "为",
- "和",
- "国",
- "地",
- "到",
- "以",
- "说",
- "时",
- "要",
- "就",
- "出",
- "会",
- "可",
- "也",
- "你",
- "对",
- "生",
- "能",
- "而",
- "子",
- "那",
- "得",
- "于",
- "着",
- "下",
- "自",
- "之",
- "年",
- "过",
- "发",
- "后",
- "作",
- "里",
- "用",
- "道",
- "行",
- "所",
- "然",
- "家",
- "种",
- "事",
- "成",
- "方",
- "多",
- "经",
- "么",
- "去",
- "法",
- "学",
- "如",
- "都",
- "同",
- "现",
- "当",
- "没",
- "动",
- "面",
- "起",
- "看",
- "定",
- "天",
- "分",
- "还",
- "进",
- "好",
- "小",
- "部",
- "其",
- "些",
- "主",
- "样",
- "理",
- "心",
- "她",
- "本",
- "前",
- "开",
- "但",
- "因",
- "只",
- "从",
- "想",
- "实",
- ],
- "Ukrainian": [
- "о",
- "а",
- "н",
- "і",
- "и",
- "р",
- "в",
- "т",
- "е",
- "с",
- "к",
- "л",
- "у",
- "д",
- "м",
- "п",
- "з",
- "я",
- "ь",
- "б",
- "г",
- "й",
- "ч",
- "х",
- "ц",
- "ї",
- ],
- "Norwegian": [
- "e",
- "r",
- "n",
- "t",
- "a",
- "s",
- "i",
- "o",
- "l",
- "d",
- "g",
- "k",
- "m",
- "v",
- "f",
- "p",
- "u",
- "b",
- "h",
- "å",
- "y",
- "j",
- "ø",
- "c",
- "æ",
- "w",
- ],
- "Finnish": [
- "a",
- "i",
- "n",
- "t",
- "e",
- "s",
- "l",
- "o",
- "u",
- "k",
- "ä",
- "m",
- "r",
- "v",
- "j",
- "h",
- "p",
- "y",
- "d",
- "ö",
- "g",
- "c",
- "b",
- "f",
- "w",
- "z",
- ],
- "Vietnamese": [
- "n",
- "h",
- "t",
- "i",
- "c",
- "g",
- "a",
- "o",
- "u",
- "m",
- "l",
- "r",
- "à",
- "đ",
- "s",
- "e",
- "v",
- "p",
- "b",
- "y",
- "ư",
- "d",
- "á",
- "k",
- "ộ",
- "ế",
- ],
- "Czech": [
- "o",
- "e",
- "a",
- "n",
- "t",
- "s",
- "i",
- "l",
- "v",
- "r",
- "k",
- "d",
- "u",
- "m",
- "p",
- "í",
- "c",
- "h",
- "z",
- "á",
- "y",
- "j",
- "b",
- "ě",
- "é",
- "ř",
- ],
- "Hungarian": [
- "e",
- "a",
- "t",
- "l",
- "s",
- "n",
- "k",
- "r",
- "i",
- "o",
- "z",
- "á",
- "é",
- "g",
- "m",
- "b",
- "y",
- "v",
- "d",
- "h",
- "u",
- "p",
- "j",
- "ö",
- "f",
- "c",
- ],
- "Korean": [
- "이",
- "다",
- "에",
- "의",
- "는",
- "로",
- "하",
- "을",
- "가",
- "고",
- "지",
- "서",
- "한",
- "은",
- "기",
- "으",
- "년",
- "대",
- "사",
- "시",
- "를",
- "리",
- "도",
- "인",
- "스",
- "일",
- ],
- "Indonesian": [
- "a",
- "n",
- "e",
- "i",
- "r",
- "t",
- "u",
- "s",
- "d",
- "k",
- "m",
- "l",
- "g",
- "p",
- "b",
- "o",
- "h",
- "y",
- "j",
- "c",
- "w",
- "f",
- "v",
- "z",
- "x",
- "q",
- ],
- "Turkish": [
- "a",
- "e",
- "i",
- "n",
- "r",
- "l",
- "ı",
- "k",
- "d",
- "t",
- "s",
- "m",
- "y",
- "u",
- "o",
- "b",
- "ü",
- "ş",
- "v",
- "g",
- "z",
- "h",
- "c",
- "p",
- "ç",
- "ğ",
- ],
- "Romanian": [
- "e",
- "i",
- "a",
- "r",
- "n",
- "t",
- "u",
- "l",
- "o",
- "c",
- "s",
- "d",
- "p",
- "m",
- "ă",
- "f",
- "v",
- "î",
- "g",
- "b",
- "ș",
- "ț",
- "z",
- "h",
- "â",
- "j",
- ],
- "Farsi": [
- "ا",
- "ی",
- "ر",
- "د",
- "ن",
- "ه",
- "و",
- "م",
- "ت",
- "ب",
- "س",
- "ل",
- "ک",
- "ش",
- "ز",
- "ف",
- "گ",
- "ع",
- "خ",
- "ق",
- "ج",
- "آ",
- "پ",
- "ح",
- "ط",
- "ص",
- ],
- "Arabic": [
- "ا",
- "ل",
- "ي",
- "م",
- "و",
- "ن",
- "ر",
- "ت",
- "ب",
- "ة",
- "ع",
- "د",
- "س",
- "ف",
- "ه",
- "ك",
- "ق",
- "أ",
- "ح",
- "ج",
- "ش",
- "ط",
- "ص",
- "ى",
- "خ",
- "إ",
- ],
- "Danish": [
- "e",
- "r",
- "n",
- "t",
- "a",
- "i",
- "s",
- "d",
- "l",
- "o",
- "g",
- "m",
- "k",
- "f",
- "v",
- "u",
- "b",
- "h",
- "p",
- "å",
- "y",
- "ø",
- "æ",
- "c",
- "j",
- "w",
- ],
- "Serbian": [
- "а",
- "и",
- "о",
- "е",
- "н",
- "р",
- "с",
- "у",
- "т",
- "к",
- "ј",
- "в",
- "д",
- "м",
- "п",
- "л",
- "г",
- "з",
- "б",
- "a",
- "i",
- "e",
- "o",
- "n",
- "ц",
- "ш",
- ],
- "Lithuanian": [
- "i",
- "a",
- "s",
- "o",
- "r",
- "e",
- "t",
- "n",
- "u",
- "k",
- "m",
- "l",
- "p",
- "v",
- "d",
- "j",
- "g",
- "ė",
- "b",
- "y",
- "ų",
- "š",
- "ž",
- "c",
- "ą",
- "į",
- ],
- "Slovene": [
- "e",
- "a",
- "i",
- "o",
- "n",
- "r",
- "s",
- "l",
- "t",
- "j",
- "v",
- "k",
- "d",
- "p",
- "m",
- "u",
- "z",
- "b",
- "g",
- "h",
- "č",
- "c",
- "š",
- "ž",
- "f",
- "y",
- ],
- "Slovak": [
- "o",
- "a",
- "e",
- "n",
- "i",
- "r",
- "v",
- "t",
- "s",
- "l",
- "k",
- "d",
- "m",
- "p",
- "u",
- "c",
- "h",
- "j",
- "b",
- "z",
- "á",
- "y",
- "ý",
- "í",
- "č",
- "é",
- ],
- "Hebrew": [
- "י",
- "ו",
- "ה",
- "ל",
- "ר",
- "ב",
- "ת",
- "מ",
- "א",
- "ש",
- "נ",
- "ע",
- "ם",
- "ד",
- "ק",
- "ח",
- "פ",
- "ס",
- "כ",
- "ג",
- "ט",
- "צ",
- "ן",
- "ז",
- "ך",
- ],
- "Bulgarian": [
- "а",
- "и",
- "о",
- "е",
- "н",
- "т",
- "р",
- "с",
- "в",
- "л",
- "к",
- "д",
- "п",
- "м",
- "з",
- "г",
- "я",
- "ъ",
- "у",
- "б",
- "ч",
- "ц",
- "й",
- "ж",
- "щ",
- "х",
- ],
- "Croatian": [
- "a",
- "i",
- "o",
- "e",
- "n",
- "r",
- "j",
- "s",
- "t",
- "u",
- "k",
- "l",
- "v",
- "d",
- "m",
- "p",
- "g",
- "z",
- "b",
- "c",
- "č",
- "h",
- "š",
- "ž",
- "ć",
- "f",
- ],
- "Hindi": [
- "क",
- "र",
- "स",
- "न",
- "त",
- "म",
- "ह",
- "प",
- "य",
- "ल",
- "व",
- "ज",
- "द",
- "ग",
- "ब",
- "श",
- "ट",
- "अ",
- "ए",
- "थ",
- "भ",
- "ड",
- "च",
- "ध",
- "ष",
- "इ",
- ],
- "Estonian": [
- "a",
- "i",
- "e",
- "s",
- "t",
- "l",
- "u",
- "n",
- "o",
- "k",
- "r",
- "d",
- "m",
- "v",
- "g",
- "p",
- "j",
- "h",
- "ä",
- "b",
- "õ",
- "ü",
- "f",
- "c",
- "ö",
- "y",
- ],
- "Thai": [
- "า",
- "น",
- "ร",
- "อ",
- "ก",
- "เ",
- "ง",
- "ม",
- "ย",
- "ล",
- "ว",
- "ด",
- "ท",
- "ส",
- "ต",
- "ะ",
- "ป",
- "บ",
- "ค",
- "ห",
- "แ",
- "จ",
- "พ",
- "ช",
- "ข",
- "ใ",
- ],
- "Greek": [
- "α",
- "τ",
- "ο",
- "ι",
- "ε",
- "ν",
- "ρ",
- "σ",
- "κ",
- "η",
- "π",
- "ς",
- "υ",
- "μ",
- "λ",
- "ί",
- "ό",
- "ά",
- "γ",
- "έ",
- "δ",
- "ή",
- "ω",
- "χ",
- "θ",
- "ύ",
- ],
- "Tamil": [
- "க",
- "த",
- "ப",
- "ட",
- "ர",
- "ம",
- "ல",
- "ன",
- "வ",
- "ற",
- "ய",
- "ள",
- "ச",
- "ந",
- "இ",
- "ண",
- "அ",
- "ஆ",
- "ழ",
- "ங",
- "எ",
- "உ",
- "ஒ",
- "ஸ",
- ],
- "Kazakh": [
- "а",
- "ы",
- "е",
- "н",
- "т",
- "р",
- "л",
- "і",
- "д",
- "с",
- "м",
- "қ",
- "к",
- "о",
- "б",
- "и",
- "у",
- "ғ",
- "ж",
- "ң",
- "з",
- "ш",
- "й",
- "п",
- "г",
- "ө",
- ],
-}
-
-LANGUAGE_SUPPORTED_COUNT: int = len(FREQUENCIES)
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/legacy.py b/.venv/lib/python3.12/site-packages/charset_normalizer/legacy.py
deleted file mode 100644
index 43aad21..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/legacy.py
+++ /dev/null
@@ -1,54 +0,0 @@
-from typing import Any, Dict, Optional, Union
-from warnings import warn
-
-from .api import from_bytes
-from .constant import CHARDET_CORRESPONDENCE
-
-
-def detect(
- byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any
-) -> Dict[str, Optional[Union[str, float]]]:
- """
- chardet legacy method
- Detect the encoding of the given byte string. It should be mostly backward-compatible.
- Encoding name will match Chardet own writing whenever possible. (Not on encoding name unsupported by it)
- This function is deprecated and should be used to migrate your project easily, consult the documentation for
- further information. Not planned for removal.
-
- :param byte_str: The byte sequence to examine.
- :param should_rename_legacy: Should we rename legacy encodings
- to their more modern equivalents?
- """
- if len(kwargs):
- warn(
- f"charset-normalizer disregard arguments '{','.join(list(kwargs.keys()))}' in legacy function detect()"
- )
-
- if not isinstance(byte_str, (bytearray, bytes)):
- raise TypeError( # pragma: nocover
- "Expected object of type bytes or bytearray, got: "
- "{0}".format(type(byte_str))
- )
-
- if isinstance(byte_str, bytearray):
- byte_str = bytes(byte_str)
-
- r = from_bytes(byte_str).best()
-
- encoding = r.encoding if r is not None else None
- language = r.language if r is not None and r.language != "Unknown" else ""
- confidence = 1.0 - r.chaos if r is not None else None
-
- # Note: CharsetNormalizer does not return 'UTF-8-SIG' as the sig get stripped in the detection/normalization process
- # but chardet does return 'utf-8-sig' and it is a valid codec name.
- if r is not None and encoding == "utf_8" and r.bom:
- encoding += "_sig"
-
- if should_rename_legacy is False and encoding in CHARDET_CORRESPONDENCE:
- encoding = CHARDET_CORRESPONDENCE[encoding]
-
- return {
- "encoding": encoding,
- "language": language,
- "confidence": confidence,
- }
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so b/.venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so
deleted file mode 100755
index 3d0b46a..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/md.cpython-312-x86_64-linux-gnu.so and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/md.py b/.venv/lib/python3.12/site-packages/charset_normalizer/md.py
deleted file mode 100644
index 77897aa..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/md.py
+++ /dev/null
@@ -1,615 +0,0 @@
-from functools import lru_cache
-from logging import getLogger
-from typing import List, Optional
-
-from .constant import (
- COMMON_SAFE_ASCII_CHARACTERS,
- TRACE,
- UNICODE_SECONDARY_RANGE_KEYWORD,
-)
-from .utils import (
- is_accentuated,
- is_arabic,
- is_arabic_isolated_form,
- is_case_variable,
- is_cjk,
- is_emoticon,
- is_hangul,
- is_hiragana,
- is_katakana,
- is_latin,
- is_punctuation,
- is_separator,
- is_symbol,
- is_thai,
- is_unprintable,
- remove_accent,
- unicode_range,
-)
-
-
-class MessDetectorPlugin:
- """
- Base abstract class used for mess detection plugins.
- All detectors MUST extend and implement given methods.
- """
-
- def eligible(self, character: str) -> bool:
- """
- Determine if given character should be fed in.
- """
- raise NotImplementedError # pragma: nocover
-
- def feed(self, character: str) -> None:
- """
- The main routine to be executed upon character.
- Insert the logic in witch the text would be considered chaotic.
- """
- raise NotImplementedError # pragma: nocover
-
- def reset(self) -> None: # pragma: no cover
- """
- Permit to reset the plugin to the initial state.
- """
- raise NotImplementedError
-
- @property
- def ratio(self) -> float:
- """
- Compute the chaos ratio based on what your feed() has seen.
- Must NOT be lower than 0.; No restriction gt 0.
- """
- raise NotImplementedError # pragma: nocover
-
-
-class TooManySymbolOrPunctuationPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._punctuation_count: int = 0
- self._symbol_count: int = 0
- self._character_count: int = 0
-
- self._last_printable_char: Optional[str] = None
- self._frenzy_symbol_in_word: bool = False
-
- def eligible(self, character: str) -> bool:
- return character.isprintable()
-
- def feed(self, character: str) -> None:
- self._character_count += 1
-
- if (
- character != self._last_printable_char
- and character not in COMMON_SAFE_ASCII_CHARACTERS
- ):
- if is_punctuation(character):
- self._punctuation_count += 1
- elif (
- character.isdigit() is False
- and is_symbol(character)
- and is_emoticon(character) is False
- ):
- self._symbol_count += 2
-
- self._last_printable_char = character
-
- def reset(self) -> None: # pragma: no cover
- self._punctuation_count = 0
- self._character_count = 0
- self._symbol_count = 0
-
- @property
- def ratio(self) -> float:
- if self._character_count == 0:
- return 0.0
-
- ratio_of_punctuation: float = (
- self._punctuation_count + self._symbol_count
- ) / self._character_count
-
- return ratio_of_punctuation if ratio_of_punctuation >= 0.3 else 0.0
-
-
-class TooManyAccentuatedPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._character_count: int = 0
- self._accentuated_count: int = 0
-
- def eligible(self, character: str) -> bool:
- return character.isalpha()
-
- def feed(self, character: str) -> None:
- self._character_count += 1
-
- if is_accentuated(character):
- self._accentuated_count += 1
-
- def reset(self) -> None: # pragma: no cover
- self._character_count = 0
- self._accentuated_count = 0
-
- @property
- def ratio(self) -> float:
- if self._character_count < 8:
- return 0.0
-
- ratio_of_accentuation: float = self._accentuated_count / self._character_count
- return ratio_of_accentuation if ratio_of_accentuation >= 0.35 else 0.0
-
-
-class UnprintablePlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._unprintable_count: int = 0
- self._character_count: int = 0
-
- def eligible(self, character: str) -> bool:
- return True
-
- def feed(self, character: str) -> None:
- if is_unprintable(character):
- self._unprintable_count += 1
- self._character_count += 1
-
- def reset(self) -> None: # pragma: no cover
- self._unprintable_count = 0
-
- @property
- def ratio(self) -> float:
- if self._character_count == 0:
- return 0.0
-
- return (self._unprintable_count * 8) / self._character_count
-
-
-class SuspiciousDuplicateAccentPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._successive_count: int = 0
- self._character_count: int = 0
-
- self._last_latin_character: Optional[str] = None
-
- def eligible(self, character: str) -> bool:
- return character.isalpha() and is_latin(character)
-
- def feed(self, character: str) -> None:
- self._character_count += 1
- if (
- self._last_latin_character is not None
- and is_accentuated(character)
- and is_accentuated(self._last_latin_character)
- ):
- if character.isupper() and self._last_latin_character.isupper():
- self._successive_count += 1
- # Worse if its the same char duplicated with different accent.
- if remove_accent(character) == remove_accent(self._last_latin_character):
- self._successive_count += 1
- self._last_latin_character = character
-
- def reset(self) -> None: # pragma: no cover
- self._successive_count = 0
- self._character_count = 0
- self._last_latin_character = None
-
- @property
- def ratio(self) -> float:
- if self._character_count == 0:
- return 0.0
-
- return (self._successive_count * 2) / self._character_count
-
-
-class SuspiciousRange(MessDetectorPlugin):
- def __init__(self) -> None:
- self._suspicious_successive_range_count: int = 0
- self._character_count: int = 0
- self._last_printable_seen: Optional[str] = None
-
- def eligible(self, character: str) -> bool:
- return character.isprintable()
-
- def feed(self, character: str) -> None:
- self._character_count += 1
-
- if (
- character.isspace()
- or is_punctuation(character)
- or character in COMMON_SAFE_ASCII_CHARACTERS
- ):
- self._last_printable_seen = None
- return
-
- if self._last_printable_seen is None:
- self._last_printable_seen = character
- return
-
- unicode_range_a: Optional[str] = unicode_range(self._last_printable_seen)
- unicode_range_b: Optional[str] = unicode_range(character)
-
- if is_suspiciously_successive_range(unicode_range_a, unicode_range_b):
- self._suspicious_successive_range_count += 1
-
- self._last_printable_seen = character
-
- def reset(self) -> None: # pragma: no cover
- self._character_count = 0
- self._suspicious_successive_range_count = 0
- self._last_printable_seen = None
-
- @property
- def ratio(self) -> float:
- if self._character_count <= 24:
- return 0.0
-
- ratio_of_suspicious_range_usage: float = (
- self._suspicious_successive_range_count * 2
- ) / self._character_count
-
- return ratio_of_suspicious_range_usage
-
-
-class SuperWeirdWordPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._word_count: int = 0
- self._bad_word_count: int = 0
- self._foreign_long_count: int = 0
-
- self._is_current_word_bad: bool = False
- self._foreign_long_watch: bool = False
-
- self._character_count: int = 0
- self._bad_character_count: int = 0
-
- self._buffer: str = ""
- self._buffer_accent_count: int = 0
-
- def eligible(self, character: str) -> bool:
- return True
-
- def feed(self, character: str) -> None:
- if character.isalpha():
- self._buffer += character
- if is_accentuated(character):
- self._buffer_accent_count += 1
- if (
- self._foreign_long_watch is False
- and (is_latin(character) is False or is_accentuated(character))
- and is_cjk(character) is False
- and is_hangul(character) is False
- and is_katakana(character) is False
- and is_hiragana(character) is False
- and is_thai(character) is False
- ):
- self._foreign_long_watch = True
- return
- if not self._buffer:
- return
- if (
- character.isspace() or is_punctuation(character) or is_separator(character)
- ) and self._buffer:
- self._word_count += 1
- buffer_length: int = len(self._buffer)
-
- self._character_count += buffer_length
-
- if buffer_length >= 4:
- if self._buffer_accent_count / buffer_length > 0.34:
- self._is_current_word_bad = True
- # Word/Buffer ending with an upper case accentuated letter are so rare,
- # that we will consider them all as suspicious. Same weight as foreign_long suspicious.
- if (
- is_accentuated(self._buffer[-1])
- and self._buffer[-1].isupper()
- and all(_.isupper() for _ in self._buffer) is False
- ):
- self._foreign_long_count += 1
- self._is_current_word_bad = True
- if buffer_length >= 24 and self._foreign_long_watch:
- camel_case_dst = [
- i
- for c, i in zip(self._buffer, range(0, buffer_length))
- if c.isupper()
- ]
- probable_camel_cased: bool = False
-
- if camel_case_dst and (len(camel_case_dst) / buffer_length <= 0.3):
- probable_camel_cased = True
-
- if not probable_camel_cased:
- self._foreign_long_count += 1
- self._is_current_word_bad = True
-
- if self._is_current_word_bad:
- self._bad_word_count += 1
- self._bad_character_count += len(self._buffer)
- self._is_current_word_bad = False
-
- self._foreign_long_watch = False
- self._buffer = ""
- self._buffer_accent_count = 0
- elif (
- character not in {"<", ">", "-", "=", "~", "|", "_"}
- and character.isdigit() is False
- and is_symbol(character)
- ):
- self._is_current_word_bad = True
- self._buffer += character
-
- def reset(self) -> None: # pragma: no cover
- self._buffer = ""
- self._is_current_word_bad = False
- self._foreign_long_watch = False
- self._bad_word_count = 0
- self._word_count = 0
- self._character_count = 0
- self._bad_character_count = 0
- self._foreign_long_count = 0
-
- @property
- def ratio(self) -> float:
- if self._word_count <= 10 and self._foreign_long_count == 0:
- return 0.0
-
- return self._bad_character_count / self._character_count
-
-
-class CjkInvalidStopPlugin(MessDetectorPlugin):
- """
- GB(Chinese) based encoding often render the stop incorrectly when the content does not fit and
- can be easily detected. Searching for the overuse of '丅' and '丄'.
- """
-
- def __init__(self) -> None:
- self._wrong_stop_count: int = 0
- self._cjk_character_count: int = 0
-
- def eligible(self, character: str) -> bool:
- return True
-
- def feed(self, character: str) -> None:
- if character in {"丅", "丄"}:
- self._wrong_stop_count += 1
- return
- if is_cjk(character):
- self._cjk_character_count += 1
-
- def reset(self) -> None: # pragma: no cover
- self._wrong_stop_count = 0
- self._cjk_character_count = 0
-
- @property
- def ratio(self) -> float:
- if self._cjk_character_count < 16:
- return 0.0
- return self._wrong_stop_count / self._cjk_character_count
-
-
-class ArchaicUpperLowerPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._buf: bool = False
-
- self._character_count_since_last_sep: int = 0
-
- self._successive_upper_lower_count: int = 0
- self._successive_upper_lower_count_final: int = 0
-
- self._character_count: int = 0
-
- self._last_alpha_seen: Optional[str] = None
- self._current_ascii_only: bool = True
-
- def eligible(self, character: str) -> bool:
- return True
-
- def feed(self, character: str) -> None:
- is_concerned = character.isalpha() and is_case_variable(character)
- chunk_sep = is_concerned is False
-
- if chunk_sep and self._character_count_since_last_sep > 0:
- if (
- self._character_count_since_last_sep <= 64
- and character.isdigit() is False
- and self._current_ascii_only is False
- ):
- self._successive_upper_lower_count_final += (
- self._successive_upper_lower_count
- )
-
- self._successive_upper_lower_count = 0
- self._character_count_since_last_sep = 0
- self._last_alpha_seen = None
- self._buf = False
- self._character_count += 1
- self._current_ascii_only = True
-
- return
-
- if self._current_ascii_only is True and character.isascii() is False:
- self._current_ascii_only = False
-
- if self._last_alpha_seen is not None:
- if (character.isupper() and self._last_alpha_seen.islower()) or (
- character.islower() and self._last_alpha_seen.isupper()
- ):
- if self._buf is True:
- self._successive_upper_lower_count += 2
- self._buf = False
- else:
- self._buf = True
- else:
- self._buf = False
-
- self._character_count += 1
- self._character_count_since_last_sep += 1
- self._last_alpha_seen = character
-
- def reset(self) -> None: # pragma: no cover
- self._character_count = 0
- self._character_count_since_last_sep = 0
- self._successive_upper_lower_count = 0
- self._successive_upper_lower_count_final = 0
- self._last_alpha_seen = None
- self._buf = False
- self._current_ascii_only = True
-
- @property
- def ratio(self) -> float:
- if self._character_count == 0:
- return 0.0
-
- return self._successive_upper_lower_count_final / self._character_count
-
-
-class ArabicIsolatedFormPlugin(MessDetectorPlugin):
- def __init__(self) -> None:
- self._character_count: int = 0
- self._isolated_form_count: int = 0
-
- def reset(self) -> None: # pragma: no cover
- self._character_count = 0
- self._isolated_form_count = 0
-
- def eligible(self, character: str) -> bool:
- return is_arabic(character)
-
- def feed(self, character: str) -> None:
- self._character_count += 1
-
- if is_arabic_isolated_form(character):
- self._isolated_form_count += 1
-
- @property
- def ratio(self) -> float:
- if self._character_count < 8:
- return 0.0
-
- isolated_form_usage: float = self._isolated_form_count / self._character_count
-
- return isolated_form_usage
-
-
-@lru_cache(maxsize=1024)
-def is_suspiciously_successive_range(
- unicode_range_a: Optional[str], unicode_range_b: Optional[str]
-) -> bool:
- """
- Determine if two Unicode range seen next to each other can be considered as suspicious.
- """
- if unicode_range_a is None or unicode_range_b is None:
- return True
-
- if unicode_range_a == unicode_range_b:
- return False
-
- if "Latin" in unicode_range_a and "Latin" in unicode_range_b:
- return False
-
- if "Emoticons" in unicode_range_a or "Emoticons" in unicode_range_b:
- return False
-
- # Latin characters can be accompanied with a combining diacritical mark
- # eg. Vietnamese.
- if ("Latin" in unicode_range_a or "Latin" in unicode_range_b) and (
- "Combining" in unicode_range_a or "Combining" in unicode_range_b
- ):
- return False
-
- keywords_range_a, keywords_range_b = unicode_range_a.split(
- " "
- ), unicode_range_b.split(" ")
-
- for el in keywords_range_a:
- if el in UNICODE_SECONDARY_RANGE_KEYWORD:
- continue
- if el in keywords_range_b:
- return False
-
- # Japanese Exception
- range_a_jp_chars, range_b_jp_chars = (
- unicode_range_a
- in (
- "Hiragana",
- "Katakana",
- ),
- unicode_range_b in ("Hiragana", "Katakana"),
- )
- if (range_a_jp_chars or range_b_jp_chars) and (
- "CJK" in unicode_range_a or "CJK" in unicode_range_b
- ):
- return False
- if range_a_jp_chars and range_b_jp_chars:
- return False
-
- if "Hangul" in unicode_range_a or "Hangul" in unicode_range_b:
- if "CJK" in unicode_range_a or "CJK" in unicode_range_b:
- return False
- if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin":
- return False
-
- # Chinese/Japanese use dedicated range for punctuation and/or separators.
- if ("CJK" in unicode_range_a or "CJK" in unicode_range_b) or (
- unicode_range_a in ["Katakana", "Hiragana"]
- and unicode_range_b in ["Katakana", "Hiragana"]
- ):
- if "Punctuation" in unicode_range_a or "Punctuation" in unicode_range_b:
- return False
- if "Forms" in unicode_range_a or "Forms" in unicode_range_b:
- return False
- if unicode_range_a == "Basic Latin" or unicode_range_b == "Basic Latin":
- return False
-
- return True
-
-
-@lru_cache(maxsize=2048)
-def mess_ratio(
- decoded_sequence: str, maximum_threshold: float = 0.2, debug: bool = False
-) -> float:
- """
- Compute a mess ratio given a decoded bytes sequence. The maximum threshold does stop the computation earlier.
- """
-
- detectors: List[MessDetectorPlugin] = [
- md_class() for md_class in MessDetectorPlugin.__subclasses__()
- ]
-
- length: int = len(decoded_sequence) + 1
-
- mean_mess_ratio: float = 0.0
-
- if length < 512:
- intermediary_mean_mess_ratio_calc: int = 32
- elif length <= 1024:
- intermediary_mean_mess_ratio_calc = 64
- else:
- intermediary_mean_mess_ratio_calc = 128
-
- for character, index in zip(decoded_sequence + "\n", range(length)):
- for detector in detectors:
- if detector.eligible(character):
- detector.feed(character)
-
- if (
- index > 0 and index % intermediary_mean_mess_ratio_calc == 0
- ) or index == length - 1:
- mean_mess_ratio = sum(dt.ratio for dt in detectors)
-
- if mean_mess_ratio >= maximum_threshold:
- break
-
- if debug:
- logger = getLogger("charset_normalizer")
-
- logger.log(
- TRACE,
- "Mess-detector extended-analysis start. "
- f"intermediary_mean_mess_ratio_calc={intermediary_mean_mess_ratio_calc} mean_mess_ratio={mean_mess_ratio} "
- f"maximum_threshold={maximum_threshold}",
- )
-
- if len(decoded_sequence) > 16:
- logger.log(TRACE, f"Starting with: {decoded_sequence[:16]}")
- logger.log(TRACE, f"Ending with: {decoded_sequence[-16::]}")
-
- for dt in detectors: # pragma: nocover
- logger.log(TRACE, f"{dt.__class__}: {dt.ratio}")
-
- return round(mean_mess_ratio, 3)
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so b/.venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so
deleted file mode 100755
index e3044d9..0000000
Binary files a/.venv/lib/python3.12/site-packages/charset_normalizer/md__mypyc.cpython-312-x86_64-linux-gnu.so and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/models.py b/.venv/lib/python3.12/site-packages/charset_normalizer/models.py
deleted file mode 100644
index a760b9c..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/models.py
+++ /dev/null
@@ -1,340 +0,0 @@
-from encodings.aliases import aliases
-from hashlib import sha256
-from json import dumps
-from typing import Any, Dict, Iterator, List, Optional, Tuple, Union
-
-from .constant import TOO_BIG_SEQUENCE
-from .utils import iana_name, is_multi_byte_encoding, unicode_range
-
-
-class CharsetMatch:
- def __init__(
- self,
- payload: bytes,
- guessed_encoding: str,
- mean_mess_ratio: float,
- has_sig_or_bom: bool,
- languages: "CoherenceMatches",
- decoded_payload: Optional[str] = None,
- ):
- self._payload: bytes = payload
-
- self._encoding: str = guessed_encoding
- self._mean_mess_ratio: float = mean_mess_ratio
- self._languages: CoherenceMatches = languages
- self._has_sig_or_bom: bool = has_sig_or_bom
- self._unicode_ranges: Optional[List[str]] = None
-
- self._leaves: List[CharsetMatch] = []
- self._mean_coherence_ratio: float = 0.0
-
- self._output_payload: Optional[bytes] = None
- self._output_encoding: Optional[str] = None
-
- self._string: Optional[str] = decoded_payload
-
- def __eq__(self, other: object) -> bool:
- if not isinstance(other, CharsetMatch):
- raise TypeError(
- "__eq__ cannot be invoked on {} and {}.".format(
- str(other.__class__), str(self.__class__)
- )
- )
- return self.encoding == other.encoding and self.fingerprint == other.fingerprint
-
- def __lt__(self, other: object) -> bool:
- """
- Implemented to make sorted available upon CharsetMatches items.
- """
- if not isinstance(other, CharsetMatch):
- raise ValueError
-
- chaos_difference: float = abs(self.chaos - other.chaos)
- coherence_difference: float = abs(self.coherence - other.coherence)
-
- # Below 1% difference --> Use Coherence
- if chaos_difference < 0.01 and coherence_difference > 0.02:
- return self.coherence > other.coherence
- elif chaos_difference < 0.01 and coherence_difference <= 0.02:
- # When having a difficult decision, use the result that decoded as many multi-byte as possible.
- # preserve RAM usage!
- if len(self._payload) >= TOO_BIG_SEQUENCE:
- return self.chaos < other.chaos
- return self.multi_byte_usage > other.multi_byte_usage
-
- return self.chaos < other.chaos
-
- @property
- def multi_byte_usage(self) -> float:
- return 1.0 - (len(str(self)) / len(self.raw))
-
- def __str__(self) -> str:
- # Lazy Str Loading
- if self._string is None:
- self._string = str(self._payload, self._encoding, "strict")
- return self._string
-
- def __repr__(self) -> str:
- return "".format(self.encoding, self.fingerprint)
-
- def add_submatch(self, other: "CharsetMatch") -> None:
- if not isinstance(other, CharsetMatch) or other == self:
- raise ValueError(
- "Unable to add instance <{}> as a submatch of a CharsetMatch".format(
- other.__class__
- )
- )
-
- other._string = None # Unload RAM usage; dirty trick.
- self._leaves.append(other)
-
- @property
- def encoding(self) -> str:
- return self._encoding
-
- @property
- def encoding_aliases(self) -> List[str]:
- """
- Encoding name are known by many name, using this could help when searching for IBM855 when it's listed as CP855.
- """
- also_known_as: List[str] = []
- for u, p in aliases.items():
- if self.encoding == u:
- also_known_as.append(p)
- elif self.encoding == p:
- also_known_as.append(u)
- return also_known_as
-
- @property
- def bom(self) -> bool:
- return self._has_sig_or_bom
-
- @property
- def byte_order_mark(self) -> bool:
- return self._has_sig_or_bom
-
- @property
- def languages(self) -> List[str]:
- """
- Return the complete list of possible languages found in decoded sequence.
- Usually not really useful. Returned list may be empty even if 'language' property return something != 'Unknown'.
- """
- return [e[0] for e in self._languages]
-
- @property
- def language(self) -> str:
- """
- Most probable language found in decoded sequence. If none were detected or inferred, the property will return
- "Unknown".
- """
- if not self._languages:
- # Trying to infer the language based on the given encoding
- # Its either English or we should not pronounce ourselves in certain cases.
- if "ascii" in self.could_be_from_charset:
- return "English"
-
- # doing it there to avoid circular import
- from charset_normalizer.cd import encoding_languages, mb_encoding_languages
-
- languages = (
- mb_encoding_languages(self.encoding)
- if is_multi_byte_encoding(self.encoding)
- else encoding_languages(self.encoding)
- )
-
- if len(languages) == 0 or "Latin Based" in languages:
- return "Unknown"
-
- return languages[0]
-
- return self._languages[0][0]
-
- @property
- def chaos(self) -> float:
- return self._mean_mess_ratio
-
- @property
- def coherence(self) -> float:
- if not self._languages:
- return 0.0
- return self._languages[0][1]
-
- @property
- def percent_chaos(self) -> float:
- return round(self.chaos * 100, ndigits=3)
-
- @property
- def percent_coherence(self) -> float:
- return round(self.coherence * 100, ndigits=3)
-
- @property
- def raw(self) -> bytes:
- """
- Original untouched bytes.
- """
- return self._payload
-
- @property
- def submatch(self) -> List["CharsetMatch"]:
- return self._leaves
-
- @property
- def has_submatch(self) -> bool:
- return len(self._leaves) > 0
-
- @property
- def alphabets(self) -> List[str]:
- if self._unicode_ranges is not None:
- return self._unicode_ranges
- # list detected ranges
- detected_ranges: List[Optional[str]] = [
- unicode_range(char) for char in str(self)
- ]
- # filter and sort
- self._unicode_ranges = sorted(list({r for r in detected_ranges if r}))
- return self._unicode_ranges
-
- @property
- def could_be_from_charset(self) -> List[str]:
- """
- The complete list of encoding that output the exact SAME str result and therefore could be the originating
- encoding.
- This list does include the encoding available in property 'encoding'.
- """
- return [self._encoding] + [m.encoding for m in self._leaves]
-
- def output(self, encoding: str = "utf_8") -> bytes:
- """
- Method to get re-encoded bytes payload using given target encoding. Default to UTF-8.
- Any errors will be simply ignored by the encoder NOT replaced.
- """
- if self._output_encoding is None or self._output_encoding != encoding:
- self._output_encoding = encoding
- self._output_payload = str(self).encode(encoding, "replace")
-
- return self._output_payload # type: ignore
-
- @property
- def fingerprint(self) -> str:
- """
- Retrieve the unique SHA256 computed using the transformed (re-encoded) payload. Not the original one.
- """
- return sha256(self.output()).hexdigest()
-
-
-class CharsetMatches:
- """
- Container with every CharsetMatch items ordered by default from most probable to the less one.
- Act like a list(iterable) but does not implements all related methods.
- """
-
- def __init__(self, results: Optional[List[CharsetMatch]] = None):
- self._results: List[CharsetMatch] = sorted(results) if results else []
-
- def __iter__(self) -> Iterator[CharsetMatch]:
- yield from self._results
-
- def __getitem__(self, item: Union[int, str]) -> CharsetMatch:
- """
- Retrieve a single item either by its position or encoding name (alias may be used here).
- Raise KeyError upon invalid index or encoding not present in results.
- """
- if isinstance(item, int):
- return self._results[item]
- if isinstance(item, str):
- item = iana_name(item, False)
- for result in self._results:
- if item in result.could_be_from_charset:
- return result
- raise KeyError
-
- def __len__(self) -> int:
- return len(self._results)
-
- def __bool__(self) -> bool:
- return len(self._results) > 0
-
- def append(self, item: CharsetMatch) -> None:
- """
- Insert a single match. Will be inserted accordingly to preserve sort.
- Can be inserted as a submatch.
- """
- if not isinstance(item, CharsetMatch):
- raise ValueError(
- "Cannot append instance '{}' to CharsetMatches".format(
- str(item.__class__)
- )
- )
- # We should disable the submatch factoring when the input file is too heavy (conserve RAM usage)
- if len(item.raw) <= TOO_BIG_SEQUENCE:
- for match in self._results:
- if match.fingerprint == item.fingerprint and match.chaos == item.chaos:
- match.add_submatch(item)
- return
- self._results.append(item)
- self._results = sorted(self._results)
-
- def best(self) -> Optional["CharsetMatch"]:
- """
- Simply return the first match. Strict equivalent to matches[0].
- """
- if not self._results:
- return None
- return self._results[0]
-
- def first(self) -> Optional["CharsetMatch"]:
- """
- Redundant method, call the method best(). Kept for BC reasons.
- """
- return self.best()
-
-
-CoherenceMatch = Tuple[str, float]
-CoherenceMatches = List[CoherenceMatch]
-
-
-class CliDetectionResult:
- def __init__(
- self,
- path: str,
- encoding: Optional[str],
- encoding_aliases: List[str],
- alternative_encodings: List[str],
- language: str,
- alphabets: List[str],
- has_sig_or_bom: bool,
- chaos: float,
- coherence: float,
- unicode_path: Optional[str],
- is_preferred: bool,
- ):
- self.path: str = path
- self.unicode_path: Optional[str] = unicode_path
- self.encoding: Optional[str] = encoding
- self.encoding_aliases: List[str] = encoding_aliases
- self.alternative_encodings: List[str] = alternative_encodings
- self.language: str = language
- self.alphabets: List[str] = alphabets
- self.has_sig_or_bom: bool = has_sig_or_bom
- self.chaos: float = chaos
- self.coherence: float = coherence
- self.is_preferred: bool = is_preferred
-
- @property
- def __dict__(self) -> Dict[str, Any]: # type: ignore
- return {
- "path": self.path,
- "encoding": self.encoding,
- "encoding_aliases": self.encoding_aliases,
- "alternative_encodings": self.alternative_encodings,
- "language": self.language,
- "alphabets": self.alphabets,
- "has_sig_or_bom": self.has_sig_or_bom,
- "chaos": self.chaos,
- "coherence": self.coherence,
- "unicode_path": self.unicode_path,
- "is_preferred": self.is_preferred,
- }
-
- def to_json(self) -> str:
- return dumps(self.__dict__, ensure_ascii=True, indent=4)
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/py.typed b/.venv/lib/python3.12/site-packages/charset_normalizer/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/utils.py b/.venv/lib/python3.12/site-packages/charset_normalizer/utils.py
deleted file mode 100644
index e5cbbf4..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/utils.py
+++ /dev/null
@@ -1,421 +0,0 @@
-import importlib
-import logging
-import unicodedata
-from codecs import IncrementalDecoder
-from encodings.aliases import aliases
-from functools import lru_cache
-from re import findall
-from typing import Generator, List, Optional, Set, Tuple, Union
-
-from _multibytecodec import MultibyteIncrementalDecoder
-
-from .constant import (
- ENCODING_MARKS,
- IANA_SUPPORTED_SIMILAR,
- RE_POSSIBLE_ENCODING_INDICATION,
- UNICODE_RANGES_COMBINED,
- UNICODE_SECONDARY_RANGE_KEYWORD,
- UTF8_MAXIMAL_ALLOCATION,
-)
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_accentuated(character: str) -> bool:
- try:
- description: str = unicodedata.name(character)
- except ValueError:
- return False
- return (
- "WITH GRAVE" in description
- or "WITH ACUTE" in description
- or "WITH CEDILLA" in description
- or "WITH DIAERESIS" in description
- or "WITH CIRCUMFLEX" in description
- or "WITH TILDE" in description
- or "WITH MACRON" in description
- or "WITH RING ABOVE" in description
- )
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def remove_accent(character: str) -> str:
- decomposed: str = unicodedata.decomposition(character)
- if not decomposed:
- return character
-
- codes: List[str] = decomposed.split(" ")
-
- return chr(int(codes[0], 16))
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def unicode_range(character: str) -> Optional[str]:
- """
- Retrieve the Unicode range official name from a single character.
- """
- character_ord: int = ord(character)
-
- for range_name, ord_range in UNICODE_RANGES_COMBINED.items():
- if character_ord in ord_range:
- return range_name
-
- return None
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_latin(character: str) -> bool:
- try:
- description: str = unicodedata.name(character)
- except ValueError:
- return False
- return "LATIN" in description
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_punctuation(character: str) -> bool:
- character_category: str = unicodedata.category(character)
-
- if "P" in character_category:
- return True
-
- character_range: Optional[str] = unicode_range(character)
-
- if character_range is None:
- return False
-
- return "Punctuation" in character_range
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_symbol(character: str) -> bool:
- character_category: str = unicodedata.category(character)
-
- if "S" in character_category or "N" in character_category:
- return True
-
- character_range: Optional[str] = unicode_range(character)
-
- if character_range is None:
- return False
-
- return "Forms" in character_range and character_category != "Lo"
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_emoticon(character: str) -> bool:
- character_range: Optional[str] = unicode_range(character)
-
- if character_range is None:
- return False
-
- return "Emoticons" in character_range or "Pictographs" in character_range
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_separator(character: str) -> bool:
- if character.isspace() or character in {"|", "+", "<", ">"}:
- return True
-
- character_category: str = unicodedata.category(character)
-
- return "Z" in character_category or character_category in {"Po", "Pd", "Pc"}
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_case_variable(character: str) -> bool:
- return character.islower() != character.isupper()
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_cjk(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "CJK" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_hiragana(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "HIRAGANA" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_katakana(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "KATAKANA" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_hangul(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "HANGUL" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_thai(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "THAI" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_arabic(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "ARABIC" in character_name
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_arabic_isolated_form(character: str) -> bool:
- try:
- character_name = unicodedata.name(character)
- except ValueError:
- return False
-
- return "ARABIC" in character_name and "ISOLATED FORM" in character_name
-
-
-@lru_cache(maxsize=len(UNICODE_RANGES_COMBINED))
-def is_unicode_range_secondary(range_name: str) -> bool:
- return any(keyword in range_name for keyword in UNICODE_SECONDARY_RANGE_KEYWORD)
-
-
-@lru_cache(maxsize=UTF8_MAXIMAL_ALLOCATION)
-def is_unprintable(character: str) -> bool:
- return (
- character.isspace() is False # includes \n \t \r \v
- and character.isprintable() is False
- and character != "\x1A" # Why? Its the ASCII substitute character.
- and character != "\ufeff" # bug discovered in Python,
- # Zero Width No-Break Space located in Arabic Presentation Forms-B, Unicode 1.1 not acknowledged as space.
- )
-
-
-def any_specified_encoding(sequence: bytes, search_zone: int = 8192) -> Optional[str]:
- """
- Extract using ASCII-only decoder any specified encoding in the first n-bytes.
- """
- if not isinstance(sequence, bytes):
- raise TypeError
-
- seq_len: int = len(sequence)
-
- results: List[str] = findall(
- RE_POSSIBLE_ENCODING_INDICATION,
- sequence[: min(seq_len, search_zone)].decode("ascii", errors="ignore"),
- )
-
- if len(results) == 0:
- return None
-
- for specified_encoding in results:
- specified_encoding = specified_encoding.lower().replace("-", "_")
-
- encoding_alias: str
- encoding_iana: str
-
- for encoding_alias, encoding_iana in aliases.items():
- if encoding_alias == specified_encoding:
- return encoding_iana
- if encoding_iana == specified_encoding:
- return encoding_iana
-
- return None
-
-
-@lru_cache(maxsize=128)
-def is_multi_byte_encoding(name: str) -> bool:
- """
- Verify is a specific encoding is a multi byte one based on it IANA name
- """
- return name in {
- "utf_8",
- "utf_8_sig",
- "utf_16",
- "utf_16_be",
- "utf_16_le",
- "utf_32",
- "utf_32_le",
- "utf_32_be",
- "utf_7",
- } or issubclass(
- importlib.import_module("encodings.{}".format(name)).IncrementalDecoder,
- MultibyteIncrementalDecoder,
- )
-
-
-def identify_sig_or_bom(sequence: bytes) -> Tuple[Optional[str], bytes]:
- """
- Identify and extract SIG/BOM in given sequence.
- """
-
- for iana_encoding in ENCODING_MARKS:
- marks: Union[bytes, List[bytes]] = ENCODING_MARKS[iana_encoding]
-
- if isinstance(marks, bytes):
- marks = [marks]
-
- for mark in marks:
- if sequence.startswith(mark):
- return iana_encoding, mark
-
- return None, b""
-
-
-def should_strip_sig_or_bom(iana_encoding: str) -> bool:
- return iana_encoding not in {"utf_16", "utf_32"}
-
-
-def iana_name(cp_name: str, strict: bool = True) -> str:
- cp_name = cp_name.lower().replace("-", "_")
-
- encoding_alias: str
- encoding_iana: str
-
- for encoding_alias, encoding_iana in aliases.items():
- if cp_name in [encoding_alias, encoding_iana]:
- return encoding_iana
-
- if strict:
- raise ValueError("Unable to retrieve IANA for '{}'".format(cp_name))
-
- return cp_name
-
-
-def range_scan(decoded_sequence: str) -> List[str]:
- ranges: Set[str] = set()
-
- for character in decoded_sequence:
- character_range: Optional[str] = unicode_range(character)
-
- if character_range is None:
- continue
-
- ranges.add(character_range)
-
- return list(ranges)
-
-
-def cp_similarity(iana_name_a: str, iana_name_b: str) -> float:
- if is_multi_byte_encoding(iana_name_a) or is_multi_byte_encoding(iana_name_b):
- return 0.0
-
- decoder_a = importlib.import_module(
- "encodings.{}".format(iana_name_a)
- ).IncrementalDecoder
- decoder_b = importlib.import_module(
- "encodings.{}".format(iana_name_b)
- ).IncrementalDecoder
-
- id_a: IncrementalDecoder = decoder_a(errors="ignore")
- id_b: IncrementalDecoder = decoder_b(errors="ignore")
-
- character_match_count: int = 0
-
- for i in range(255):
- to_be_decoded: bytes = bytes([i])
- if id_a.decode(to_be_decoded) == id_b.decode(to_be_decoded):
- character_match_count += 1
-
- return character_match_count / 254
-
-
-def is_cp_similar(iana_name_a: str, iana_name_b: str) -> bool:
- """
- Determine if two code page are at least 80% similar. IANA_SUPPORTED_SIMILAR dict was generated using
- the function cp_similarity.
- """
- return (
- iana_name_a in IANA_SUPPORTED_SIMILAR
- and iana_name_b in IANA_SUPPORTED_SIMILAR[iana_name_a]
- )
-
-
-def set_logging_handler(
- name: str = "charset_normalizer",
- level: int = logging.INFO,
- format_string: str = "%(asctime)s | %(levelname)s | %(message)s",
-) -> None:
- logger = logging.getLogger(name)
- logger.setLevel(level)
-
- handler = logging.StreamHandler()
- handler.setFormatter(logging.Formatter(format_string))
- logger.addHandler(handler)
-
-
-def cut_sequence_chunks(
- sequences: bytes,
- encoding_iana: str,
- offsets: range,
- chunk_size: int,
- bom_or_sig_available: bool,
- strip_sig_or_bom: bool,
- sig_payload: bytes,
- is_multi_byte_decoder: bool,
- decoded_payload: Optional[str] = None,
-) -> Generator[str, None, None]:
- if decoded_payload and is_multi_byte_decoder is False:
- for i in offsets:
- chunk = decoded_payload[i : i + chunk_size]
- if not chunk:
- break
- yield chunk
- else:
- for i in offsets:
- chunk_end = i + chunk_size
- if chunk_end > len(sequences) + 8:
- continue
-
- cut_sequence = sequences[i : i + chunk_size]
-
- if bom_or_sig_available and strip_sig_or_bom is False:
- cut_sequence = sig_payload + cut_sequence
-
- chunk = cut_sequence.decode(
- encoding_iana,
- errors="ignore" if is_multi_byte_decoder else "strict",
- )
-
- # multi-byte bad cutting detector and adjustment
- # not the cleanest way to perform that fix but clever enough for now.
- if is_multi_byte_decoder and i > 0:
- chunk_partial_size_chk: int = min(chunk_size, 16)
-
- if (
- decoded_payload
- and chunk[:chunk_partial_size_chk] not in decoded_payload
- ):
- for j in range(i, i - 4, -1):
- cut_sequence = sequences[j:chunk_end]
-
- if bom_or_sig_available and strip_sig_or_bom is False:
- cut_sequence = sig_payload + cut_sequence
-
- chunk = cut_sequence.decode(encoding_iana, errors="ignore")
-
- if chunk[:chunk_partial_size_chk] in decoded_payload:
- break
-
- yield chunk
diff --git a/.venv/lib/python3.12/site-packages/charset_normalizer/version.py b/.venv/lib/python3.12/site-packages/charset_normalizer/version.py
deleted file mode 100644
index 5a4da4f..0000000
--- a/.venv/lib/python3.12/site-packages/charset_normalizer/version.py
+++ /dev/null
@@ -1,6 +0,0 @@
-"""
-Expose version
-"""
-
-__version__ = "3.3.2"
-VERSION = __version__.split(".")
diff --git a/.venv/lib/python3.12/site-packages/dns/__init__.py b/.venv/lib/python3.12/site-packages/dns/__init__.py
deleted file mode 100644
index a4249b9..0000000
--- a/.venv/lib/python3.12/site-packages/dns/__init__.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009, 2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""dnspython DNS toolkit"""
-
-__all__ = [
- "asyncbackend",
- "asyncquery",
- "asyncresolver",
- "dnssec",
- "dnssecalgs",
- "dnssectypes",
- "e164",
- "edns",
- "entropy",
- "exception",
- "flags",
- "immutable",
- "inet",
- "ipv4",
- "ipv6",
- "message",
- "name",
- "namedict",
- "node",
- "opcode",
- "query",
- "quic",
- "rcode",
- "rdata",
- "rdataclass",
- "rdataset",
- "rdatatype",
- "renderer",
- "resolver",
- "reversename",
- "rrset",
- "serial",
- "set",
- "tokenizer",
- "transaction",
- "tsig",
- "tsigkeyring",
- "ttl",
- "rdtypes",
- "update",
- "version",
- "versioned",
- "wire",
- "xfr",
- "zone",
- "zonetypes",
- "zonefile",
-]
-
-from dns.version import version as __version__ # noqa
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index dd1616c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncbackend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncbackend.cpython-312.pyc
deleted file mode 100644
index e1203dc..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncbackend.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncio_backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncio_backend.cpython-312.pyc
deleted file mode 100644
index 88cd29e..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_asyncio_backend.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_ddr.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_ddr.cpython-312.pyc
deleted file mode 100644
index 72f1045..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_ddr.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_features.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_features.cpython-312.pyc
deleted file mode 100644
index ed69c02..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_features.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_immutable_ctx.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_immutable_ctx.cpython-312.pyc
deleted file mode 100644
index 2eed9c0..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_immutable_ctx.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/_trio_backend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/_trio_backend.cpython-312.pyc
deleted file mode 100644
index 2afe865..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/_trio_backend.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncbackend.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncbackend.cpython-312.pyc
deleted file mode 100644
index f574560..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncbackend.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncquery.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncquery.cpython-312.pyc
deleted file mode 100644
index 5d98326..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncquery.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncresolver.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncresolver.cpython-312.pyc
deleted file mode 100644
index b7689d5..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/asyncresolver.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssec.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssec.cpython-312.pyc
deleted file mode 100644
index 3ba720f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssec.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssectypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssectypes.cpython-312.pyc
deleted file mode 100644
index 4337d41..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/dnssectypes.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/e164.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/e164.cpython-312.pyc
deleted file mode 100644
index e6c67b8..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/e164.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/edns.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/edns.cpython-312.pyc
deleted file mode 100644
index 88e4e06..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/edns.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/entropy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/entropy.cpython-312.pyc
deleted file mode 100644
index d44be4c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/entropy.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/enum.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/enum.cpython-312.pyc
deleted file mode 100644
index 7d2a4cf..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/enum.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/exception.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/exception.cpython-312.pyc
deleted file mode 100644
index c9fbefd..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/exception.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/flags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/flags.cpython-312.pyc
deleted file mode 100644
index 68e1990..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/flags.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/grange.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/grange.cpython-312.pyc
deleted file mode 100644
index 1bc04e2..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/grange.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/immutable.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/immutable.cpython-312.pyc
deleted file mode 100644
index da37dee..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/immutable.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/inet.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/inet.cpython-312.pyc
deleted file mode 100644
index 9a2fac4..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/inet.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv4.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv4.cpython-312.pyc
deleted file mode 100644
index dccdacd..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv4.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv6.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv6.cpython-312.pyc
deleted file mode 100644
index ddb0018..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/ipv6.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/message.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/message.cpython-312.pyc
deleted file mode 100644
index 044c59f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/message.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/name.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/name.cpython-312.pyc
deleted file mode 100644
index 95730fc..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/name.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/namedict.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/namedict.cpython-312.pyc
deleted file mode 100644
index 5265982..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/namedict.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/nameserver.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/nameserver.cpython-312.pyc
deleted file mode 100644
index 3ac1d76..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/nameserver.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/node.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/node.cpython-312.pyc
deleted file mode 100644
index 02cd8f9..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/node.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/opcode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/opcode.cpython-312.pyc
deleted file mode 100644
index c796861..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/opcode.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/query.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/query.cpython-312.pyc
deleted file mode 100644
index 21c66e2..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/query.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rcode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rcode.cpython-312.pyc
deleted file mode 100644
index aed870c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rcode.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rdata.cpython-312.pyc
deleted file mode 100644
index 4d8b274..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdata.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataclass.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataclass.cpython-312.pyc
deleted file mode 100644
index 7694b2c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataclass.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataset.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataset.cpython-312.pyc
deleted file mode 100644
index 30679f6..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdataset.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdatatype.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rdatatype.cpython-312.pyc
deleted file mode 100644
index 7ee1c10..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rdatatype.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/renderer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/renderer.cpython-312.pyc
deleted file mode 100644
index 8c08796..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/renderer.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/resolver.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/resolver.cpython-312.pyc
deleted file mode 100644
index 54a32dd..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/resolver.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/reversename.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/reversename.cpython-312.pyc
deleted file mode 100644
index 084a125..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/reversename.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/rrset.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/rrset.cpython-312.pyc
deleted file mode 100644
index 37b9e6a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/rrset.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/serial.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/serial.cpython-312.pyc
deleted file mode 100644
index d0cb00c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/serial.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/set.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/set.cpython-312.pyc
deleted file mode 100644
index eddd8df..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/set.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/tokenizer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/tokenizer.cpython-312.pyc
deleted file mode 100644
index b5f268c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/tokenizer.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/transaction.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/transaction.cpython-312.pyc
deleted file mode 100644
index c1042b4..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/transaction.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/tsig.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/tsig.cpython-312.pyc
deleted file mode 100644
index 61eb535..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/tsig.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/tsigkeyring.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/tsigkeyring.cpython-312.pyc
deleted file mode 100644
index 4d6586c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/tsigkeyring.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/ttl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/ttl.cpython-312.pyc
deleted file mode 100644
index 4db99ca..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/ttl.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/update.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/update.cpython-312.pyc
deleted file mode 100644
index 104c4ca..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/update.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/version.cpython-312.pyc
deleted file mode 100644
index 2b050e4..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/version.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/versioned.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/versioned.cpython-312.pyc
deleted file mode 100644
index 2f73cd0..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/versioned.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/win32util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/win32util.cpython-312.pyc
deleted file mode 100644
index 5e9b8cc..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/win32util.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/wire.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/wire.cpython-312.pyc
deleted file mode 100644
index 024793e..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/wire.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/xfr.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/xfr.cpython-312.pyc
deleted file mode 100644
index 74c8164..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/xfr.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/zone.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/zone.cpython-312.pyc
deleted file mode 100644
index 3891ae0..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/zone.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/zonefile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/zonefile.cpython-312.pyc
deleted file mode 100644
index 32a1556..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/zonefile.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/__pycache__/zonetypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/__pycache__/zonetypes.cpython-312.pyc
deleted file mode 100644
index 9ec3ed6..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/__pycache__/zonetypes.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/_asyncbackend.py b/.venv/lib/python3.12/site-packages/dns/_asyncbackend.py
deleted file mode 100644
index 49f14fe..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_asyncbackend.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# This is a nullcontext for both sync and async. 3.7 has a nullcontext,
-# but it is only for sync use.
-
-
-class NullContext:
- def __init__(self, enter_result=None):
- self.enter_result = enter_result
-
- def __enter__(self):
- return self.enter_result
-
- def __exit__(self, exc_type, exc_value, traceback):
- pass
-
- async def __aenter__(self):
- return self.enter_result
-
- async def __aexit__(self, exc_type, exc_value, traceback):
- pass
-
-
-# These are declared here so backends can import them without creating
-# circular dependencies with dns.asyncbackend.
-
-
-class Socket: # pragma: no cover
- async def close(self):
- pass
-
- async def getpeername(self):
- raise NotImplementedError
-
- async def getsockname(self):
- raise NotImplementedError
-
- async def getpeercert(self, timeout):
- raise NotImplementedError
-
- async def __aenter__(self):
- return self
-
- async def __aexit__(self, exc_type, exc_value, traceback):
- await self.close()
-
-
-class DatagramSocket(Socket): # pragma: no cover
- def __init__(self, family: int):
- self.family = family
-
- async def sendto(self, what, destination, timeout):
- raise NotImplementedError
-
- async def recvfrom(self, size, timeout):
- raise NotImplementedError
-
-
-class StreamSocket(Socket): # pragma: no cover
- async def sendall(self, what, timeout):
- raise NotImplementedError
-
- async def recv(self, size, timeout):
- raise NotImplementedError
-
-
-class NullTransport:
- async def connect_tcp(self, host, port, timeout, local_address):
- raise NotImplementedError
-
-
-class Backend: # pragma: no cover
- def name(self):
- return "unknown"
-
- async def make_socket(
- self,
- af,
- socktype,
- proto=0,
- source=None,
- destination=None,
- timeout=None,
- ssl_context=None,
- server_hostname=None,
- ):
- raise NotImplementedError
-
- def datagram_connection_required(self):
- return False
-
- async def sleep(self, interval):
- raise NotImplementedError
-
- def get_transport_class(self):
- raise NotImplementedError
-
- async def wait_for(self, awaitable, timeout):
- raise NotImplementedError
diff --git a/.venv/lib/python3.12/site-packages/dns/_asyncio_backend.py b/.venv/lib/python3.12/site-packages/dns/_asyncio_backend.py
deleted file mode 100644
index 9d9ed36..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_asyncio_backend.py
+++ /dev/null
@@ -1,275 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-"""asyncio library query support"""
-
-import asyncio
-import socket
-import sys
-
-import dns._asyncbackend
-import dns._features
-import dns.exception
-import dns.inet
-
-_is_win32 = sys.platform == "win32"
-
-
-def _get_running_loop():
- try:
- return asyncio.get_running_loop()
- except AttributeError: # pragma: no cover
- return asyncio.get_event_loop()
-
-
-class _DatagramProtocol:
- def __init__(self):
- self.transport = None
- self.recvfrom = None
-
- def connection_made(self, transport):
- self.transport = transport
-
- def datagram_received(self, data, addr):
- if self.recvfrom and not self.recvfrom.done():
- self.recvfrom.set_result((data, addr))
-
- def error_received(self, exc): # pragma: no cover
- if self.recvfrom and not self.recvfrom.done():
- self.recvfrom.set_exception(exc)
-
- def connection_lost(self, exc):
- if self.recvfrom and not self.recvfrom.done():
- if exc is None:
- # EOF we triggered. Is there a better way to do this?
- try:
- raise EOFError
- except EOFError as e:
- self.recvfrom.set_exception(e)
- else:
- self.recvfrom.set_exception(exc)
-
- def close(self):
- self.transport.close()
-
-
-async def _maybe_wait_for(awaitable, timeout):
- if timeout is not None:
- try:
- return await asyncio.wait_for(awaitable, timeout)
- except asyncio.TimeoutError:
- raise dns.exception.Timeout(timeout=timeout)
- else:
- return await awaitable
-
-
-class DatagramSocket(dns._asyncbackend.DatagramSocket):
- def __init__(self, family, transport, protocol):
- super().__init__(family)
- self.transport = transport
- self.protocol = protocol
-
- async def sendto(self, what, destination, timeout): # pragma: no cover
- # no timeout for asyncio sendto
- self.transport.sendto(what, destination)
- return len(what)
-
- async def recvfrom(self, size, timeout):
- # ignore size as there's no way I know to tell protocol about it
- done = _get_running_loop().create_future()
- try:
- assert self.protocol.recvfrom is None
- self.protocol.recvfrom = done
- await _maybe_wait_for(done, timeout)
- return done.result()
- finally:
- self.protocol.recvfrom = None
-
- async def close(self):
- self.protocol.close()
-
- async def getpeername(self):
- return self.transport.get_extra_info("peername")
-
- async def getsockname(self):
- return self.transport.get_extra_info("sockname")
-
- async def getpeercert(self, timeout):
- raise NotImplementedError
-
-
-class StreamSocket(dns._asyncbackend.StreamSocket):
- def __init__(self, af, reader, writer):
- self.family = af
- self.reader = reader
- self.writer = writer
-
- async def sendall(self, what, timeout):
- self.writer.write(what)
- return await _maybe_wait_for(self.writer.drain(), timeout)
-
- async def recv(self, size, timeout):
- return await _maybe_wait_for(self.reader.read(size), timeout)
-
- async def close(self):
- self.writer.close()
-
- async def getpeername(self):
- return self.writer.get_extra_info("peername")
-
- async def getsockname(self):
- return self.writer.get_extra_info("sockname")
-
- async def getpeercert(self, timeout):
- return self.writer.get_extra_info("peercert")
-
-
-if dns._features.have("doh"):
- import anyio
- import httpcore
- import httpcore._backends.anyio
- import httpx
-
- _CoreAsyncNetworkBackend = httpcore.AsyncNetworkBackend
- _CoreAnyIOStream = httpcore._backends.anyio.AnyIOStream
-
- from dns.query import _compute_times, _expiration_for_this_attempt, _remaining
-
- class _NetworkBackend(_CoreAsyncNetworkBackend):
- def __init__(self, resolver, local_port, bootstrap_address, family):
- super().__init__()
- self._local_port = local_port
- self._resolver = resolver
- self._bootstrap_address = bootstrap_address
- self._family = family
- if local_port != 0:
- raise NotImplementedError(
- "the asyncio transport for HTTPX cannot set the local port"
- )
-
- async def connect_tcp(
- self, host, port, timeout, local_address, socket_options=None
- ): # pylint: disable=signature-differs
- addresses = []
- _, expiration = _compute_times(timeout)
- if dns.inet.is_address(host):
- addresses.append(host)
- elif self._bootstrap_address is not None:
- addresses.append(self._bootstrap_address)
- else:
- timeout = _remaining(expiration)
- family = self._family
- if local_address:
- family = dns.inet.af_for_address(local_address)
- answers = await self._resolver.resolve_name(
- host, family=family, lifetime=timeout
- )
- addresses = answers.addresses()
- for address in addresses:
- try:
- attempt_expiration = _expiration_for_this_attempt(2.0, expiration)
- timeout = _remaining(attempt_expiration)
- with anyio.fail_after(timeout):
- stream = await anyio.connect_tcp(
- remote_host=address,
- remote_port=port,
- local_host=local_address,
- )
- return _CoreAnyIOStream(stream)
- except Exception:
- pass
- raise httpcore.ConnectError
-
- async def connect_unix_socket(
- self, path, timeout, socket_options=None
- ): # pylint: disable=signature-differs
- raise NotImplementedError
-
- async def sleep(self, seconds): # pylint: disable=signature-differs
- await anyio.sleep(seconds)
-
- class _HTTPTransport(httpx.AsyncHTTPTransport):
- def __init__(
- self,
- *args,
- local_port=0,
- bootstrap_address=None,
- resolver=None,
- family=socket.AF_UNSPEC,
- **kwargs,
- ):
- if resolver is None:
- # pylint: disable=import-outside-toplevel,redefined-outer-name
- import dns.asyncresolver
-
- resolver = dns.asyncresolver.Resolver()
- super().__init__(*args, **kwargs)
- self._pool._network_backend = _NetworkBackend(
- resolver, local_port, bootstrap_address, family
- )
-
-else:
- _HTTPTransport = dns._asyncbackend.NullTransport # type: ignore
-
-
-class Backend(dns._asyncbackend.Backend):
- def name(self):
- return "asyncio"
-
- async def make_socket(
- self,
- af,
- socktype,
- proto=0,
- source=None,
- destination=None,
- timeout=None,
- ssl_context=None,
- server_hostname=None,
- ):
- loop = _get_running_loop()
- if socktype == socket.SOCK_DGRAM:
- if _is_win32 and source is None:
- # Win32 wants explicit binding before recvfrom(). This is the
- # proper fix for [#637].
- source = (dns.inet.any_for_af(af), 0)
- transport, protocol = await loop.create_datagram_endpoint(
- _DatagramProtocol,
- source,
- family=af,
- proto=proto,
- remote_addr=destination,
- )
- return DatagramSocket(af, transport, protocol)
- elif socktype == socket.SOCK_STREAM:
- if destination is None:
- # This shouldn't happen, but we check to make code analysis software
- # happier.
- raise ValueError("destination required for stream sockets")
- (r, w) = await _maybe_wait_for(
- asyncio.open_connection(
- destination[0],
- destination[1],
- ssl=ssl_context,
- family=af,
- proto=proto,
- local_addr=source,
- server_hostname=server_hostname,
- ),
- timeout,
- )
- return StreamSocket(af, r, w)
- raise NotImplementedError(
- "unsupported socket " + f"type {socktype}"
- ) # pragma: no cover
-
- async def sleep(self, interval):
- await asyncio.sleep(interval)
-
- def datagram_connection_required(self):
- return False
-
- def get_transport_class(self):
- return _HTTPTransport
-
- async def wait_for(self, awaitable, timeout):
- return await _maybe_wait_for(awaitable, timeout)
diff --git a/.venv/lib/python3.12/site-packages/dns/_ddr.py b/.venv/lib/python3.12/site-packages/dns/_ddr.py
deleted file mode 100644
index bf5c11e..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_ddr.py
+++ /dev/null
@@ -1,154 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-#
-# Support for Discovery of Designated Resolvers
-
-import socket
-import time
-from urllib.parse import urlparse
-
-import dns.asyncbackend
-import dns.inet
-import dns.name
-import dns.nameserver
-import dns.query
-import dns.rdtypes.svcbbase
-
-# The special name of the local resolver when using DDR
-_local_resolver_name = dns.name.from_text("_dns.resolver.arpa")
-
-
-#
-# Processing is split up into I/O independent and I/O dependent parts to
-# make supporting sync and async versions easy.
-#
-
-
-class _SVCBInfo:
- def __init__(self, bootstrap_address, port, hostname, nameservers):
- self.bootstrap_address = bootstrap_address
- self.port = port
- self.hostname = hostname
- self.nameservers = nameservers
-
- def ddr_check_certificate(self, cert):
- """Verify that the _SVCBInfo's address is in the cert's subjectAltName (SAN)"""
- for name, value in cert["subjectAltName"]:
- if name == "IP Address" and value == self.bootstrap_address:
- return True
- return False
-
- def make_tls_context(self):
- ssl = dns.query.ssl
- ctx = ssl.create_default_context()
- ctx.minimum_version = ssl.TLSVersion.TLSv1_2
- return ctx
-
- def ddr_tls_check_sync(self, lifetime):
- ctx = self.make_tls_context()
- expiration = time.time() + lifetime
- with socket.create_connection(
- (self.bootstrap_address, self.port), lifetime
- ) as s:
- with ctx.wrap_socket(s, server_hostname=self.hostname) as ts:
- ts.settimeout(dns.query._remaining(expiration))
- ts.do_handshake()
- cert = ts.getpeercert()
- return self.ddr_check_certificate(cert)
-
- async def ddr_tls_check_async(self, lifetime, backend=None):
- if backend is None:
- backend = dns.asyncbackend.get_default_backend()
- ctx = self.make_tls_context()
- expiration = time.time() + lifetime
- async with await backend.make_socket(
- dns.inet.af_for_address(self.bootstrap_address),
- socket.SOCK_STREAM,
- 0,
- None,
- (self.bootstrap_address, self.port),
- lifetime,
- ctx,
- self.hostname,
- ) as ts:
- cert = await ts.getpeercert(dns.query._remaining(expiration))
- return self.ddr_check_certificate(cert)
-
-
-def _extract_nameservers_from_svcb(answer):
- bootstrap_address = answer.nameserver
- if not dns.inet.is_address(bootstrap_address):
- return []
- infos = []
- for rr in answer.rrset.processing_order():
- nameservers = []
- param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.ALPN)
- if param is None:
- continue
- alpns = set(param.ids)
- host = rr.target.to_text(omit_final_dot=True)
- port = None
- param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.PORT)
- if param is not None:
- port = param.port
- # For now we ignore address hints and address resolution and always use the
- # bootstrap address
- if b"h2" in alpns:
- param = rr.params.get(dns.rdtypes.svcbbase.ParamKey.DOHPATH)
- if param is None or not param.value.endswith(b"{?dns}"):
- continue
- path = param.value[:-6].decode()
- if not path.startswith("/"):
- path = "/" + path
- if port is None:
- port = 443
- url = f"https://{host}:{port}{path}"
- # check the URL
- try:
- urlparse(url)
- nameservers.append(dns.nameserver.DoHNameserver(url, bootstrap_address))
- except Exception:
- # continue processing other ALPN types
- pass
- if b"dot" in alpns:
- if port is None:
- port = 853
- nameservers.append(
- dns.nameserver.DoTNameserver(bootstrap_address, port, host)
- )
- if b"doq" in alpns:
- if port is None:
- port = 853
- nameservers.append(
- dns.nameserver.DoQNameserver(bootstrap_address, port, True, host)
- )
- if len(nameservers) > 0:
- infos.append(_SVCBInfo(bootstrap_address, port, host, nameservers))
- return infos
-
-
-def _get_nameservers_sync(answer, lifetime):
- """Return a list of TLS-validated resolver nameservers extracted from an SVCB
- answer."""
- nameservers = []
- infos = _extract_nameservers_from_svcb(answer)
- for info in infos:
- try:
- if info.ddr_tls_check_sync(lifetime):
- nameservers.extend(info.nameservers)
- except Exception:
- pass
- return nameservers
-
-
-async def _get_nameservers_async(answer, lifetime):
- """Return a list of TLS-validated resolver nameservers extracted from an SVCB
- answer."""
- nameservers = []
- infos = _extract_nameservers_from_svcb(answer)
- for info in infos:
- try:
- if await info.ddr_tls_check_async(lifetime):
- nameservers.extend(info.nameservers)
- except Exception:
- pass
- return nameservers
diff --git a/.venv/lib/python3.12/site-packages/dns/_features.py b/.venv/lib/python3.12/site-packages/dns/_features.py
deleted file mode 100644
index 03ccaa7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_features.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import importlib.metadata
-import itertools
-import string
-from typing import Dict, List, Tuple
-
-
-def _tuple_from_text(version: str) -> Tuple:
- text_parts = version.split(".")
- int_parts = []
- for text_part in text_parts:
- digit_prefix = "".join(
- itertools.takewhile(lambda x: x in string.digits, text_part)
- )
- try:
- int_parts.append(int(digit_prefix))
- except Exception:
- break
- return tuple(int_parts)
-
-
-def _version_check(
- requirement: str,
-) -> bool:
- """Is the requirement fulfilled?
-
- The requirement must be of the form
-
- package>=version
- """
- package, minimum = requirement.split(">=")
- try:
- version = importlib.metadata.version(package)
- except Exception:
- return False
- t_version = _tuple_from_text(version)
- t_minimum = _tuple_from_text(minimum)
- if t_version < t_minimum:
- return False
- return True
-
-
-_cache: Dict[str, bool] = {}
-
-
-def have(feature: str) -> bool:
- """Is *feature* available?
-
- This tests if all optional packages needed for the
- feature are available and recent enough.
-
- Returns ``True`` if the feature is available,
- and ``False`` if it is not or if metadata is
- missing.
- """
- value = _cache.get(feature)
- if value is not None:
- return value
- requirements = _requirements.get(feature)
- if requirements is None:
- # we make a cache entry here for consistency not performance
- _cache[feature] = False
- return False
- ok = True
- for requirement in requirements:
- if not _version_check(requirement):
- ok = False
- break
- _cache[feature] = ok
- return ok
-
-
-def force(feature: str, enabled: bool) -> None:
- """Force the status of *feature* to be *enabled*.
-
- This method is provided as a workaround for any cases
- where importlib.metadata is ineffective, or for testing.
- """
- _cache[feature] = enabled
-
-
-_requirements: Dict[str, List[str]] = {
- ### BEGIN generated requirements
- "dnssec": ["cryptography>=41"],
- "doh": ["httpcore>=1.0.0", "httpx>=0.26.0", "h2>=4.1.0"],
- "doq": ["aioquic>=0.9.25"],
- "idna": ["idna>=3.6"],
- "trio": ["trio>=0.23"],
- "wmi": ["wmi>=1.5.1"],
- ### END generated requirements
-}
diff --git a/.venv/lib/python3.12/site-packages/dns/_immutable_ctx.py b/.venv/lib/python3.12/site-packages/dns/_immutable_ctx.py
deleted file mode 100644
index ae7a33b..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_immutable_ctx.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# This implementation of the immutable decorator requires python >=
-# 3.7, and is significantly more storage efficient when making classes
-# with slots immutable. It's also faster.
-
-import contextvars
-import inspect
-
-_in__init__ = contextvars.ContextVar("_immutable_in__init__", default=False)
-
-
-class _Immutable:
- """Immutable mixin class"""
-
- # We set slots to the empty list to say "we don't have any attributes".
- # We do this so that if we're mixed in with a class with __slots__, we
- # don't cause a __dict__ to be added which would waste space.
-
- __slots__ = ()
-
- def __setattr__(self, name, value):
- if _in__init__.get() is not self:
- raise TypeError("object doesn't support attribute assignment")
- else:
- super().__setattr__(name, value)
-
- def __delattr__(self, name):
- if _in__init__.get() is not self:
- raise TypeError("object doesn't support attribute assignment")
- else:
- super().__delattr__(name)
-
-
-def _immutable_init(f):
- def nf(*args, **kwargs):
- previous = _in__init__.set(args[0])
- try:
- # call the actual __init__
- f(*args, **kwargs)
- finally:
- _in__init__.reset(previous)
-
- nf.__signature__ = inspect.signature(f)
- return nf
-
-
-def immutable(cls):
- if _Immutable in cls.__mro__:
- # Some ancestor already has the mixin, so just make sure we keep
- # following the __init__ protocol.
- cls.__init__ = _immutable_init(cls.__init__)
- if hasattr(cls, "__setstate__"):
- cls.__setstate__ = _immutable_init(cls.__setstate__)
- ncls = cls
- else:
- # Mixin the Immutable class and follow the __init__ protocol.
- class ncls(_Immutable, cls):
- # We have to do the __slots__ declaration here too!
- __slots__ = ()
-
- @_immutable_init
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- if hasattr(cls, "__setstate__"):
-
- @_immutable_init
- def __setstate__(self, *args, **kwargs):
- super().__setstate__(*args, **kwargs)
-
- # make ncls have the same name and module as cls
- ncls.__name__ = cls.__name__
- ncls.__qualname__ = cls.__qualname__
- ncls.__module__ = cls.__module__
- return ncls
diff --git a/.venv/lib/python3.12/site-packages/dns/_trio_backend.py b/.venv/lib/python3.12/site-packages/dns/_trio_backend.py
deleted file mode 100644
index 398e327..0000000
--- a/.venv/lib/python3.12/site-packages/dns/_trio_backend.py
+++ /dev/null
@@ -1,250 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-"""trio async I/O library query support"""
-
-import socket
-
-import trio
-import trio.socket # type: ignore
-
-import dns._asyncbackend
-import dns._features
-import dns.exception
-import dns.inet
-
-if not dns._features.have("trio"):
- raise ImportError("trio not found or too old")
-
-
-def _maybe_timeout(timeout):
- if timeout is not None:
- return trio.move_on_after(timeout)
- else:
- return dns._asyncbackend.NullContext()
-
-
-# for brevity
-_lltuple = dns.inet.low_level_address_tuple
-
-# pylint: disable=redefined-outer-name
-
-
-class DatagramSocket(dns._asyncbackend.DatagramSocket):
- def __init__(self, socket):
- super().__init__(socket.family)
- self.socket = socket
-
- async def sendto(self, what, destination, timeout):
- with _maybe_timeout(timeout):
- return await self.socket.sendto(what, destination)
- raise dns.exception.Timeout(
- timeout=timeout
- ) # pragma: no cover lgtm[py/unreachable-statement]
-
- async def recvfrom(self, size, timeout):
- with _maybe_timeout(timeout):
- return await self.socket.recvfrom(size)
- raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement]
-
- async def close(self):
- self.socket.close()
-
- async def getpeername(self):
- return self.socket.getpeername()
-
- async def getsockname(self):
- return self.socket.getsockname()
-
- async def getpeercert(self, timeout):
- raise NotImplementedError
-
-
-class StreamSocket(dns._asyncbackend.StreamSocket):
- def __init__(self, family, stream, tls=False):
- self.family = family
- self.stream = stream
- self.tls = tls
-
- async def sendall(self, what, timeout):
- with _maybe_timeout(timeout):
- return await self.stream.send_all(what)
- raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement]
-
- async def recv(self, size, timeout):
- with _maybe_timeout(timeout):
- return await self.stream.receive_some(size)
- raise dns.exception.Timeout(timeout=timeout) # lgtm[py/unreachable-statement]
-
- async def close(self):
- await self.stream.aclose()
-
- async def getpeername(self):
- if self.tls:
- return self.stream.transport_stream.socket.getpeername()
- else:
- return self.stream.socket.getpeername()
-
- async def getsockname(self):
- if self.tls:
- return self.stream.transport_stream.socket.getsockname()
- else:
- return self.stream.socket.getsockname()
-
- async def getpeercert(self, timeout):
- if self.tls:
- with _maybe_timeout(timeout):
- await self.stream.do_handshake()
- return self.stream.getpeercert()
- else:
- raise NotImplementedError
-
-
-if dns._features.have("doh"):
- import httpcore
- import httpcore._backends.trio
- import httpx
-
- _CoreAsyncNetworkBackend = httpcore.AsyncNetworkBackend
- _CoreTrioStream = httpcore._backends.trio.TrioStream
-
- from dns.query import _compute_times, _expiration_for_this_attempt, _remaining
-
- class _NetworkBackend(_CoreAsyncNetworkBackend):
- def __init__(self, resolver, local_port, bootstrap_address, family):
- super().__init__()
- self._local_port = local_port
- self._resolver = resolver
- self._bootstrap_address = bootstrap_address
- self._family = family
-
- async def connect_tcp(
- self, host, port, timeout, local_address, socket_options=None
- ): # pylint: disable=signature-differs
- addresses = []
- _, expiration = _compute_times(timeout)
- if dns.inet.is_address(host):
- addresses.append(host)
- elif self._bootstrap_address is not None:
- addresses.append(self._bootstrap_address)
- else:
- timeout = _remaining(expiration)
- family = self._family
- if local_address:
- family = dns.inet.af_for_address(local_address)
- answers = await self._resolver.resolve_name(
- host, family=family, lifetime=timeout
- )
- addresses = answers.addresses()
- for address in addresses:
- try:
- af = dns.inet.af_for_address(address)
- if local_address is not None or self._local_port != 0:
- source = (local_address, self._local_port)
- else:
- source = None
- destination = (address, port)
- attempt_expiration = _expiration_for_this_attempt(2.0, expiration)
- timeout = _remaining(attempt_expiration)
- sock = await Backend().make_socket(
- af, socket.SOCK_STREAM, 0, source, destination, timeout
- )
- return _CoreTrioStream(sock.stream)
- except Exception:
- continue
- raise httpcore.ConnectError
-
- async def connect_unix_socket(
- self, path, timeout, socket_options=None
- ): # pylint: disable=signature-differs
- raise NotImplementedError
-
- async def sleep(self, seconds): # pylint: disable=signature-differs
- await trio.sleep(seconds)
-
- class _HTTPTransport(httpx.AsyncHTTPTransport):
- def __init__(
- self,
- *args,
- local_port=0,
- bootstrap_address=None,
- resolver=None,
- family=socket.AF_UNSPEC,
- **kwargs,
- ):
- if resolver is None:
- # pylint: disable=import-outside-toplevel,redefined-outer-name
- import dns.asyncresolver
-
- resolver = dns.asyncresolver.Resolver()
- super().__init__(*args, **kwargs)
- self._pool._network_backend = _NetworkBackend(
- resolver, local_port, bootstrap_address, family
- )
-
-else:
- _HTTPTransport = dns._asyncbackend.NullTransport # type: ignore
-
-
-class Backend(dns._asyncbackend.Backend):
- def name(self):
- return "trio"
-
- async def make_socket(
- self,
- af,
- socktype,
- proto=0,
- source=None,
- destination=None,
- timeout=None,
- ssl_context=None,
- server_hostname=None,
- ):
- s = trio.socket.socket(af, socktype, proto)
- stream = None
- try:
- if source:
- await s.bind(_lltuple(source, af))
- if socktype == socket.SOCK_STREAM:
- connected = False
- with _maybe_timeout(timeout):
- await s.connect(_lltuple(destination, af))
- connected = True
- if not connected:
- raise dns.exception.Timeout(
- timeout=timeout
- ) # lgtm[py/unreachable-statement]
- except Exception: # pragma: no cover
- s.close()
- raise
- if socktype == socket.SOCK_DGRAM:
- return DatagramSocket(s)
- elif socktype == socket.SOCK_STREAM:
- stream = trio.SocketStream(s)
- tls = False
- if ssl_context:
- tls = True
- try:
- stream = trio.SSLStream(
- stream, ssl_context, server_hostname=server_hostname
- )
- except Exception: # pragma: no cover
- await stream.aclose()
- raise
- return StreamSocket(af, stream, tls)
- raise NotImplementedError(
- "unsupported socket " + f"type {socktype}"
- ) # pragma: no cover
-
- async def sleep(self, interval):
- await trio.sleep(interval)
-
- def get_transport_class(self):
- return _HTTPTransport
-
- async def wait_for(self, awaitable, timeout):
- with _maybe_timeout(timeout):
- return await awaitable
- raise dns.exception.Timeout(
- timeout=timeout
- ) # pragma: no cover lgtm[py/unreachable-statement]
diff --git a/.venv/lib/python3.12/site-packages/dns/asyncbackend.py b/.venv/lib/python3.12/site-packages/dns/asyncbackend.py
deleted file mode 100644
index 0ec58b0..0000000
--- a/.venv/lib/python3.12/site-packages/dns/asyncbackend.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-from typing import Dict
-
-import dns.exception
-
-# pylint: disable=unused-import
-from dns._asyncbackend import ( # noqa: F401 lgtm[py/unused-import]
- Backend,
- DatagramSocket,
- Socket,
- StreamSocket,
-)
-
-# pylint: enable=unused-import
-
-_default_backend = None
-
-_backends: Dict[str, Backend] = {}
-
-# Allow sniffio import to be disabled for testing purposes
-_no_sniffio = False
-
-
-class AsyncLibraryNotFoundError(dns.exception.DNSException):
- pass
-
-
-def get_backend(name: str) -> Backend:
- """Get the specified asynchronous backend.
-
- *name*, a ``str``, the name of the backend. Currently the "trio"
- and "asyncio" backends are available.
-
- Raises NotImplementedError if an unknown backend name is specified.
- """
- # pylint: disable=import-outside-toplevel,redefined-outer-name
- backend = _backends.get(name)
- if backend:
- return backend
- if name == "trio":
- import dns._trio_backend
-
- backend = dns._trio_backend.Backend()
- elif name == "asyncio":
- import dns._asyncio_backend
-
- backend = dns._asyncio_backend.Backend()
- else:
- raise NotImplementedError(f"unimplemented async backend {name}")
- _backends[name] = backend
- return backend
-
-
-def sniff() -> str:
- """Attempt to determine the in-use asynchronous I/O library by using
- the ``sniffio`` module if it is available.
-
- Returns the name of the library, or raises AsyncLibraryNotFoundError
- if the library cannot be determined.
- """
- # pylint: disable=import-outside-toplevel
- try:
- if _no_sniffio:
- raise ImportError
- import sniffio
-
- try:
- return sniffio.current_async_library()
- except sniffio.AsyncLibraryNotFoundError:
- raise AsyncLibraryNotFoundError("sniffio cannot determine async library")
- except ImportError:
- import asyncio
-
- try:
- asyncio.get_running_loop()
- return "asyncio"
- except RuntimeError:
- raise AsyncLibraryNotFoundError("no async library detected")
-
-
-def get_default_backend() -> Backend:
- """Get the default backend, initializing it if necessary."""
- if _default_backend:
- return _default_backend
-
- return set_default_backend(sniff())
-
-
-def set_default_backend(name: str) -> Backend:
- """Set the default backend.
-
- It's not normally necessary to call this method, as
- ``get_default_backend()`` will initialize the backend
- appropriately in many cases. If ``sniffio`` is not installed, or
- in testing situations, this function allows the backend to be set
- explicitly.
- """
- global _default_backend
- _default_backend = get_backend(name)
- return _default_backend
diff --git a/.venv/lib/python3.12/site-packages/dns/asyncquery.py b/.venv/lib/python3.12/site-packages/dns/asyncquery.py
deleted file mode 100644
index 4d9ab9a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/asyncquery.py
+++ /dev/null
@@ -1,780 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Talk to a DNS server."""
-
-import base64
-import contextlib
-import socket
-import struct
-import time
-from typing import Any, Dict, Optional, Tuple, Union
-
-import dns.asyncbackend
-import dns.exception
-import dns.inet
-import dns.message
-import dns.name
-import dns.quic
-import dns.rcode
-import dns.rdataclass
-import dns.rdatatype
-import dns.transaction
-from dns._asyncbackend import NullContext
-from dns.query import (
- BadResponse,
- NoDOH,
- NoDOQ,
- UDPMode,
- _compute_times,
- _make_dot_ssl_context,
- _matches_destination,
- _remaining,
- have_doh,
- ssl,
-)
-
-if have_doh:
- import httpx
-
-# for brevity
-_lltuple = dns.inet.low_level_address_tuple
-
-
-def _source_tuple(af, address, port):
- # Make a high level source tuple, or return None if address and port
- # are both None
- if address or port:
- if address is None:
- if af == socket.AF_INET:
- address = "0.0.0.0"
- elif af == socket.AF_INET6:
- address = "::"
- else:
- raise NotImplementedError(f"unknown address family {af}")
- return (address, port)
- else:
- return None
-
-
-def _timeout(expiration, now=None):
- if expiration is not None:
- if not now:
- now = time.time()
- return max(expiration - now, 0)
- else:
- return None
-
-
-async def send_udp(
- sock: dns.asyncbackend.DatagramSocket,
- what: Union[dns.message.Message, bytes],
- destination: Any,
- expiration: Optional[float] = None,
-) -> Tuple[int, float]:
- """Send a DNS message to the specified UDP socket.
-
- *sock*, a ``dns.asyncbackend.DatagramSocket``.
-
- *what*, a ``bytes`` or ``dns.message.Message``, the message to send.
-
- *destination*, a destination tuple appropriate for the address family
- of the socket, specifying where to send the query.
-
- *expiration*, a ``float`` or ``None``, the absolute time at which
- a timeout exception should be raised. If ``None``, no timeout will
- occur. The expiration value is meaningless for the asyncio backend, as
- asyncio's transport sendto() never blocks.
-
- Returns an ``(int, float)`` tuple of bytes sent and the sent time.
- """
-
- if isinstance(what, dns.message.Message):
- what = what.to_wire()
- sent_time = time.time()
- n = await sock.sendto(what, destination, _timeout(expiration, sent_time))
- return (n, sent_time)
-
-
-async def receive_udp(
- sock: dns.asyncbackend.DatagramSocket,
- destination: Optional[Any] = None,
- expiration: Optional[float] = None,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None,
- request_mac: Optional[bytes] = b"",
- ignore_trailing: bool = False,
- raise_on_truncation: bool = False,
- ignore_errors: bool = False,
- query: Optional[dns.message.Message] = None,
-) -> Any:
- """Read a DNS message from a UDP socket.
-
- *sock*, a ``dns.asyncbackend.DatagramSocket``.
-
- See :py:func:`dns.query.receive_udp()` for the documentation of the other
- parameters, and exceptions.
-
- Returns a ``(dns.message.Message, float, tuple)`` tuple of the received message, the
- received time, and the address where the message arrived from.
- """
-
- wire = b""
- while True:
- (wire, from_address) = await sock.recvfrom(65535, _timeout(expiration))
- if not _matches_destination(
- sock.family, from_address, destination, ignore_unexpected
- ):
- continue
- received_time = time.time()
- try:
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- raise_on_truncation=raise_on_truncation,
- )
- except dns.message.Truncated as e:
- # See the comment in query.py for details.
- if (
- ignore_errors
- and query is not None
- and not query.is_response(e.message())
- ):
- continue
- else:
- raise
- except Exception:
- if ignore_errors:
- continue
- else:
- raise
- if ignore_errors and query is not None and not query.is_response(r):
- continue
- return (r, received_time, from_address)
-
-
-async def udp(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- raise_on_truncation: bool = False,
- sock: Optional[dns.asyncbackend.DatagramSocket] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
- ignore_errors: bool = False,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via UDP.
-
- *sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``,
- the socket to use for the query. If ``None``, the default, a
- socket is created. Note that if a socket is provided, the
- *source*, *source_port*, and *backend* are ignored.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.udp()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
- wire = q.to_wire()
- (begin_time, expiration) = _compute_times(timeout)
- af = dns.inet.af_for_address(where)
- destination = _lltuple((where, port), af)
- if sock:
- cm: contextlib.AbstractAsyncContextManager = NullContext(sock)
- else:
- if not backend:
- backend = dns.asyncbackend.get_default_backend()
- stuple = _source_tuple(af, source, source_port)
- if backend.datagram_connection_required():
- dtuple = (where, port)
- else:
- dtuple = None
- cm = await backend.make_socket(af, socket.SOCK_DGRAM, 0, stuple, dtuple)
- async with cm as s:
- await send_udp(s, wire, destination, expiration)
- (r, received_time, _) = await receive_udp(
- s,
- destination,
- expiration,
- ignore_unexpected,
- one_rr_per_rrset,
- q.keyring,
- q.mac,
- ignore_trailing,
- raise_on_truncation,
- ignore_errors,
- q,
- )
- r.time = received_time - begin_time
- # We don't need to check q.is_response() if we are in ignore_errors mode
- # as receive_udp() will have checked it.
- if not (ignore_errors or q.is_response(r)):
- raise BadResponse
- return r
-
-
-async def udp_with_fallback(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- udp_sock: Optional[dns.asyncbackend.DatagramSocket] = None,
- tcp_sock: Optional[dns.asyncbackend.StreamSocket] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
- ignore_errors: bool = False,
-) -> Tuple[dns.message.Message, bool]:
- """Return the response to the query, trying UDP first and falling back
- to TCP if UDP results in a truncated response.
-
- *udp_sock*, a ``dns.asyncbackend.DatagramSocket``, or ``None``,
- the socket to use for the UDP query. If ``None``, the default, a
- socket is created. Note that if a socket is provided the *source*,
- *source_port*, and *backend* are ignored for the UDP query.
-
- *tcp_sock*, a ``dns.asyncbackend.StreamSocket``, or ``None``, the
- socket to use for the TCP query. If ``None``, the default, a
- socket is created. Note that if a socket is provided *where*,
- *source*, *source_port*, and *backend* are ignored for the TCP query.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.udp_with_fallback()` for the documentation
- of the other parameters, exceptions, and return type of this
- method.
- """
- try:
- response = await udp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- ignore_unexpected,
- one_rr_per_rrset,
- ignore_trailing,
- True,
- udp_sock,
- backend,
- ignore_errors,
- )
- return (response, False)
- except dns.message.Truncated:
- response = await tcp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- one_rr_per_rrset,
- ignore_trailing,
- tcp_sock,
- backend,
- )
- return (response, True)
-
-
-async def send_tcp(
- sock: dns.asyncbackend.StreamSocket,
- what: Union[dns.message.Message, bytes],
- expiration: Optional[float] = None,
-) -> Tuple[int, float]:
- """Send a DNS message to the specified TCP socket.
-
- *sock*, a ``dns.asyncbackend.StreamSocket``.
-
- See :py:func:`dns.query.send_tcp()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
-
- if isinstance(what, dns.message.Message):
- tcpmsg = what.to_wire(prepend_length=True)
- else:
- # copying the wire into tcpmsg is inefficient, but lets us
- # avoid writev() or doing a short write that would get pushed
- # onto the net
- tcpmsg = len(what).to_bytes(2, "big") + what
- sent_time = time.time()
- await sock.sendall(tcpmsg, _timeout(expiration, sent_time))
- return (len(tcpmsg), sent_time)
-
-
-async def _read_exactly(sock, count, expiration):
- """Read the specified number of bytes from stream. Keep trying until we
- either get the desired amount, or we hit EOF.
- """
- s = b""
- while count > 0:
- n = await sock.recv(count, _timeout(expiration))
- if n == b"":
- raise EOFError
- count = count - len(n)
- s = s + n
- return s
-
-
-async def receive_tcp(
- sock: dns.asyncbackend.StreamSocket,
- expiration: Optional[float] = None,
- one_rr_per_rrset: bool = False,
- keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None,
- request_mac: Optional[bytes] = b"",
- ignore_trailing: bool = False,
-) -> Tuple[dns.message.Message, float]:
- """Read a DNS message from a TCP socket.
-
- *sock*, a ``dns.asyncbackend.StreamSocket``.
-
- See :py:func:`dns.query.receive_tcp()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
-
- ldata = await _read_exactly(sock, 2, expiration)
- (l,) = struct.unpack("!H", ldata)
- wire = await _read_exactly(sock, l, expiration)
- received_time = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- return (r, received_time)
-
-
-async def tcp(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- sock: Optional[dns.asyncbackend.StreamSocket] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via TCP.
-
- *sock*, a ``dns.asyncbacket.StreamSocket``, or ``None``, the
- socket to use for the query. If ``None``, the default, a socket
- is created. Note that if a socket is provided
- *where*, *port*, *source*, *source_port*, and *backend* are ignored.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.tcp()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
-
- wire = q.to_wire()
- (begin_time, expiration) = _compute_times(timeout)
- if sock:
- # Verify that the socket is connected, as if it's not connected,
- # it's not writable, and the polling in send_tcp() will time out or
- # hang forever.
- await sock.getpeername()
- cm: contextlib.AbstractAsyncContextManager = NullContext(sock)
- else:
- # These are simple (address, port) pairs, not family-dependent tuples
- # you pass to low-level socket code.
- af = dns.inet.af_for_address(where)
- stuple = _source_tuple(af, source, source_port)
- dtuple = (where, port)
- if not backend:
- backend = dns.asyncbackend.get_default_backend()
- cm = await backend.make_socket(
- af, socket.SOCK_STREAM, 0, stuple, dtuple, timeout
- )
- async with cm as s:
- await send_tcp(s, wire, expiration)
- (r, received_time) = await receive_tcp(
- s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing
- )
- r.time = received_time - begin_time
- if not q.is_response(r):
- raise BadResponse
- return r
-
-
-async def tls(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 853,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- sock: Optional[dns.asyncbackend.StreamSocket] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
- ssl_context: Optional[ssl.SSLContext] = None,
- server_hostname: Optional[str] = None,
- verify: Union[bool, str] = True,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via TLS.
-
- *sock*, an ``asyncbackend.StreamSocket``, or ``None``, the socket
- to use for the query. If ``None``, the default, a socket is
- created. Note that if a socket is provided, it must be a
- connected SSL stream socket, and *where*, *port*,
- *source*, *source_port*, *backend*, *ssl_context*, and *server_hostname*
- are ignored.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.tls()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
- (begin_time, expiration) = _compute_times(timeout)
- if sock:
- cm: contextlib.AbstractAsyncContextManager = NullContext(sock)
- else:
- if ssl_context is None:
- ssl_context = _make_dot_ssl_context(server_hostname, verify)
- af = dns.inet.af_for_address(where)
- stuple = _source_tuple(af, source, source_port)
- dtuple = (where, port)
- if not backend:
- backend = dns.asyncbackend.get_default_backend()
- cm = await backend.make_socket(
- af,
- socket.SOCK_STREAM,
- 0,
- stuple,
- dtuple,
- timeout,
- ssl_context,
- server_hostname,
- )
- async with cm as s:
- timeout = _timeout(expiration)
- response = await tcp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- one_rr_per_rrset,
- ignore_trailing,
- s,
- backend,
- )
- end_time = time.time()
- response.time = end_time - begin_time
- return response
-
-
-async def https(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 443,
- source: Optional[str] = None,
- source_port: int = 0, # pylint: disable=W0613
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- client: Optional["httpx.AsyncClient"] = None,
- path: str = "/dns-query",
- post: bool = True,
- verify: Union[bool, str] = True,
- bootstrap_address: Optional[str] = None,
- resolver: Optional["dns.asyncresolver.Resolver"] = None,
- family: Optional[int] = socket.AF_UNSPEC,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via DNS-over-HTTPS.
-
- *client*, a ``httpx.AsyncClient``. If provided, the client to use for
- the query.
-
- Unlike the other dnspython async functions, a backend cannot be provided
- in this function because httpx always auto-detects the async backend.
-
- See :py:func:`dns.query.https()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
-
- if not have_doh:
- raise NoDOH # pragma: no cover
- if client and not isinstance(client, httpx.AsyncClient):
- raise ValueError("session parameter must be an httpx.AsyncClient")
-
- wire = q.to_wire()
- try:
- af = dns.inet.af_for_address(where)
- except ValueError:
- af = None
- transport = None
- headers = {"accept": "application/dns-message"}
- if af is not None and dns.inet.is_address(where):
- if af == socket.AF_INET:
- url = "https://{}:{}{}".format(where, port, path)
- elif af == socket.AF_INET6:
- url = "https://[{}]:{}{}".format(where, port, path)
- else:
- url = where
-
- backend = dns.asyncbackend.get_default_backend()
-
- if source is None:
- local_address = None
- local_port = 0
- else:
- local_address = source
- local_port = source_port
- transport = backend.get_transport_class()(
- local_address=local_address,
- http1=True,
- http2=True,
- verify=verify,
- local_port=local_port,
- bootstrap_address=bootstrap_address,
- resolver=resolver,
- family=family,
- )
-
- if client:
- cm: contextlib.AbstractAsyncContextManager = NullContext(client)
- else:
- cm = httpx.AsyncClient(
- http1=True, http2=True, verify=verify, transport=transport
- )
-
- async with cm as the_client:
- # see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH
- # GET and POST examples
- if post:
- headers.update(
- {
- "content-type": "application/dns-message",
- "content-length": str(len(wire)),
- }
- )
- response = await backend.wait_for(
- the_client.post(url, headers=headers, content=wire), timeout
- )
- else:
- wire = base64.urlsafe_b64encode(wire).rstrip(b"=")
- twire = wire.decode() # httpx does a repr() if we give it bytes
- response = await backend.wait_for(
- the_client.get(url, headers=headers, params={"dns": twire}), timeout
- )
-
- # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH
- # status codes
- if response.status_code < 200 or response.status_code > 299:
- raise ValueError(
- "{} responded with status code {}"
- "\nResponse body: {!r}".format(
- where, response.status_code, response.content
- )
- )
- r = dns.message.from_wire(
- response.content,
- keyring=q.keyring,
- request_mac=q.request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- r.time = response.elapsed.total_seconds()
- if not q.is_response(r):
- raise BadResponse
- return r
-
-
-async def inbound_xfr(
- where: str,
- txn_manager: dns.transaction.TransactionManager,
- query: Optional[dns.message.Message] = None,
- port: int = 53,
- timeout: Optional[float] = None,
- lifetime: Optional[float] = None,
- source: Optional[str] = None,
- source_port: int = 0,
- udp_mode: UDPMode = UDPMode.NEVER,
- backend: Optional[dns.asyncbackend.Backend] = None,
-) -> None:
- """Conduct an inbound transfer and apply it via a transaction from the
- txn_manager.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.inbound_xfr()` for the documentation of
- the other parameters, exceptions, and return type of this method.
- """
- if query is None:
- (query, serial) = dns.xfr.make_query(txn_manager)
- else:
- serial = dns.xfr.extract_serial_from_query(query)
- rdtype = query.question[0].rdtype
- is_ixfr = rdtype == dns.rdatatype.IXFR
- origin = txn_manager.from_wire_origin()
- wire = query.to_wire()
- af = dns.inet.af_for_address(where)
- stuple = _source_tuple(af, source, source_port)
- dtuple = (where, port)
- (_, expiration) = _compute_times(lifetime)
- retry = True
- while retry:
- retry = False
- if is_ixfr and udp_mode != UDPMode.NEVER:
- sock_type = socket.SOCK_DGRAM
- is_udp = True
- else:
- sock_type = socket.SOCK_STREAM
- is_udp = False
- if not backend:
- backend = dns.asyncbackend.get_default_backend()
- s = await backend.make_socket(
- af, sock_type, 0, stuple, dtuple, _timeout(expiration)
- )
- async with s:
- if is_udp:
- await s.sendto(wire, dtuple, _timeout(expiration))
- else:
- tcpmsg = struct.pack("!H", len(wire)) + wire
- await s.sendall(tcpmsg, expiration)
- with dns.xfr.Inbound(txn_manager, rdtype, serial, is_udp) as inbound:
- done = False
- tsig_ctx = None
- while not done:
- (_, mexpiration) = _compute_times(timeout)
- if mexpiration is None or (
- expiration is not None and mexpiration > expiration
- ):
- mexpiration = expiration
- if is_udp:
- destination = _lltuple((where, port), af)
- while True:
- timeout = _timeout(mexpiration)
- (rwire, from_address) = await s.recvfrom(65535, timeout)
- if _matches_destination(
- af, from_address, destination, True
- ):
- break
- else:
- ldata = await _read_exactly(s, 2, mexpiration)
- (l,) = struct.unpack("!H", ldata)
- rwire = await _read_exactly(s, l, mexpiration)
- is_ixfr = rdtype == dns.rdatatype.IXFR
- r = dns.message.from_wire(
- rwire,
- keyring=query.keyring,
- request_mac=query.mac,
- xfr=True,
- origin=origin,
- tsig_ctx=tsig_ctx,
- multi=(not is_udp),
- one_rr_per_rrset=is_ixfr,
- )
- try:
- done = inbound.process_message(r)
- except dns.xfr.UseTCP:
- assert is_udp # should not happen if we used TCP!
- if udp_mode == UDPMode.ONLY:
- raise
- done = True
- retry = True
- udp_mode = UDPMode.NEVER
- continue
- tsig_ctx = r.tsig_ctx
- if not retry and query.keyring and not r.had_tsig:
- raise dns.exception.FormError("missing TSIG")
-
-
-async def quic(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 853,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- connection: Optional[dns.quic.AsyncQuicConnection] = None,
- verify: Union[bool, str] = True,
- backend: Optional[dns.asyncbackend.Backend] = None,
- server_hostname: Optional[str] = None,
-) -> dns.message.Message:
- """Return the response obtained after sending an asynchronous query via
- DNS-over-QUIC.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.query.quic()` for the documentation of the other
- parameters, exceptions, and return type of this method.
- """
-
- if not dns.quic.have_quic:
- raise NoDOQ("DNS-over-QUIC is not available.") # pragma: no cover
-
- q.id = 0
- wire = q.to_wire()
- the_connection: dns.quic.AsyncQuicConnection
- if connection:
- cfactory = dns.quic.null_factory
- mfactory = dns.quic.null_factory
- the_connection = connection
- else:
- (cfactory, mfactory) = dns.quic.factories_for_backend(backend)
-
- async with cfactory() as context:
- async with mfactory(
- context, verify_mode=verify, server_name=server_hostname
- ) as the_manager:
- if not connection:
- the_connection = the_manager.connect(where, port, source, source_port)
- (start, expiration) = _compute_times(timeout)
- stream = await the_connection.make_stream(timeout)
- async with stream:
- await stream.send(wire, True)
- wire = await stream.receive(_remaining(expiration))
- finish = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=q.keyring,
- request_mac=q.request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- r.time = max(finish - start, 0.0)
- if not q.is_response(r):
- raise BadResponse
- return r
diff --git a/.venv/lib/python3.12/site-packages/dns/asyncresolver.py b/.venv/lib/python3.12/site-packages/dns/asyncresolver.py
deleted file mode 100644
index 8f5e062..0000000
--- a/.venv/lib/python3.12/site-packages/dns/asyncresolver.py
+++ /dev/null
@@ -1,475 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Asynchronous DNS stub resolver."""
-
-import socket
-import time
-from typing import Any, Dict, List, Optional, Union
-
-import dns._ddr
-import dns.asyncbackend
-import dns.asyncquery
-import dns.exception
-import dns.name
-import dns.query
-import dns.rdataclass
-import dns.rdatatype
-import dns.resolver # lgtm[py/import-and-import-from]
-
-# import some resolver symbols for brevity
-from dns.resolver import NXDOMAIN, NoAnswer, NoRootSOA, NotAbsolute
-
-# for indentation purposes below
-_udp = dns.asyncquery.udp
-_tcp = dns.asyncquery.tcp
-
-
-class Resolver(dns.resolver.BaseResolver):
- """Asynchronous DNS stub resolver."""
-
- async def resolve(
- self,
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
- ) -> dns.resolver.Answer:
- """Query nameservers asynchronously to find the answer to the question.
-
- *backend*, a ``dns.asyncbackend.Backend``, or ``None``. If ``None``,
- the default, then dnspython will use the default backend.
-
- See :py:func:`dns.resolver.Resolver.resolve()` for the
- documentation of the other parameters, exceptions, and return
- type of this method.
- """
-
- resolution = dns.resolver._Resolution(
- self, qname, rdtype, rdclass, tcp, raise_on_no_answer, search
- )
- if not backend:
- backend = dns.asyncbackend.get_default_backend()
- start = time.time()
- while True:
- (request, answer) = resolution.next_request()
- # Note we need to say "if answer is not None" and not just
- # "if answer" because answer implements __len__, and python
- # will call that. We want to return if we have an answer
- # object, including in cases where its length is 0.
- if answer is not None:
- # cache hit!
- return answer
- assert request is not None # needed for type checking
- done = False
- while not done:
- (nameserver, tcp, backoff) = resolution.next_nameserver()
- if backoff:
- await backend.sleep(backoff)
- timeout = self._compute_timeout(start, lifetime, resolution.errors)
- try:
- response = await nameserver.async_query(
- request,
- timeout=timeout,
- source=source,
- source_port=source_port,
- max_size=tcp,
- backend=backend,
- )
- except Exception as ex:
- (_, done) = resolution.query_result(None, ex)
- continue
- (answer, done) = resolution.query_result(response, None)
- # Note we need to say "if answer is not None" and not just
- # "if answer" because answer implements __len__, and python
- # will call that. We want to return if we have an answer
- # object, including in cases where its length is 0.
- if answer is not None:
- return answer
-
- async def resolve_address(
- self, ipaddr: str, *args: Any, **kwargs: Any
- ) -> dns.resolver.Answer:
- """Use an asynchronous resolver to run a reverse query for PTR
- records.
-
- This utilizes the resolve() method to perform a PTR lookup on the
- specified IP address.
-
- *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get
- the PTR record for.
-
- All other arguments that can be passed to the resolve() function
- except for rdtype and rdclass are also supported by this
- function.
-
- """
- # We make a modified kwargs for type checking happiness, as otherwise
- # we get a legit warning about possibly having rdtype and rdclass
- # in the kwargs more than once.
- modified_kwargs: Dict[str, Any] = {}
- modified_kwargs.update(kwargs)
- modified_kwargs["rdtype"] = dns.rdatatype.PTR
- modified_kwargs["rdclass"] = dns.rdataclass.IN
- return await self.resolve(
- dns.reversename.from_address(ipaddr), *args, **modified_kwargs
- )
-
- async def resolve_name(
- self,
- name: Union[dns.name.Name, str],
- family: int = socket.AF_UNSPEC,
- **kwargs: Any,
- ) -> dns.resolver.HostAnswers:
- """Use an asynchronous resolver to query for address records.
-
- This utilizes the resolve() method to perform A and/or AAAA lookups on
- the specified name.
-
- *qname*, a ``dns.name.Name`` or ``str``, the name to resolve.
-
- *family*, an ``int``, the address family. If socket.AF_UNSPEC
- (the default), both A and AAAA records will be retrieved.
-
- All other arguments that can be passed to the resolve() function
- except for rdtype and rdclass are also supported by this
- function.
- """
- # We make a modified kwargs for type checking happiness, as otherwise
- # we get a legit warning about possibly having rdtype and rdclass
- # in the kwargs more than once.
- modified_kwargs: Dict[str, Any] = {}
- modified_kwargs.update(kwargs)
- modified_kwargs.pop("rdtype", None)
- modified_kwargs["rdclass"] = dns.rdataclass.IN
-
- if family == socket.AF_INET:
- v4 = await self.resolve(name, dns.rdatatype.A, **modified_kwargs)
- return dns.resolver.HostAnswers.make(v4=v4)
- elif family == socket.AF_INET6:
- v6 = await self.resolve(name, dns.rdatatype.AAAA, **modified_kwargs)
- return dns.resolver.HostAnswers.make(v6=v6)
- elif family != socket.AF_UNSPEC:
- raise NotImplementedError(f"unknown address family {family}")
-
- raise_on_no_answer = modified_kwargs.pop("raise_on_no_answer", True)
- lifetime = modified_kwargs.pop("lifetime", None)
- start = time.time()
- v6 = await self.resolve(
- name,
- dns.rdatatype.AAAA,
- raise_on_no_answer=False,
- lifetime=self._compute_timeout(start, lifetime),
- **modified_kwargs,
- )
- # Note that setting name ensures we query the same name
- # for A as we did for AAAA. (This is just in case search lists
- # are active by default in the resolver configuration and
- # we might be talking to a server that says NXDOMAIN when it
- # wants to say NOERROR no data.
- name = v6.qname
- v4 = await self.resolve(
- name,
- dns.rdatatype.A,
- raise_on_no_answer=False,
- lifetime=self._compute_timeout(start, lifetime),
- **modified_kwargs,
- )
- answers = dns.resolver.HostAnswers.make(
- v6=v6, v4=v4, add_empty=not raise_on_no_answer
- )
- if not answers:
- raise NoAnswer(response=v6.response)
- return answers
-
- # pylint: disable=redefined-outer-name
-
- async def canonical_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name:
- """Determine the canonical name of *name*.
-
- The canonical name is the name the resolver uses for queries
- after all CNAME and DNAME renamings have been applied.
-
- *name*, a ``dns.name.Name`` or ``str``, the query name.
-
- This method can raise any exception that ``resolve()`` can
- raise, other than ``dns.resolver.NoAnswer`` and
- ``dns.resolver.NXDOMAIN``.
-
- Returns a ``dns.name.Name``.
- """
- try:
- answer = await self.resolve(name, raise_on_no_answer=False)
- canonical_name = answer.canonical_name
- except dns.resolver.NXDOMAIN as e:
- canonical_name = e.canonical_name
- return canonical_name
-
- async def try_ddr(self, lifetime: float = 5.0) -> None:
- """Try to update the resolver's nameservers using Discovery of Designated
- Resolvers (DDR). If successful, the resolver will subsequently use
- DNS-over-HTTPS or DNS-over-TLS for future queries.
-
- *lifetime*, a float, is the maximum time to spend attempting DDR. The default
- is 5 seconds.
-
- If the SVCB query is successful and results in a non-empty list of nameservers,
- then the resolver's nameservers are set to the returned servers in priority
- order.
-
- The current implementation does not use any address hints from the SVCB record,
- nor does it resolve addresses for the SCVB target name, rather it assumes that
- the bootstrap nameserver will always be one of the addresses and uses it.
- A future revision to the code may offer fuller support. The code verifies that
- the bootstrap nameserver is in the Subject Alternative Name field of the
- TLS certficate.
- """
- try:
- expiration = time.time() + lifetime
- answer = await self.resolve(
- dns._ddr._local_resolver_name, "svcb", lifetime=lifetime
- )
- timeout = dns.query._remaining(expiration)
- nameservers = await dns._ddr._get_nameservers_async(answer, timeout)
- if len(nameservers) > 0:
- self.nameservers = nameservers
- except Exception:
- pass
-
-
-default_resolver = None
-
-
-def get_default_resolver() -> Resolver:
- """Get the default asynchronous resolver, initializing it if necessary."""
- if default_resolver is None:
- reset_default_resolver()
- assert default_resolver is not None
- return default_resolver
-
-
-def reset_default_resolver() -> None:
- """Re-initialize default asynchronous resolver.
-
- Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX
- systems) will be re-read immediately.
- """
-
- global default_resolver
- default_resolver = Resolver()
-
-
-async def resolve(
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
-) -> dns.resolver.Answer:
- """Query nameservers asynchronously to find the answer to the question.
-
- This is a convenience function that uses the default resolver
- object to make the query.
-
- See :py:func:`dns.asyncresolver.Resolver.resolve` for more
- information on the parameters.
- """
-
- return await get_default_resolver().resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- search,
- backend,
- )
-
-
-async def resolve_address(
- ipaddr: str, *args: Any, **kwargs: Any
-) -> dns.resolver.Answer:
- """Use a resolver to run a reverse query for PTR records.
-
- See :py:func:`dns.asyncresolver.Resolver.resolve_address` for more
- information on the parameters.
- """
-
- return await get_default_resolver().resolve_address(ipaddr, *args, **kwargs)
-
-
-async def resolve_name(
- name: Union[dns.name.Name, str], family: int = socket.AF_UNSPEC, **kwargs: Any
-) -> dns.resolver.HostAnswers:
- """Use a resolver to asynchronously query for address records.
-
- See :py:func:`dns.asyncresolver.Resolver.resolve_name` for more
- information on the parameters.
- """
-
- return await get_default_resolver().resolve_name(name, family, **kwargs)
-
-
-async def canonical_name(name: Union[dns.name.Name, str]) -> dns.name.Name:
- """Determine the canonical name of *name*.
-
- See :py:func:`dns.resolver.Resolver.canonical_name` for more
- information on the parameters and possible exceptions.
- """
-
- return await get_default_resolver().canonical_name(name)
-
-
-async def try_ddr(timeout: float = 5.0) -> None:
- """Try to update the default resolver's nameservers using Discovery of Designated
- Resolvers (DDR). If successful, the resolver will subsequently use
- DNS-over-HTTPS or DNS-over-TLS for future queries.
-
- See :py:func:`dns.resolver.Resolver.try_ddr` for more information.
- """
- return await get_default_resolver().try_ddr(timeout)
-
-
-async def zone_for_name(
- name: Union[dns.name.Name, str],
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- tcp: bool = False,
- resolver: Optional[Resolver] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
-) -> dns.name.Name:
- """Find the name of the zone which contains the specified name.
-
- See :py:func:`dns.resolver.Resolver.zone_for_name` for more
- information on the parameters and possible exceptions.
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, dns.name.root)
- if resolver is None:
- resolver = get_default_resolver()
- if not name.is_absolute():
- raise NotAbsolute(name)
- while True:
- try:
- answer = await resolver.resolve(
- name, dns.rdatatype.SOA, rdclass, tcp, backend=backend
- )
- assert answer.rrset is not None
- if answer.rrset.name == name:
- return name
- # otherwise we were CNAMEd or DNAMEd and need to look higher
- except (NXDOMAIN, NoAnswer):
- pass
- try:
- name = name.parent()
- except dns.name.NoParent: # pragma: no cover
- raise NoRootSOA
-
-
-async def make_resolver_at(
- where: Union[dns.name.Name, str],
- port: int = 53,
- family: int = socket.AF_UNSPEC,
- resolver: Optional[Resolver] = None,
-) -> Resolver:
- """Make a stub resolver using the specified destination as the full resolver.
-
- *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the
- full resolver.
-
- *port*, an ``int``, the port to use. If not specified, the default is 53.
-
- *family*, an ``int``, the address family to use. This parameter is used if
- *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case
- the first address returned by ``resolve_name()`` will be used, otherwise the
- first address of the specified family will be used.
-
- *resolver*, a ``dns.asyncresolver.Resolver`` or ``None``, the resolver to use for
- resolution of hostnames. If not specified, the default resolver will be used.
-
- Returns a ``dns.resolver.Resolver`` or raises an exception.
- """
- if resolver is None:
- resolver = get_default_resolver()
- nameservers: List[Union[str, dns.nameserver.Nameserver]] = []
- if isinstance(where, str) and dns.inet.is_address(where):
- nameservers.append(dns.nameserver.Do53Nameserver(where, port))
- else:
- answers = await resolver.resolve_name(where, family)
- for address in answers.addresses():
- nameservers.append(dns.nameserver.Do53Nameserver(address, port))
- res = dns.asyncresolver.Resolver(configure=False)
- res.nameservers = nameservers
- return res
-
-
-async def resolve_at(
- where: Union[dns.name.Name, str],
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
- backend: Optional[dns.asyncbackend.Backend] = None,
- port: int = 53,
- family: int = socket.AF_UNSPEC,
- resolver: Optional[Resolver] = None,
-) -> dns.resolver.Answer:
- """Query nameservers to find the answer to the question.
-
- This is a convenience function that calls ``dns.asyncresolver.make_resolver_at()``
- to make a resolver, and then uses it to resolve the query.
-
- See ``dns.asyncresolver.Resolver.resolve`` for more information on the resolution
- parameters, and ``dns.asyncresolver.make_resolver_at`` for information about the
- resolver parameters *where*, *port*, *family*, and *resolver*.
-
- If making more than one query, it is more efficient to call
- ``dns.asyncresolver.make_resolver_at()`` and then use that resolver for the queries
- instead of calling ``resolve_at()`` multiple times.
- """
- res = await make_resolver_at(where, port, family, resolver)
- return await res.resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- search,
- backend,
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssec.py b/.venv/lib/python3.12/site-packages/dns/dnssec.py
deleted file mode 100644
index e49c3b7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssec.py
+++ /dev/null
@@ -1,1223 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Common DNSSEC-related functions and constants."""
-
-
-import base64
-import contextlib
-import functools
-import hashlib
-import struct
-import time
-from datetime import datetime
-from typing import Callable, Dict, List, Optional, Set, Tuple, Union, cast
-
-import dns._features
-import dns.exception
-import dns.name
-import dns.node
-import dns.rdata
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.rrset
-import dns.transaction
-import dns.zone
-from dns.dnssectypes import Algorithm, DSDigest, NSEC3Hash
-from dns.exception import ( # pylint: disable=W0611
- AlgorithmKeyMismatch,
- DeniedByPolicy,
- UnsupportedAlgorithm,
- ValidationFailure,
-)
-from dns.rdtypes.ANY.CDNSKEY import CDNSKEY
-from dns.rdtypes.ANY.CDS import CDS
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-from dns.rdtypes.ANY.DS import DS
-from dns.rdtypes.ANY.NSEC import NSEC, Bitmap
-from dns.rdtypes.ANY.NSEC3PARAM import NSEC3PARAM
-from dns.rdtypes.ANY.RRSIG import RRSIG, sigtime_to_posixtime
-from dns.rdtypes.dnskeybase import Flag
-
-PublicKey = Union[
- "GenericPublicKey",
- "rsa.RSAPublicKey",
- "ec.EllipticCurvePublicKey",
- "ed25519.Ed25519PublicKey",
- "ed448.Ed448PublicKey",
-]
-
-PrivateKey = Union[
- "GenericPrivateKey",
- "rsa.RSAPrivateKey",
- "ec.EllipticCurvePrivateKey",
- "ed25519.Ed25519PrivateKey",
- "ed448.Ed448PrivateKey",
-]
-
-RRsetSigner = Callable[[dns.transaction.Transaction, dns.rrset.RRset], None]
-
-
-def algorithm_from_text(text: str) -> Algorithm:
- """Convert text into a DNSSEC algorithm value.
-
- *text*, a ``str``, the text to convert to into an algorithm value.
-
- Returns an ``int``.
- """
-
- return Algorithm.from_text(text)
-
-
-def algorithm_to_text(value: Union[Algorithm, int]) -> str:
- """Convert a DNSSEC algorithm value to text
-
- *value*, a ``dns.dnssec.Algorithm``.
-
- Returns a ``str``, the name of a DNSSEC algorithm.
- """
-
- return Algorithm.to_text(value)
-
-
-def to_timestamp(value: Union[datetime, str, float, int]) -> int:
- """Convert various format to a timestamp"""
- if isinstance(value, datetime):
- return int(value.timestamp())
- elif isinstance(value, str):
- return sigtime_to_posixtime(value)
- elif isinstance(value, float):
- return int(value)
- elif isinstance(value, int):
- return value
- else:
- raise TypeError("Unsupported timestamp type")
-
-
-def key_id(key: Union[DNSKEY, CDNSKEY]) -> int:
- """Return the key id (a 16-bit number) for the specified key.
-
- *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY``
-
- Returns an ``int`` between 0 and 65535
- """
-
- rdata = key.to_wire()
- if key.algorithm == Algorithm.RSAMD5:
- return (rdata[-3] << 8) + rdata[-2]
- else:
- total = 0
- for i in range(len(rdata) // 2):
- total += (rdata[2 * i] << 8) + rdata[2 * i + 1]
- if len(rdata) % 2 != 0:
- total += rdata[len(rdata) - 1] << 8
- total += (total >> 16) & 0xFFFF
- return total & 0xFFFF
-
-
-class Policy:
- def __init__(self):
- pass
-
- def ok_to_sign(self, _: DNSKEY) -> bool: # pragma: no cover
- return False
-
- def ok_to_validate(self, _: DNSKEY) -> bool: # pragma: no cover
- return False
-
- def ok_to_create_ds(self, _: DSDigest) -> bool: # pragma: no cover
- return False
-
- def ok_to_validate_ds(self, _: DSDigest) -> bool: # pragma: no cover
- return False
-
-
-class SimpleDeny(Policy):
- def __init__(self, deny_sign, deny_validate, deny_create_ds, deny_validate_ds):
- super().__init__()
- self._deny_sign = deny_sign
- self._deny_validate = deny_validate
- self._deny_create_ds = deny_create_ds
- self._deny_validate_ds = deny_validate_ds
-
- def ok_to_sign(self, key: DNSKEY) -> bool:
- return key.algorithm not in self._deny_sign
-
- def ok_to_validate(self, key: DNSKEY) -> bool:
- return key.algorithm not in self._deny_validate
-
- def ok_to_create_ds(self, algorithm: DSDigest) -> bool:
- return algorithm not in self._deny_create_ds
-
- def ok_to_validate_ds(self, algorithm: DSDigest) -> bool:
- return algorithm not in self._deny_validate_ds
-
-
-rfc_8624_policy = SimpleDeny(
- {Algorithm.RSAMD5, Algorithm.DSA, Algorithm.DSANSEC3SHA1, Algorithm.ECCGOST},
- {Algorithm.RSAMD5, Algorithm.DSA, Algorithm.DSANSEC3SHA1},
- {DSDigest.NULL, DSDigest.SHA1, DSDigest.GOST},
- {DSDigest.NULL},
-)
-
-allow_all_policy = SimpleDeny(set(), set(), set(), set())
-
-
-default_policy = rfc_8624_policy
-
-
-def make_ds(
- name: Union[dns.name.Name, str],
- key: dns.rdata.Rdata,
- algorithm: Union[DSDigest, str],
- origin: Optional[dns.name.Name] = None,
- policy: Optional[Policy] = None,
- validating: bool = False,
-) -> DS:
- """Create a DS record for a DNSSEC key.
-
- *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record.
-
- *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``,
- the key the DS is about.
-
- *algorithm*, a ``str`` or ``int`` specifying the hash algorithm.
- The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case
- does not matter for these strings.
-
- *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name,
- then it will be made absolute using the specified origin.
-
- *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy,
- ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624.
-
- *validating*, a ``bool``. If ``True``, then policy is checked in
- validating mode, i.e. "Is it ok to validate using this digest algorithm?".
- Otherwise the policy is checked in creating mode, i.e. "Is it ok to create a DS with
- this digest algorithm?".
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
-
- Raises ``DeniedByPolicy`` if the algorithm is denied by policy.
-
- Returns a ``dns.rdtypes.ANY.DS.DS``
- """
-
- if policy is None:
- policy = default_policy
- try:
- if isinstance(algorithm, str):
- algorithm = DSDigest[algorithm.upper()]
- except Exception:
- raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm)
- if validating:
- check = policy.ok_to_validate_ds
- else:
- check = policy.ok_to_create_ds
- if not check(algorithm):
- raise DeniedByPolicy
- if not isinstance(key, (DNSKEY, CDNSKEY)):
- raise ValueError("key is not a DNSKEY/CDNSKEY")
- if algorithm == DSDigest.SHA1:
- dshash = hashlib.sha1()
- elif algorithm == DSDigest.SHA256:
- dshash = hashlib.sha256()
- elif algorithm == DSDigest.SHA384:
- dshash = hashlib.sha384()
- else:
- raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm)
-
- if isinstance(name, str):
- name = dns.name.from_text(name, origin)
- wire = name.canonicalize().to_wire()
- assert wire is not None
- dshash.update(wire)
- dshash.update(key.to_wire(origin=origin))
- digest = dshash.digest()
-
- dsrdata = struct.pack("!HBB", key_id(key), key.algorithm, algorithm) + digest
- ds = dns.rdata.from_wire(
- dns.rdataclass.IN, dns.rdatatype.DS, dsrdata, 0, len(dsrdata)
- )
- return cast(DS, ds)
-
-
-def make_cds(
- name: Union[dns.name.Name, str],
- key: dns.rdata.Rdata,
- algorithm: Union[DSDigest, str],
- origin: Optional[dns.name.Name] = None,
-) -> CDS:
- """Create a CDS record for a DNSSEC key.
-
- *name*, a ``dns.name.Name`` or ``str``, the owner name of the DS record.
-
- *key*, a ``dns.rdtypes.ANY.DNSKEY.DNSKEY`` or ``dns.rdtypes.ANY.DNSKEY.CDNSKEY``,
- the key the DS is about.
-
- *algorithm*, a ``str`` or ``int`` specifying the hash algorithm.
- The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case
- does not matter for these strings.
-
- *origin*, a ``dns.name.Name`` or ``None``. If *key* is a relative name,
- then it will be made absolute using the specified origin.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
-
- Returns a ``dns.rdtypes.ANY.DS.CDS``
- """
-
- ds = make_ds(name, key, algorithm, origin)
- return CDS(
- rdclass=ds.rdclass,
- rdtype=dns.rdatatype.CDS,
- key_tag=ds.key_tag,
- algorithm=ds.algorithm,
- digest_type=ds.digest_type,
- digest=ds.digest,
- )
-
-
-def _find_candidate_keys(
- keys: Dict[dns.name.Name, Union[dns.rdataset.Rdataset, dns.node.Node]], rrsig: RRSIG
-) -> Optional[List[DNSKEY]]:
- value = keys.get(rrsig.signer)
- if isinstance(value, dns.node.Node):
- rdataset = value.get_rdataset(dns.rdataclass.IN, dns.rdatatype.DNSKEY)
- else:
- rdataset = value
- if rdataset is None:
- return None
- return [
- cast(DNSKEY, rd)
- for rd in rdataset
- if rd.algorithm == rrsig.algorithm
- and key_id(rd) == rrsig.key_tag
- and (rd.flags & Flag.ZONE) == Flag.ZONE # RFC 4034 2.1.1
- and rd.protocol == 3 # RFC 4034 2.1.2
- ]
-
-
-def _get_rrname_rdataset(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
-) -> Tuple[dns.name.Name, dns.rdataset.Rdataset]:
- if isinstance(rrset, tuple):
- return rrset[0], rrset[1]
- else:
- return rrset.name, rrset
-
-
-def _validate_signature(sig: bytes, data: bytes, key: DNSKEY) -> None:
- public_cls = get_algorithm_cls_from_dnskey(key).public_cls
- try:
- public_key = public_cls.from_dnskey(key)
- except ValueError:
- raise ValidationFailure("invalid public key")
- public_key.verify(sig, data)
-
-
-def _validate_rrsig(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- rrsig: RRSIG,
- keys: Dict[dns.name.Name, Union[dns.node.Node, dns.rdataset.Rdataset]],
- origin: Optional[dns.name.Name] = None,
- now: Optional[float] = None,
- policy: Optional[Policy] = None,
-) -> None:
- """Validate an RRset against a single signature rdata, throwing an
- exception if validation is not successful.
-
- *rrset*, the RRset to validate. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *rrsig*, a ``dns.rdata.Rdata``, the signature to validate.
-
- *keys*, the key dictionary, used to find the DNSKEY associated
- with a given name. The dictionary is keyed by a
- ``dns.name.Name``, and has ``dns.node.Node`` or
- ``dns.rdataset.Rdataset`` values.
-
- *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative
- names.
-
- *now*, a ``float`` or ``None``, the time, in seconds since the epoch, to
- use as the current time when validating. If ``None``, the actual current
- time is used.
-
- *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy,
- ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624.
-
- Raises ``ValidationFailure`` if the signature is expired, not yet valid,
- the public key is invalid, the algorithm is unknown, the verification
- fails, etc.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by
- dnspython but not implemented.
- """
-
- if policy is None:
- policy = default_policy
-
- candidate_keys = _find_candidate_keys(keys, rrsig)
- if candidate_keys is None:
- raise ValidationFailure("unknown key")
-
- if now is None:
- now = time.time()
- if rrsig.expiration < now:
- raise ValidationFailure("expired")
- if rrsig.inception > now:
- raise ValidationFailure("not yet valid")
-
- data = _make_rrsig_signature_data(rrset, rrsig, origin)
-
- for candidate_key in candidate_keys:
- if not policy.ok_to_validate(candidate_key):
- continue
- try:
- _validate_signature(rrsig.signature, data, candidate_key)
- return
- except (InvalidSignature, ValidationFailure):
- # this happens on an individual validation failure
- continue
- # nothing verified -- raise failure:
- raise ValidationFailure("verify failure")
-
-
-def _validate(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- rrsigset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- keys: Dict[dns.name.Name, Union[dns.node.Node, dns.rdataset.Rdataset]],
- origin: Optional[dns.name.Name] = None,
- now: Optional[float] = None,
- policy: Optional[Policy] = None,
-) -> None:
- """Validate an RRset against a signature RRset, throwing an exception
- if none of the signatures validate.
-
- *rrset*, the RRset to validate. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *rrsigset*, the signature RRset. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *keys*, the key dictionary, used to find the DNSKEY associated
- with a given name. The dictionary is keyed by a
- ``dns.name.Name``, and has ``dns.node.Node`` or
- ``dns.rdataset.Rdataset`` values.
-
- *origin*, a ``dns.name.Name``, the origin to use for relative names;
- defaults to None.
-
- *now*, an ``int`` or ``None``, the time, in seconds since the epoch, to
- use as the current time when validating. If ``None``, the actual current
- time is used.
-
- *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy,
- ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624.
-
- Raises ``ValidationFailure`` if the signature is expired, not yet valid,
- the public key is invalid, the algorithm is unknown, the verification
- fails, etc.
- """
-
- if policy is None:
- policy = default_policy
-
- if isinstance(origin, str):
- origin = dns.name.from_text(origin, dns.name.root)
-
- if isinstance(rrset, tuple):
- rrname = rrset[0]
- else:
- rrname = rrset.name
-
- if isinstance(rrsigset, tuple):
- rrsigname = rrsigset[0]
- rrsigrdataset = rrsigset[1]
- else:
- rrsigname = rrsigset.name
- rrsigrdataset = rrsigset
-
- rrname = rrname.choose_relativity(origin)
- rrsigname = rrsigname.choose_relativity(origin)
- if rrname != rrsigname:
- raise ValidationFailure("owner names do not match")
-
- for rrsig in rrsigrdataset:
- if not isinstance(rrsig, RRSIG):
- raise ValidationFailure("expected an RRSIG")
- try:
- _validate_rrsig(rrset, rrsig, keys, origin, now, policy)
- return
- except (ValidationFailure, UnsupportedAlgorithm):
- pass
- raise ValidationFailure("no RRSIGs validated")
-
-
-def _sign(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- private_key: PrivateKey,
- signer: dns.name.Name,
- dnskey: DNSKEY,
- inception: Optional[Union[datetime, str, int, float]] = None,
- expiration: Optional[Union[datetime, str, int, float]] = None,
- lifetime: Optional[int] = None,
- verify: bool = False,
- policy: Optional[Policy] = None,
- origin: Optional[dns.name.Name] = None,
-) -> RRSIG:
- """Sign RRset using private key.
-
- *rrset*, the RRset to validate. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *private_key*, the private key to use for signing, a
- ``cryptography.hazmat.primitives.asymmetric`` private key class applicable
- for DNSSEC.
-
- *signer*, a ``dns.name.Name``, the Signer's name.
-
- *dnskey*, a ``DNSKEY`` matching ``private_key``.
-
- *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the
- signature inception time. If ``None``, the current time is used. If a ``str``, the
- format is "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX
- epoch in text form; this is the same the RRSIG rdata's text form.
- Values of type `int` or `float` are interpreted as seconds since the UNIX epoch.
-
- *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature
- expiration time. If ``None``, the expiration time will be the inception time plus
- the value of the *lifetime* parameter. See the description of *inception* above
- for how the various parameter types are interpreted.
-
- *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This
- parameter is only meaningful if *expiration* is ``None``.
-
- *verify*, a ``bool``. If set to ``True``, the signer will verify signatures
- after they are created; the default is ``False``.
-
- *policy*, a ``dns.dnssec.Policy`` or ``None``. If ``None``, the default policy,
- ``dns.dnssec.default_policy`` is used; this policy defaults to that of RFC 8624.
-
- *origin*, a ``dns.name.Name`` or ``None``. If ``None``, the default, then all
- names in the rrset (including its owner name) must be absolute; otherwise the
- specified origin will be used to make names absolute when signing.
-
- Raises ``DeniedByPolicy`` if the signature is denied by policy.
- """
-
- if policy is None:
- policy = default_policy
- if not policy.ok_to_sign(dnskey):
- raise DeniedByPolicy
-
- if isinstance(rrset, tuple):
- rdclass = rrset[1].rdclass
- rdtype = rrset[1].rdtype
- rrname = rrset[0]
- original_ttl = rrset[1].ttl
- else:
- rdclass = rrset.rdclass
- rdtype = rrset.rdtype
- rrname = rrset.name
- original_ttl = rrset.ttl
-
- if inception is not None:
- rrsig_inception = to_timestamp(inception)
- else:
- rrsig_inception = int(time.time())
-
- if expiration is not None:
- rrsig_expiration = to_timestamp(expiration)
- elif lifetime is not None:
- rrsig_expiration = rrsig_inception + lifetime
- else:
- raise ValueError("expiration or lifetime must be specified")
-
- # Derelativize now because we need a correct labels length for the
- # rrsig_template.
- if origin is not None:
- rrname = rrname.derelativize(origin)
- labels = len(rrname) - 1
-
- # Adjust labels appropriately for wildcards.
- if rrname.is_wild():
- labels -= 1
-
- rrsig_template = RRSIG(
- rdclass=rdclass,
- rdtype=dns.rdatatype.RRSIG,
- type_covered=rdtype,
- algorithm=dnskey.algorithm,
- labels=labels,
- original_ttl=original_ttl,
- expiration=rrsig_expiration,
- inception=rrsig_inception,
- key_tag=key_id(dnskey),
- signer=signer,
- signature=b"",
- )
-
- data = dns.dnssec._make_rrsig_signature_data(rrset, rrsig_template, origin)
-
- if isinstance(private_key, GenericPrivateKey):
- signing_key = private_key
- else:
- try:
- private_cls = get_algorithm_cls_from_dnskey(dnskey)
- signing_key = private_cls(key=private_key)
- except UnsupportedAlgorithm:
- raise TypeError("Unsupported key algorithm")
-
- signature = signing_key.sign(data, verify)
-
- return cast(RRSIG, rrsig_template.replace(signature=signature))
-
-
-def _make_rrsig_signature_data(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- rrsig: RRSIG,
- origin: Optional[dns.name.Name] = None,
-) -> bytes:
- """Create signature rdata.
-
- *rrset*, the RRset to sign/validate. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *rrsig*, a ``dns.rdata.Rdata``, the signature to validate, or the
- signature template used when signing.
-
- *origin*, a ``dns.name.Name`` or ``None``, the origin to use for relative
- names.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is recognized by
- dnspython but not implemented.
- """
-
- if isinstance(origin, str):
- origin = dns.name.from_text(origin, dns.name.root)
-
- signer = rrsig.signer
- if not signer.is_absolute():
- if origin is None:
- raise ValidationFailure("relative RR name without an origin specified")
- signer = signer.derelativize(origin)
-
- # For convenience, allow the rrset to be specified as a (name,
- # rdataset) tuple as well as a proper rrset
- rrname, rdataset = _get_rrname_rdataset(rrset)
-
- data = b""
- data += rrsig.to_wire(origin=signer)[:18]
- data += rrsig.signer.to_digestable(signer)
-
- # Derelativize the name before considering labels.
- if not rrname.is_absolute():
- if origin is None:
- raise ValidationFailure("relative RR name without an origin specified")
- rrname = rrname.derelativize(origin)
-
- name_len = len(rrname)
- if rrname.is_wild() and rrsig.labels != name_len - 2:
- raise ValidationFailure("wild owner name has wrong label length")
- if name_len - 1 < rrsig.labels:
- raise ValidationFailure("owner name longer than RRSIG labels")
- elif rrsig.labels < name_len - 1:
- suffix = rrname.split(rrsig.labels + 1)[1]
- rrname = dns.name.from_text("*", suffix)
- rrnamebuf = rrname.to_digestable()
- rrfixed = struct.pack("!HHI", rdataset.rdtype, rdataset.rdclass, rrsig.original_ttl)
- rdatas = [rdata.to_digestable(origin) for rdata in rdataset]
- for rdata in sorted(rdatas):
- data += rrnamebuf
- data += rrfixed
- rrlen = struct.pack("!H", len(rdata))
- data += rrlen
- data += rdata
-
- return data
-
-
-def _make_dnskey(
- public_key: PublicKey,
- algorithm: Union[int, str],
- flags: int = Flag.ZONE,
- protocol: int = 3,
-) -> DNSKEY:
- """Convert a public key to DNSKEY Rdata
-
- *public_key*, a ``PublicKey`` (``GenericPublicKey`` or
- ``cryptography.hazmat.primitives.asymmetric``) to convert.
-
- *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
-
- *flags*: DNSKEY flags field as an integer.
-
- *protocol*: DNSKEY protocol field as an integer.
-
- Raises ``ValueError`` if the specified key algorithm parameters are not
- unsupported, ``TypeError`` if the key type is unsupported,
- `UnsupportedAlgorithm` if the algorithm is unknown and
- `AlgorithmKeyMismatch` if the algorithm does not match the key type.
-
- Return DNSKEY ``Rdata``.
- """
-
- algorithm = Algorithm.make(algorithm)
-
- if isinstance(public_key, GenericPublicKey):
- return public_key.to_dnskey(flags=flags, protocol=protocol)
- else:
- public_cls = get_algorithm_cls(algorithm).public_cls
- return public_cls(key=public_key).to_dnskey(flags=flags, protocol=protocol)
-
-
-def _make_cdnskey(
- public_key: PublicKey,
- algorithm: Union[int, str],
- flags: int = Flag.ZONE,
- protocol: int = 3,
-) -> CDNSKEY:
- """Convert a public key to CDNSKEY Rdata
-
- *public_key*, the public key to convert, a
- ``cryptography.hazmat.primitives.asymmetric`` public key class applicable
- for DNSSEC.
-
- *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
-
- *flags*: DNSKEY flags field as an integer.
-
- *protocol*: DNSKEY protocol field as an integer.
-
- Raises ``ValueError`` if the specified key algorithm parameters are not
- unsupported, ``TypeError`` if the key type is unsupported,
- `UnsupportedAlgorithm` if the algorithm is unknown and
- `AlgorithmKeyMismatch` if the algorithm does not match the key type.
-
- Return CDNSKEY ``Rdata``.
- """
-
- dnskey = _make_dnskey(public_key, algorithm, flags, protocol)
-
- return CDNSKEY(
- rdclass=dnskey.rdclass,
- rdtype=dns.rdatatype.CDNSKEY,
- flags=dnskey.flags,
- protocol=dnskey.protocol,
- algorithm=dnskey.algorithm,
- key=dnskey.key,
- )
-
-
-def nsec3_hash(
- domain: Union[dns.name.Name, str],
- salt: Optional[Union[str, bytes]],
- iterations: int,
- algorithm: Union[int, str],
-) -> str:
- """
- Calculate the NSEC3 hash, according to
- https://tools.ietf.org/html/rfc5155#section-5
-
- *domain*, a ``dns.name.Name`` or ``str``, the name to hash.
-
- *salt*, a ``str``, ``bytes``, or ``None``, the hash salt. If a
- string, it is decoded as a hex string.
-
- *iterations*, an ``int``, the number of iterations.
-
- *algorithm*, a ``str`` or ``int``, the hash algorithm.
- The only defined algorithm is SHA1.
-
- Returns a ``str``, the encoded NSEC3 hash.
- """
-
- b32_conversion = str.maketrans(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", "0123456789ABCDEFGHIJKLMNOPQRSTUV"
- )
-
- try:
- if isinstance(algorithm, str):
- algorithm = NSEC3Hash[algorithm.upper()]
- except Exception:
- raise ValueError("Wrong hash algorithm (only SHA1 is supported)")
-
- if algorithm != NSEC3Hash.SHA1:
- raise ValueError("Wrong hash algorithm (only SHA1 is supported)")
-
- if salt is None:
- salt_encoded = b""
- elif isinstance(salt, str):
- if len(salt) % 2 == 0:
- salt_encoded = bytes.fromhex(salt)
- else:
- raise ValueError("Invalid salt length")
- else:
- salt_encoded = salt
-
- if not isinstance(domain, dns.name.Name):
- domain = dns.name.from_text(domain)
- domain_encoded = domain.canonicalize().to_wire()
- assert domain_encoded is not None
-
- digest = hashlib.sha1(domain_encoded + salt_encoded).digest()
- for _ in range(iterations):
- digest = hashlib.sha1(digest + salt_encoded).digest()
-
- output = base64.b32encode(digest).decode("utf-8")
- output = output.translate(b32_conversion)
-
- return output
-
-
-def make_ds_rdataset(
- rrset: Union[dns.rrset.RRset, Tuple[dns.name.Name, dns.rdataset.Rdataset]],
- algorithms: Set[Union[DSDigest, str]],
- origin: Optional[dns.name.Name] = None,
-) -> dns.rdataset.Rdataset:
- """Create a DS record from DNSKEY/CDNSKEY/CDS.
-
- *rrset*, the RRset to create DS Rdataset for. This can be a
- ``dns.rrset.RRset`` or a (``dns.name.Name``, ``dns.rdataset.Rdataset``)
- tuple.
-
- *algorithms*, a set of ``str`` or ``int`` specifying the hash algorithms.
- The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case
- does not matter for these strings. If the RRset is a CDS, only digest
- algorithms matching algorithms are accepted.
-
- *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name,
- then it will be made absolute using the specified origin.
-
- Raises ``UnsupportedAlgorithm`` if any of the algorithms are unknown and
- ``ValueError`` if the given RRset is not usable.
-
- Returns a ``dns.rdataset.Rdataset``
- """
-
- rrname, rdataset = _get_rrname_rdataset(rrset)
-
- if rdataset.rdtype not in (
- dns.rdatatype.DNSKEY,
- dns.rdatatype.CDNSKEY,
- dns.rdatatype.CDS,
- ):
- raise ValueError("rrset not a DNSKEY/CDNSKEY/CDS")
-
- _algorithms = set()
- for algorithm in algorithms:
- try:
- if isinstance(algorithm, str):
- algorithm = DSDigest[algorithm.upper()]
- except Exception:
- raise UnsupportedAlgorithm('unsupported algorithm "%s"' % algorithm)
- _algorithms.add(algorithm)
-
- if rdataset.rdtype == dns.rdatatype.CDS:
- res = []
- for rdata in cds_rdataset_to_ds_rdataset(rdataset):
- if rdata.digest_type in _algorithms:
- res.append(rdata)
- if len(res) == 0:
- raise ValueError("no acceptable CDS rdata found")
- return dns.rdataset.from_rdata_list(rdataset.ttl, res)
-
- res = []
- for algorithm in _algorithms:
- res.extend(dnskey_rdataset_to_cds_rdataset(rrname, rdataset, algorithm, origin))
- return dns.rdataset.from_rdata_list(rdataset.ttl, res)
-
-
-def cds_rdataset_to_ds_rdataset(
- rdataset: dns.rdataset.Rdataset,
-) -> dns.rdataset.Rdataset:
- """Create a CDS record from DS.
-
- *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for.
-
- Raises ``ValueError`` if the rdataset is not CDS.
-
- Returns a ``dns.rdataset.Rdataset``
- """
-
- if rdataset.rdtype != dns.rdatatype.CDS:
- raise ValueError("rdataset not a CDS")
- res = []
- for rdata in rdataset:
- res.append(
- CDS(
- rdclass=rdata.rdclass,
- rdtype=dns.rdatatype.DS,
- key_tag=rdata.key_tag,
- algorithm=rdata.algorithm,
- digest_type=rdata.digest_type,
- digest=rdata.digest,
- )
- )
- return dns.rdataset.from_rdata_list(rdataset.ttl, res)
-
-
-def dnskey_rdataset_to_cds_rdataset(
- name: Union[dns.name.Name, str],
- rdataset: dns.rdataset.Rdataset,
- algorithm: Union[DSDigest, str],
- origin: Optional[dns.name.Name] = None,
-) -> dns.rdataset.Rdataset:
- """Create a CDS record from DNSKEY/CDNSKEY.
-
- *name*, a ``dns.name.Name`` or ``str``, the owner name of the CDS record.
-
- *rdataset*, a ``dns.rdataset.Rdataset``, to create DS Rdataset for.
-
- *algorithm*, a ``str`` or ``int`` specifying the hash algorithm.
- The currently supported hashes are "SHA1", "SHA256", and "SHA384". Case
- does not matter for these strings.
-
- *origin*, a ``dns.name.Name`` or ``None``. If `key` is a relative name,
- then it will be made absolute using the specified origin.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is unknown or
- ``ValueError`` if the rdataset is not DNSKEY/CDNSKEY.
-
- Returns a ``dns.rdataset.Rdataset``
- """
-
- if rdataset.rdtype not in (dns.rdatatype.DNSKEY, dns.rdatatype.CDNSKEY):
- raise ValueError("rdataset not a DNSKEY/CDNSKEY")
- res = []
- for rdata in rdataset:
- res.append(make_cds(name, rdata, algorithm, origin))
- return dns.rdataset.from_rdata_list(rdataset.ttl, res)
-
-
-def dnskey_rdataset_to_cdnskey_rdataset(
- rdataset: dns.rdataset.Rdataset,
-) -> dns.rdataset.Rdataset:
- """Create a CDNSKEY record from DNSKEY.
-
- *rdataset*, a ``dns.rdataset.Rdataset``, to create CDNSKEY Rdataset for.
-
- Returns a ``dns.rdataset.Rdataset``
- """
-
- if rdataset.rdtype != dns.rdatatype.DNSKEY:
- raise ValueError("rdataset not a DNSKEY")
- res = []
- for rdata in rdataset:
- res.append(
- CDNSKEY(
- rdclass=rdataset.rdclass,
- rdtype=rdataset.rdtype,
- flags=rdata.flags,
- protocol=rdata.protocol,
- algorithm=rdata.algorithm,
- key=rdata.key,
- )
- )
- return dns.rdataset.from_rdata_list(rdataset.ttl, res)
-
-
-def default_rrset_signer(
- txn: dns.transaction.Transaction,
- rrset: dns.rrset.RRset,
- signer: dns.name.Name,
- ksks: List[Tuple[PrivateKey, DNSKEY]],
- zsks: List[Tuple[PrivateKey, DNSKEY]],
- inception: Optional[Union[datetime, str, int, float]] = None,
- expiration: Optional[Union[datetime, str, int, float]] = None,
- lifetime: Optional[int] = None,
- policy: Optional[Policy] = None,
- origin: Optional[dns.name.Name] = None,
-) -> None:
- """Default RRset signer"""
-
- if rrset.rdtype in set(
- [
- dns.rdatatype.RdataType.DNSKEY,
- dns.rdatatype.RdataType.CDS,
- dns.rdatatype.RdataType.CDNSKEY,
- ]
- ):
- keys = ksks
- else:
- keys = zsks
-
- for private_key, dnskey in keys:
- rrsig = dns.dnssec.sign(
- rrset=rrset,
- private_key=private_key,
- dnskey=dnskey,
- inception=inception,
- expiration=expiration,
- lifetime=lifetime,
- signer=signer,
- policy=policy,
- origin=origin,
- )
- txn.add(rrset.name, rrset.ttl, rrsig)
-
-
-def sign_zone(
- zone: dns.zone.Zone,
- txn: Optional[dns.transaction.Transaction] = None,
- keys: Optional[List[Tuple[PrivateKey, DNSKEY]]] = None,
- add_dnskey: bool = True,
- dnskey_ttl: Optional[int] = None,
- inception: Optional[Union[datetime, str, int, float]] = None,
- expiration: Optional[Union[datetime, str, int, float]] = None,
- lifetime: Optional[int] = None,
- nsec3: Optional[NSEC3PARAM] = None,
- rrset_signer: Optional[RRsetSigner] = None,
- policy: Optional[Policy] = None,
-) -> None:
- """Sign zone.
-
- *zone*, a ``dns.zone.Zone``, the zone to sign.
-
- *txn*, a ``dns.transaction.Transaction``, an optional transaction to use for
- signing.
-
- *keys*, a list of (``PrivateKey``, ``DNSKEY``) tuples, to use for signing. KSK/ZSK
- roles are assigned automatically if the SEP flag is used, otherwise all RRsets are
- signed by all keys.
-
- *add_dnskey*, a ``bool``. If ``True``, the default, all specified DNSKEYs are
- automatically added to the zone on signing.
-
- *dnskey_ttl*, a``int``, specifies the TTL for DNSKEY RRs. If not specified the TTL
- of the existing DNSKEY RRset used or the TTL of the SOA RRset.
-
- *inception*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature
- inception time. If ``None``, the current time is used. If a ``str``, the format is
- "YYYYMMDDHHMMSS" or alternatively the number of seconds since the UNIX epoch in text
- form; this is the same the RRSIG rdata's text form. Values of type `int` or `float`
- are interpreted as seconds since the UNIX epoch.
-
- *expiration*, a ``datetime``, ``str``, ``int``, ``float`` or ``None``, the signature
- expiration time. If ``None``, the expiration time will be the inception time plus
- the value of the *lifetime* parameter. See the description of *inception* above for
- how the various parameter types are interpreted.
-
- *lifetime*, an ``int`` or ``None``, the signature lifetime in seconds. This
- parameter is only meaningful if *expiration* is ``None``.
-
- *nsec3*, a ``NSEC3PARAM`` Rdata, configures signing using NSEC3. Not yet
- implemented.
-
- *rrset_signer*, a ``Callable``, an optional function for signing RRsets. The
- function requires two arguments: transaction and RRset. If the not specified,
- ``dns.dnssec.default_rrset_signer`` will be used.
-
- Returns ``None``.
- """
-
- ksks = []
- zsks = []
-
- # if we have both KSKs and ZSKs, split by SEP flag. if not, sign all
- # records with all keys
- if keys:
- for key in keys:
- if key[1].flags & Flag.SEP:
- ksks.append(key)
- else:
- zsks.append(key)
- if not ksks:
- ksks = keys
- if not zsks:
- zsks = keys
- else:
- keys = []
-
- if txn:
- cm: contextlib.AbstractContextManager = contextlib.nullcontext(txn)
- else:
- cm = zone.writer()
-
- with cm as _txn:
- if add_dnskey:
- if dnskey_ttl is None:
- dnskey = _txn.get(zone.origin, dns.rdatatype.DNSKEY)
- if dnskey:
- dnskey_ttl = dnskey.ttl
- else:
- soa = _txn.get(zone.origin, dns.rdatatype.SOA)
- dnskey_ttl = soa.ttl
- for _, dnskey in keys:
- _txn.add(zone.origin, dnskey_ttl, dnskey)
-
- if nsec3:
- raise NotImplementedError("Signing with NSEC3 not yet implemented")
- else:
- _rrset_signer = rrset_signer or functools.partial(
- default_rrset_signer,
- signer=zone.origin,
- ksks=ksks,
- zsks=zsks,
- inception=inception,
- expiration=expiration,
- lifetime=lifetime,
- policy=policy,
- origin=zone.origin,
- )
- return _sign_zone_nsec(zone, _txn, _rrset_signer)
-
-
-def _sign_zone_nsec(
- zone: dns.zone.Zone,
- txn: dns.transaction.Transaction,
- rrset_signer: Optional[RRsetSigner] = None,
-) -> None:
- """NSEC zone signer"""
-
- def _txn_add_nsec(
- txn: dns.transaction.Transaction,
- name: dns.name.Name,
- next_secure: Optional[dns.name.Name],
- rdclass: dns.rdataclass.RdataClass,
- ttl: int,
- rrset_signer: Optional[RRsetSigner] = None,
- ) -> None:
- """NSEC zone signer helper"""
- mandatory_types = set(
- [dns.rdatatype.RdataType.RRSIG, dns.rdatatype.RdataType.NSEC]
- )
- node = txn.get_node(name)
- if node and next_secure:
- types = (
- set([rdataset.rdtype for rdataset in node.rdatasets]) | mandatory_types
- )
- windows = Bitmap.from_rdtypes(list(types))
- rrset = dns.rrset.from_rdata(
- name,
- ttl,
- NSEC(
- rdclass=rdclass,
- rdtype=dns.rdatatype.RdataType.NSEC,
- next=next_secure,
- windows=windows,
- ),
- )
- txn.add(rrset)
- if rrset_signer:
- rrset_signer(txn, rrset)
-
- rrsig_ttl = zone.get_soa().minimum
- delegation = None
- last_secure = None
-
- for name in sorted(txn.iterate_names()):
- if delegation and name.is_subdomain(delegation):
- # names below delegations are not secure
- continue
- elif txn.get(name, dns.rdatatype.NS) and name != zone.origin:
- # inside delegation
- delegation = name
- else:
- # outside delegation
- delegation = None
-
- if rrset_signer:
- node = txn.get_node(name)
- if node:
- for rdataset in node.rdatasets:
- if rdataset.rdtype == dns.rdatatype.RRSIG:
- # do not sign RRSIGs
- continue
- elif delegation and rdataset.rdtype != dns.rdatatype.DS:
- # do not sign delegations except DS records
- continue
- else:
- rrset = dns.rrset.from_rdata(name, rdataset.ttl, *rdataset)
- rrset_signer(txn, rrset)
-
- # We need "is not None" as the empty name is False because its length is 0.
- if last_secure is not None:
- _txn_add_nsec(txn, last_secure, name, zone.rdclass, rrsig_ttl, rrset_signer)
- last_secure = name
-
- if last_secure:
- _txn_add_nsec(
- txn, last_secure, zone.origin, zone.rdclass, rrsig_ttl, rrset_signer
- )
-
-
-def _need_pyca(*args, **kwargs):
- raise ImportError(
- "DNSSEC validation requires python cryptography"
- ) # pragma: no cover
-
-
-if dns._features.have("dnssec"):
- from cryptography.exceptions import InvalidSignature
- from cryptography.hazmat.primitives.asymmetric import dsa # pylint: disable=W0611
- from cryptography.hazmat.primitives.asymmetric import ec # pylint: disable=W0611
- from cryptography.hazmat.primitives.asymmetric import ed448 # pylint: disable=W0611
- from cryptography.hazmat.primitives.asymmetric import rsa # pylint: disable=W0611
- from cryptography.hazmat.primitives.asymmetric import ( # pylint: disable=W0611
- ed25519,
- )
-
- from dns.dnssecalgs import ( # pylint: disable=C0412
- get_algorithm_cls,
- get_algorithm_cls_from_dnskey,
- )
- from dns.dnssecalgs.base import GenericPrivateKey, GenericPublicKey
-
- validate = _validate # type: ignore
- validate_rrsig = _validate_rrsig # type: ignore
- sign = _sign
- make_dnskey = _make_dnskey
- make_cdnskey = _make_cdnskey
- _have_pyca = True
-else: # pragma: no cover
- validate = _need_pyca
- validate_rrsig = _need_pyca
- sign = _need_pyca
- make_dnskey = _need_pyca
- make_cdnskey = _need_pyca
- _have_pyca = False
-
-### BEGIN generated Algorithm constants
-
-RSAMD5 = Algorithm.RSAMD5
-DH = Algorithm.DH
-DSA = Algorithm.DSA
-ECC = Algorithm.ECC
-RSASHA1 = Algorithm.RSASHA1
-DSANSEC3SHA1 = Algorithm.DSANSEC3SHA1
-RSASHA1NSEC3SHA1 = Algorithm.RSASHA1NSEC3SHA1
-RSASHA256 = Algorithm.RSASHA256
-RSASHA512 = Algorithm.RSASHA512
-ECCGOST = Algorithm.ECCGOST
-ECDSAP256SHA256 = Algorithm.ECDSAP256SHA256
-ECDSAP384SHA384 = Algorithm.ECDSAP384SHA384
-ED25519 = Algorithm.ED25519
-ED448 = Algorithm.ED448
-INDIRECT = Algorithm.INDIRECT
-PRIVATEDNS = Algorithm.PRIVATEDNS
-PRIVATEOID = Algorithm.PRIVATEOID
-
-### END generated Algorithm constants
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__init__.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__init__.py
deleted file mode 100644
index 3d9181a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__init__.py
+++ /dev/null
@@ -1,120 +0,0 @@
-from typing import Dict, Optional, Tuple, Type, Union
-
-import dns.name
-from dns.dnssecalgs.base import GenericPrivateKey
-from dns.dnssectypes import Algorithm
-from dns.exception import UnsupportedAlgorithm
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-
-if dns._features.have("dnssec"):
- from dns.dnssecalgs.dsa import PrivateDSA, PrivateDSANSEC3SHA1
- from dns.dnssecalgs.ecdsa import PrivateECDSAP256SHA256, PrivateECDSAP384SHA384
- from dns.dnssecalgs.eddsa import PrivateED448, PrivateED25519
- from dns.dnssecalgs.rsa import (
- PrivateRSAMD5,
- PrivateRSASHA1,
- PrivateRSASHA1NSEC3SHA1,
- PrivateRSASHA256,
- PrivateRSASHA512,
- )
-
- _have_cryptography = True
-else:
- _have_cryptography = False
-
-AlgorithmPrefix = Optional[Union[bytes, dns.name.Name]]
-
-algorithms: Dict[Tuple[Algorithm, AlgorithmPrefix], Type[GenericPrivateKey]] = {}
-if _have_cryptography:
- algorithms.update(
- {
- (Algorithm.RSAMD5, None): PrivateRSAMD5,
- (Algorithm.DSA, None): PrivateDSA,
- (Algorithm.RSASHA1, None): PrivateRSASHA1,
- (Algorithm.DSANSEC3SHA1, None): PrivateDSANSEC3SHA1,
- (Algorithm.RSASHA1NSEC3SHA1, None): PrivateRSASHA1NSEC3SHA1,
- (Algorithm.RSASHA256, None): PrivateRSASHA256,
- (Algorithm.RSASHA512, None): PrivateRSASHA512,
- (Algorithm.ECDSAP256SHA256, None): PrivateECDSAP256SHA256,
- (Algorithm.ECDSAP384SHA384, None): PrivateECDSAP384SHA384,
- (Algorithm.ED25519, None): PrivateED25519,
- (Algorithm.ED448, None): PrivateED448,
- }
- )
-
-
-def get_algorithm_cls(
- algorithm: Union[int, str], prefix: AlgorithmPrefix = None
-) -> Type[GenericPrivateKey]:
- """Get Private Key class from Algorithm.
-
- *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
-
- Returns a ``dns.dnssecalgs.GenericPrivateKey``
- """
- algorithm = Algorithm.make(algorithm)
- cls = algorithms.get((algorithm, prefix))
- if cls:
- return cls
- raise UnsupportedAlgorithm(
- 'algorithm "%s" not supported by dnspython' % Algorithm.to_text(algorithm)
- )
-
-
-def get_algorithm_cls_from_dnskey(dnskey: DNSKEY) -> Type[GenericPrivateKey]:
- """Get Private Key class from DNSKEY.
-
- *dnskey*, a ``DNSKEY`` to get Algorithm class for.
-
- Raises ``UnsupportedAlgorithm`` if the algorithm is unknown.
-
- Returns a ``dns.dnssecalgs.GenericPrivateKey``
- """
- prefix: AlgorithmPrefix = None
- if dnskey.algorithm == Algorithm.PRIVATEDNS:
- prefix, _ = dns.name.from_wire(dnskey.key, 0)
- elif dnskey.algorithm == Algorithm.PRIVATEOID:
- length = int(dnskey.key[0])
- prefix = dnskey.key[0 : length + 1]
- return get_algorithm_cls(dnskey.algorithm, prefix)
-
-
-def register_algorithm_cls(
- algorithm: Union[int, str],
- algorithm_cls: Type[GenericPrivateKey],
- name: Optional[Union[dns.name.Name, str]] = None,
- oid: Optional[bytes] = None,
-) -> None:
- """Register Algorithm Private Key class.
-
- *algorithm*, a ``str`` or ``int`` specifying the DNSKEY algorithm.
-
- *algorithm_cls*: A `GenericPrivateKey` class.
-
- *name*, an optional ``dns.name.Name`` or ``str``, for for PRIVATEDNS algorithms.
-
- *oid*: an optional BER-encoded `bytes` for PRIVATEOID algorithms.
-
- Raises ``ValueError`` if a name or oid is specified incorrectly.
- """
- if not issubclass(algorithm_cls, GenericPrivateKey):
- raise TypeError("Invalid algorithm class")
- algorithm = Algorithm.make(algorithm)
- prefix: AlgorithmPrefix = None
- if algorithm == Algorithm.PRIVATEDNS:
- if name is None:
- raise ValueError("Name required for PRIVATEDNS algorithms")
- if isinstance(name, str):
- name = dns.name.from_text(name)
- prefix = name
- elif algorithm == Algorithm.PRIVATEOID:
- if oid is None:
- raise ValueError("OID required for PRIVATEOID algorithms")
- prefix = bytes([len(oid)]) + oid
- elif name:
- raise ValueError("Name only supported for PRIVATEDNS algorithm")
- elif oid:
- raise ValueError("OID only supported for PRIVATEOID algorithm")
- algorithms[(algorithm, prefix)] = algorithm_cls
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index d1aa1e8..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/base.cpython-312.pyc
deleted file mode 100644
index 6e73eb8..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/base.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/cryptography.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/cryptography.cpython-312.pyc
deleted file mode 100644
index 0b2343c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/cryptography.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/dsa.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/dsa.cpython-312.pyc
deleted file mode 100644
index 47d5a38..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/dsa.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/ecdsa.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/ecdsa.cpython-312.pyc
deleted file mode 100644
index af6ac05..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/ecdsa.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/eddsa.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/eddsa.cpython-312.pyc
deleted file mode 100644
index bff8672..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/eddsa.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/rsa.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/rsa.cpython-312.pyc
deleted file mode 100644
index dd67c07..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/__pycache__/rsa.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/base.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/base.py
deleted file mode 100644
index e990575..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/base.py
+++ /dev/null
@@ -1,84 +0,0 @@
-from abc import ABC, abstractmethod # pylint: disable=no-name-in-module
-from typing import Any, Optional, Type
-
-import dns.rdataclass
-import dns.rdatatype
-from dns.dnssectypes import Algorithm
-from dns.exception import AlgorithmKeyMismatch
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-from dns.rdtypes.dnskeybase import Flag
-
-
-class GenericPublicKey(ABC):
- algorithm: Algorithm
-
- @abstractmethod
- def __init__(self, key: Any) -> None:
- pass
-
- @abstractmethod
- def verify(self, signature: bytes, data: bytes) -> None:
- """Verify signed DNSSEC data"""
-
- @abstractmethod
- def encode_key_bytes(self) -> bytes:
- """Encode key as bytes for DNSKEY"""
-
- @classmethod
- def _ensure_algorithm_key_combination(cls, key: DNSKEY) -> None:
- if key.algorithm != cls.algorithm:
- raise AlgorithmKeyMismatch
-
- def to_dnskey(self, flags: int = Flag.ZONE, protocol: int = 3) -> DNSKEY:
- """Return public key as DNSKEY"""
- return DNSKEY(
- rdclass=dns.rdataclass.IN,
- rdtype=dns.rdatatype.DNSKEY,
- flags=flags,
- protocol=protocol,
- algorithm=self.algorithm,
- key=self.encode_key_bytes(),
- )
-
- @classmethod
- @abstractmethod
- def from_dnskey(cls, key: DNSKEY) -> "GenericPublicKey":
- """Create public key from DNSKEY"""
-
- @classmethod
- @abstractmethod
- def from_pem(cls, public_pem: bytes) -> "GenericPublicKey":
- """Create public key from PEM-encoded SubjectPublicKeyInfo as specified
- in RFC 5280"""
-
- @abstractmethod
- def to_pem(self) -> bytes:
- """Return public-key as PEM-encoded SubjectPublicKeyInfo as specified
- in RFC 5280"""
-
-
-class GenericPrivateKey(ABC):
- public_cls: Type[GenericPublicKey]
-
- @abstractmethod
- def __init__(self, key: Any) -> None:
- pass
-
- @abstractmethod
- def sign(self, data: bytes, verify: bool = False) -> bytes:
- """Sign DNSSEC data"""
-
- @abstractmethod
- def public_key(self) -> "GenericPublicKey":
- """Return public key instance"""
-
- @classmethod
- @abstractmethod
- def from_pem(
- cls, private_pem: bytes, password: Optional[bytes] = None
- ) -> "GenericPrivateKey":
- """Create private key from PEM-encoded PKCS#8"""
-
- @abstractmethod
- def to_pem(self, password: Optional[bytes] = None) -> bytes:
- """Return private key as PEM-encoded PKCS#8"""
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/cryptography.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/cryptography.py
deleted file mode 100644
index 5a31a81..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/cryptography.py
+++ /dev/null
@@ -1,68 +0,0 @@
-from typing import Any, Optional, Type
-
-from cryptography.hazmat.primitives import serialization
-
-from dns.dnssecalgs.base import GenericPrivateKey, GenericPublicKey
-from dns.exception import AlgorithmKeyMismatch
-
-
-class CryptographyPublicKey(GenericPublicKey):
- key: Any = None
- key_cls: Any = None
-
- def __init__(self, key: Any) -> None: # pylint: disable=super-init-not-called
- if self.key_cls is None:
- raise TypeError("Undefined private key class")
- if not isinstance( # pylint: disable=isinstance-second-argument-not-valid-type
- key, self.key_cls
- ):
- raise AlgorithmKeyMismatch
- self.key = key
-
- @classmethod
- def from_pem(cls, public_pem: bytes) -> "GenericPublicKey":
- key = serialization.load_pem_public_key(public_pem)
- return cls(key=key)
-
- def to_pem(self) -> bytes:
- return self.key.public_bytes(
- encoding=serialization.Encoding.PEM,
- format=serialization.PublicFormat.SubjectPublicKeyInfo,
- )
-
-
-class CryptographyPrivateKey(GenericPrivateKey):
- key: Any = None
- key_cls: Any = None
- public_cls: Type[CryptographyPublicKey]
-
- def __init__(self, key: Any) -> None: # pylint: disable=super-init-not-called
- if self.key_cls is None:
- raise TypeError("Undefined private key class")
- if not isinstance( # pylint: disable=isinstance-second-argument-not-valid-type
- key, self.key_cls
- ):
- raise AlgorithmKeyMismatch
- self.key = key
-
- def public_key(self) -> "CryptographyPublicKey":
- return self.public_cls(key=self.key.public_key())
-
- @classmethod
- def from_pem(
- cls, private_pem: bytes, password: Optional[bytes] = None
- ) -> "GenericPrivateKey":
- key = serialization.load_pem_private_key(private_pem, password=password)
- return cls(key=key)
-
- def to_pem(self, password: Optional[bytes] = None) -> bytes:
- encryption_algorithm: serialization.KeySerializationEncryption
- if password:
- encryption_algorithm = serialization.BestAvailableEncryption(password)
- else:
- encryption_algorithm = serialization.NoEncryption()
- return self.key.private_bytes(
- encoding=serialization.Encoding.PEM,
- format=serialization.PrivateFormat.PKCS8,
- encryption_algorithm=encryption_algorithm,
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/dsa.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/dsa.py
deleted file mode 100644
index 0fe4690..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/dsa.py
+++ /dev/null
@@ -1,101 +0,0 @@
-import struct
-
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.asymmetric import dsa, utils
-
-from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
-from dns.dnssectypes import Algorithm
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-
-
-class PublicDSA(CryptographyPublicKey):
- key: dsa.DSAPublicKey
- key_cls = dsa.DSAPublicKey
- algorithm = Algorithm.DSA
- chosen_hash = hashes.SHA1()
-
- def verify(self, signature: bytes, data: bytes) -> None:
- sig_r = signature[1:21]
- sig_s = signature[21:]
- sig = utils.encode_dss_signature(
- int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big")
- )
- self.key.verify(sig, data, self.chosen_hash)
-
- def encode_key_bytes(self) -> bytes:
- """Encode a public key per RFC 2536, section 2."""
- pn = self.key.public_numbers()
- dsa_t = (self.key.key_size // 8 - 64) // 8
- if dsa_t > 8:
- raise ValueError("unsupported DSA key size")
- octets = 64 + dsa_t * 8
- res = struct.pack("!B", dsa_t)
- res += pn.parameter_numbers.q.to_bytes(20, "big")
- res += pn.parameter_numbers.p.to_bytes(octets, "big")
- res += pn.parameter_numbers.g.to_bytes(octets, "big")
- res += pn.y.to_bytes(octets, "big")
- return res
-
- @classmethod
- def from_dnskey(cls, key: DNSKEY) -> "PublicDSA":
- cls._ensure_algorithm_key_combination(key)
- keyptr = key.key
- (t,) = struct.unpack("!B", keyptr[0:1])
- keyptr = keyptr[1:]
- octets = 64 + t * 8
- dsa_q = keyptr[0:20]
- keyptr = keyptr[20:]
- dsa_p = keyptr[0:octets]
- keyptr = keyptr[octets:]
- dsa_g = keyptr[0:octets]
- keyptr = keyptr[octets:]
- dsa_y = keyptr[0:octets]
- return cls(
- key=dsa.DSAPublicNumbers( # type: ignore
- int.from_bytes(dsa_y, "big"),
- dsa.DSAParameterNumbers(
- int.from_bytes(dsa_p, "big"),
- int.from_bytes(dsa_q, "big"),
- int.from_bytes(dsa_g, "big"),
- ),
- ).public_key(default_backend()),
- )
-
-
-class PrivateDSA(CryptographyPrivateKey):
- key: dsa.DSAPrivateKey
- key_cls = dsa.DSAPrivateKey
- public_cls = PublicDSA
-
- def sign(self, data: bytes, verify: bool = False) -> bytes:
- """Sign using a private key per RFC 2536, section 3."""
- public_dsa_key = self.key.public_key()
- if public_dsa_key.key_size > 1024:
- raise ValueError("DSA key size overflow")
- der_signature = self.key.sign(data, self.public_cls.chosen_hash)
- dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
- dsa_t = (public_dsa_key.key_size // 8 - 64) // 8
- octets = 20
- signature = (
- struct.pack("!B", dsa_t)
- + int.to_bytes(dsa_r, length=octets, byteorder="big")
- + int.to_bytes(dsa_s, length=octets, byteorder="big")
- )
- if verify:
- self.public_key().verify(signature, data)
- return signature
-
- @classmethod
- def generate(cls, key_size: int) -> "PrivateDSA":
- return cls(
- key=dsa.generate_private_key(key_size=key_size),
- )
-
-
-class PublicDSANSEC3SHA1(PublicDSA):
- algorithm = Algorithm.DSANSEC3SHA1
-
-
-class PrivateDSANSEC3SHA1(PrivateDSA):
- public_cls = PublicDSANSEC3SHA1
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/ecdsa.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/ecdsa.py
deleted file mode 100644
index a31d79f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/ecdsa.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.asymmetric import ec, utils
-
-from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
-from dns.dnssectypes import Algorithm
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-
-
-class PublicECDSA(CryptographyPublicKey):
- key: ec.EllipticCurvePublicKey
- key_cls = ec.EllipticCurvePublicKey
- algorithm: Algorithm
- chosen_hash: hashes.HashAlgorithm
- curve: ec.EllipticCurve
- octets: int
-
- def verify(self, signature: bytes, data: bytes) -> None:
- sig_r = signature[0 : self.octets]
- sig_s = signature[self.octets :]
- sig = utils.encode_dss_signature(
- int.from_bytes(sig_r, "big"), int.from_bytes(sig_s, "big")
- )
- self.key.verify(sig, data, ec.ECDSA(self.chosen_hash))
-
- def encode_key_bytes(self) -> bytes:
- """Encode a public key per RFC 6605, section 4."""
- pn = self.key.public_numbers()
- return pn.x.to_bytes(self.octets, "big") + pn.y.to_bytes(self.octets, "big")
-
- @classmethod
- def from_dnskey(cls, key: DNSKEY) -> "PublicECDSA":
- cls._ensure_algorithm_key_combination(key)
- ecdsa_x = key.key[0 : cls.octets]
- ecdsa_y = key.key[cls.octets : cls.octets * 2]
- return cls(
- key=ec.EllipticCurvePublicNumbers(
- curve=cls.curve,
- x=int.from_bytes(ecdsa_x, "big"),
- y=int.from_bytes(ecdsa_y, "big"),
- ).public_key(default_backend()),
- )
-
-
-class PrivateECDSA(CryptographyPrivateKey):
- key: ec.EllipticCurvePrivateKey
- key_cls = ec.EllipticCurvePrivateKey
- public_cls = PublicECDSA
-
- def sign(self, data: bytes, verify: bool = False) -> bytes:
- """Sign using a private key per RFC 6605, section 4."""
- der_signature = self.key.sign(data, ec.ECDSA(self.public_cls.chosen_hash))
- dsa_r, dsa_s = utils.decode_dss_signature(der_signature)
- signature = int.to_bytes(
- dsa_r, length=self.public_cls.octets, byteorder="big"
- ) + int.to_bytes(dsa_s, length=self.public_cls.octets, byteorder="big")
- if verify:
- self.public_key().verify(signature, data)
- return signature
-
- @classmethod
- def generate(cls) -> "PrivateECDSA":
- return cls(
- key=ec.generate_private_key(
- curve=cls.public_cls.curve, backend=default_backend()
- ),
- )
-
-
-class PublicECDSAP256SHA256(PublicECDSA):
- algorithm = Algorithm.ECDSAP256SHA256
- chosen_hash = hashes.SHA256()
- curve = ec.SECP256R1()
- octets = 32
-
-
-class PrivateECDSAP256SHA256(PrivateECDSA):
- public_cls = PublicECDSAP256SHA256
-
-
-class PublicECDSAP384SHA384(PublicECDSA):
- algorithm = Algorithm.ECDSAP384SHA384
- chosen_hash = hashes.SHA384()
- curve = ec.SECP384R1()
- octets = 48
-
-
-class PrivateECDSAP384SHA384(PrivateECDSA):
- public_cls = PublicECDSAP384SHA384
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/eddsa.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/eddsa.py
deleted file mode 100644
index 7050534..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/eddsa.py
+++ /dev/null
@@ -1,65 +0,0 @@
-from typing import Type
-
-from cryptography.hazmat.primitives import serialization
-from cryptography.hazmat.primitives.asymmetric import ed448, ed25519
-
-from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
-from dns.dnssectypes import Algorithm
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-
-
-class PublicEDDSA(CryptographyPublicKey):
- def verify(self, signature: bytes, data: bytes) -> None:
- self.key.verify(signature, data)
-
- def encode_key_bytes(self) -> bytes:
- """Encode a public key per RFC 8080, section 3."""
- return self.key.public_bytes(
- encoding=serialization.Encoding.Raw, format=serialization.PublicFormat.Raw
- )
-
- @classmethod
- def from_dnskey(cls, key: DNSKEY) -> "PublicEDDSA":
- cls._ensure_algorithm_key_combination(key)
- return cls(
- key=cls.key_cls.from_public_bytes(key.key),
- )
-
-
-class PrivateEDDSA(CryptographyPrivateKey):
- public_cls: Type[PublicEDDSA]
-
- def sign(self, data: bytes, verify: bool = False) -> bytes:
- """Sign using a private key per RFC 8080, section 4."""
- signature = self.key.sign(data)
- if verify:
- self.public_key().verify(signature, data)
- return signature
-
- @classmethod
- def generate(cls) -> "PrivateEDDSA":
- return cls(key=cls.key_cls.generate())
-
-
-class PublicED25519(PublicEDDSA):
- key: ed25519.Ed25519PublicKey
- key_cls = ed25519.Ed25519PublicKey
- algorithm = Algorithm.ED25519
-
-
-class PrivateED25519(PrivateEDDSA):
- key: ed25519.Ed25519PrivateKey
- key_cls = ed25519.Ed25519PrivateKey
- public_cls = PublicED25519
-
-
-class PublicED448(PublicEDDSA):
- key: ed448.Ed448PublicKey
- key_cls = ed448.Ed448PublicKey
- algorithm = Algorithm.ED448
-
-
-class PrivateED448(PrivateEDDSA):
- key: ed448.Ed448PrivateKey
- key_cls = ed448.Ed448PrivateKey
- public_cls = PublicED448
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/rsa.py b/.venv/lib/python3.12/site-packages/dns/dnssecalgs/rsa.py
deleted file mode 100644
index e95dcf1..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssecalgs/rsa.py
+++ /dev/null
@@ -1,119 +0,0 @@
-import math
-import struct
-
-from cryptography.hazmat.backends import default_backend
-from cryptography.hazmat.primitives import hashes
-from cryptography.hazmat.primitives.asymmetric import padding, rsa
-
-from dns.dnssecalgs.cryptography import CryptographyPrivateKey, CryptographyPublicKey
-from dns.dnssectypes import Algorithm
-from dns.rdtypes.ANY.DNSKEY import DNSKEY
-
-
-class PublicRSA(CryptographyPublicKey):
- key: rsa.RSAPublicKey
- key_cls = rsa.RSAPublicKey
- algorithm: Algorithm
- chosen_hash: hashes.HashAlgorithm
-
- def verify(self, signature: bytes, data: bytes) -> None:
- self.key.verify(signature, data, padding.PKCS1v15(), self.chosen_hash)
-
- def encode_key_bytes(self) -> bytes:
- """Encode a public key per RFC 3110, section 2."""
- pn = self.key.public_numbers()
- _exp_len = math.ceil(int.bit_length(pn.e) / 8)
- exp = int.to_bytes(pn.e, length=_exp_len, byteorder="big")
- if _exp_len > 255:
- exp_header = b"\0" + struct.pack("!H", _exp_len)
- else:
- exp_header = struct.pack("!B", _exp_len)
- if pn.n.bit_length() < 512 or pn.n.bit_length() > 4096:
- raise ValueError("unsupported RSA key length")
- return exp_header + exp + pn.n.to_bytes((pn.n.bit_length() + 7) // 8, "big")
-
- @classmethod
- def from_dnskey(cls, key: DNSKEY) -> "PublicRSA":
- cls._ensure_algorithm_key_combination(key)
- keyptr = key.key
- (bytes_,) = struct.unpack("!B", keyptr[0:1])
- keyptr = keyptr[1:]
- if bytes_ == 0:
- (bytes_,) = struct.unpack("!H", keyptr[0:2])
- keyptr = keyptr[2:]
- rsa_e = keyptr[0:bytes_]
- rsa_n = keyptr[bytes_:]
- return cls(
- key=rsa.RSAPublicNumbers(
- int.from_bytes(rsa_e, "big"), int.from_bytes(rsa_n, "big")
- ).public_key(default_backend())
- )
-
-
-class PrivateRSA(CryptographyPrivateKey):
- key: rsa.RSAPrivateKey
- key_cls = rsa.RSAPrivateKey
- public_cls = PublicRSA
- default_public_exponent = 65537
-
- def sign(self, data: bytes, verify: bool = False) -> bytes:
- """Sign using a private key per RFC 3110, section 3."""
- signature = self.key.sign(data, padding.PKCS1v15(), self.public_cls.chosen_hash)
- if verify:
- self.public_key().verify(signature, data)
- return signature
-
- @classmethod
- def generate(cls, key_size: int) -> "PrivateRSA":
- return cls(
- key=rsa.generate_private_key(
- public_exponent=cls.default_public_exponent,
- key_size=key_size,
- backend=default_backend(),
- )
- )
-
-
-class PublicRSAMD5(PublicRSA):
- algorithm = Algorithm.RSAMD5
- chosen_hash = hashes.MD5()
-
-
-class PrivateRSAMD5(PrivateRSA):
- public_cls = PublicRSAMD5
-
-
-class PublicRSASHA1(PublicRSA):
- algorithm = Algorithm.RSASHA1
- chosen_hash = hashes.SHA1()
-
-
-class PrivateRSASHA1(PrivateRSA):
- public_cls = PublicRSASHA1
-
-
-class PublicRSASHA1NSEC3SHA1(PublicRSA):
- algorithm = Algorithm.RSASHA1NSEC3SHA1
- chosen_hash = hashes.SHA1()
-
-
-class PrivateRSASHA1NSEC3SHA1(PrivateRSA):
- public_cls = PublicRSASHA1NSEC3SHA1
-
-
-class PublicRSASHA256(PublicRSA):
- algorithm = Algorithm.RSASHA256
- chosen_hash = hashes.SHA256()
-
-
-class PrivateRSASHA256(PrivateRSA):
- public_cls = PublicRSASHA256
-
-
-class PublicRSASHA512(PublicRSA):
- algorithm = Algorithm.RSASHA512
- chosen_hash = hashes.SHA512()
-
-
-class PrivateRSASHA512(PrivateRSA):
- public_cls = PublicRSASHA512
diff --git a/.venv/lib/python3.12/site-packages/dns/dnssectypes.py b/.venv/lib/python3.12/site-packages/dns/dnssectypes.py
deleted file mode 100644
index 02131e0..0000000
--- a/.venv/lib/python3.12/site-packages/dns/dnssectypes.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Common DNSSEC-related types."""
-
-# This is a separate file to avoid import circularity between dns.dnssec and
-# the implementations of the DS and DNSKEY types.
-
-import dns.enum
-
-
-class Algorithm(dns.enum.IntEnum):
- RSAMD5 = 1
- DH = 2
- DSA = 3
- ECC = 4
- RSASHA1 = 5
- DSANSEC3SHA1 = 6
- RSASHA1NSEC3SHA1 = 7
- RSASHA256 = 8
- RSASHA512 = 10
- ECCGOST = 12
- ECDSAP256SHA256 = 13
- ECDSAP384SHA384 = 14
- ED25519 = 15
- ED448 = 16
- INDIRECT = 252
- PRIVATEDNS = 253
- PRIVATEOID = 254
-
- @classmethod
- def _maximum(cls):
- return 255
-
-
-class DSDigest(dns.enum.IntEnum):
- """DNSSEC Delegation Signer Digest Algorithm"""
-
- NULL = 0
- SHA1 = 1
- SHA256 = 2
- GOST = 3
- SHA384 = 4
-
- @classmethod
- def _maximum(cls):
- return 255
-
-
-class NSEC3Hash(dns.enum.IntEnum):
- """NSEC3 hash algorithm"""
-
- SHA1 = 1
-
- @classmethod
- def _maximum(cls):
- return 255
diff --git a/.venv/lib/python3.12/site-packages/dns/e164.py b/.venv/lib/python3.12/site-packages/dns/e164.py
deleted file mode 100644
index 453736d..0000000
--- a/.venv/lib/python3.12/site-packages/dns/e164.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS E.164 helpers."""
-
-from typing import Iterable, Optional, Union
-
-import dns.exception
-import dns.name
-import dns.resolver
-
-#: The public E.164 domain.
-public_enum_domain = dns.name.from_text("e164.arpa.")
-
-
-def from_e164(
- text: str, origin: Optional[dns.name.Name] = public_enum_domain
-) -> dns.name.Name:
- """Convert an E.164 number in textual form into a Name object whose
- value is the ENUM domain name for that number.
-
- Non-digits in the text are ignored, i.e. "16505551212",
- "+1.650.555.1212" and "1 (650) 555-1212" are all the same.
-
- *text*, a ``str``, is an E.164 number in textual form.
-
- *origin*, a ``dns.name.Name``, the domain in which the number
- should be constructed. The default is ``e164.arpa.``.
-
- Returns a ``dns.name.Name``.
- """
-
- parts = [d for d in text if d.isdigit()]
- parts.reverse()
- return dns.name.from_text(".".join(parts), origin=origin)
-
-
-def to_e164(
- name: dns.name.Name,
- origin: Optional[dns.name.Name] = public_enum_domain,
- want_plus_prefix: bool = True,
-) -> str:
- """Convert an ENUM domain name into an E.164 number.
-
- Note that dnspython does not have any information about preferred
- number formats within national numbering plans, so all numbers are
- emitted as a simple string of digits, prefixed by a '+' (unless
- *want_plus_prefix* is ``False``).
-
- *name* is a ``dns.name.Name``, the ENUM domain name.
-
- *origin* is a ``dns.name.Name``, a domain containing the ENUM
- domain name. The name is relativized to this domain before being
- converted to text. If ``None``, no relativization is done.
-
- *want_plus_prefix* is a ``bool``. If True, add a '+' to the beginning of
- the returned number.
-
- Returns a ``str``.
-
- """
- if origin is not None:
- name = name.relativize(origin)
- dlabels = [d for d in name.labels if d.isdigit() and len(d) == 1]
- if len(dlabels) != len(name.labels):
- raise dns.exception.SyntaxError("non-digit labels in ENUM domain name")
- dlabels.reverse()
- text = b"".join(dlabels)
- if want_plus_prefix:
- text = b"+" + text
- return text.decode()
-
-
-def query(
- number: str,
- domains: Iterable[Union[dns.name.Name, str]],
- resolver: Optional[dns.resolver.Resolver] = None,
-) -> dns.resolver.Answer:
- """Look for NAPTR RRs for the specified number in the specified domains.
-
- e.g. lookup('16505551212', ['e164.dnspython.org.', 'e164.arpa.'])
-
- *number*, a ``str`` is the number to look for.
-
- *domains* is an iterable containing ``dns.name.Name`` values.
-
- *resolver*, a ``dns.resolver.Resolver``, is the resolver to use. If
- ``None``, the default resolver is used.
- """
-
- if resolver is None:
- resolver = dns.resolver.get_default_resolver()
- e_nx = dns.resolver.NXDOMAIN()
- for domain in domains:
- if isinstance(domain, str):
- domain = dns.name.from_text(domain)
- qname = dns.e164.from_e164(number, domain)
- try:
- return resolver.resolve(qname, "NAPTR")
- except dns.resolver.NXDOMAIN as e:
- e_nx += e
- raise e_nx
diff --git a/.venv/lib/python3.12/site-packages/dns/edns.py b/.venv/lib/python3.12/site-packages/dns/edns.py
deleted file mode 100644
index 776e5ee..0000000
--- a/.venv/lib/python3.12/site-packages/dns/edns.py
+++ /dev/null
@@ -1,516 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2009-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""EDNS Options"""
-
-import binascii
-import math
-import socket
-import struct
-from typing import Any, Dict, Optional, Union
-
-import dns.enum
-import dns.inet
-import dns.rdata
-import dns.wire
-
-
-class OptionType(dns.enum.IntEnum):
- #: NSID
- NSID = 3
- #: DAU
- DAU = 5
- #: DHU
- DHU = 6
- #: N3U
- N3U = 7
- #: ECS (client-subnet)
- ECS = 8
- #: EXPIRE
- EXPIRE = 9
- #: COOKIE
- COOKIE = 10
- #: KEEPALIVE
- KEEPALIVE = 11
- #: PADDING
- PADDING = 12
- #: CHAIN
- CHAIN = 13
- #: EDE (extended-dns-error)
- EDE = 15
-
- @classmethod
- def _maximum(cls):
- return 65535
-
-
-class Option:
- """Base class for all EDNS option types."""
-
- def __init__(self, otype: Union[OptionType, str]):
- """Initialize an option.
-
- *otype*, a ``dns.edns.OptionType``, is the option type.
- """
- self.otype = OptionType.make(otype)
-
- def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]:
- """Convert an option to wire format.
-
- Returns a ``bytes`` or ``None``.
-
- """
- raise NotImplementedError # pragma: no cover
-
- def to_text(self) -> str:
- raise NotImplementedError # pragma: no cover
-
- @classmethod
- def from_wire_parser(cls, otype: OptionType, parser: "dns.wire.Parser") -> "Option":
- """Build an EDNS option object from wire format.
-
- *otype*, a ``dns.edns.OptionType``, is the option type.
-
- *parser*, a ``dns.wire.Parser``, the parser, which should be
- restructed to the option length.
-
- Returns a ``dns.edns.Option``.
- """
- raise NotImplementedError # pragma: no cover
-
- def _cmp(self, other):
- """Compare an EDNS option with another option of the same type.
-
- Returns < 0 if < *other*, 0 if == *other*, and > 0 if > *other*.
- """
- wire = self.to_wire()
- owire = other.to_wire()
- if wire == owire:
- return 0
- if wire > owire:
- return 1
- return -1
-
- def __eq__(self, other):
- if not isinstance(other, Option):
- return False
- if self.otype != other.otype:
- return False
- return self._cmp(other) == 0
-
- def __ne__(self, other):
- if not isinstance(other, Option):
- return True
- if self.otype != other.otype:
- return True
- return self._cmp(other) != 0
-
- def __lt__(self, other):
- if not isinstance(other, Option) or self.otype != other.otype:
- return NotImplemented
- return self._cmp(other) < 0
-
- def __le__(self, other):
- if not isinstance(other, Option) or self.otype != other.otype:
- return NotImplemented
- return self._cmp(other) <= 0
-
- def __ge__(self, other):
- if not isinstance(other, Option) or self.otype != other.otype:
- return NotImplemented
- return self._cmp(other) >= 0
-
- def __gt__(self, other):
- if not isinstance(other, Option) or self.otype != other.otype:
- return NotImplemented
- return self._cmp(other) > 0
-
- def __str__(self):
- return self.to_text()
-
-
-class GenericOption(Option): # lgtm[py/missing-equals]
- """Generic Option Class
-
- This class is used for EDNS option types for which we have no better
- implementation.
- """
-
- def __init__(self, otype: Union[OptionType, str], data: Union[bytes, str]):
- super().__init__(otype)
- self.data = dns.rdata.Rdata._as_bytes(data, True)
-
- def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]:
- if file:
- file.write(self.data)
- return None
- else:
- return self.data
-
- def to_text(self) -> str:
- return "Generic %d" % self.otype
-
- @classmethod
- def from_wire_parser(
- cls, otype: Union[OptionType, str], parser: "dns.wire.Parser"
- ) -> Option:
- return cls(otype, parser.get_remaining())
-
-
-class ECSOption(Option): # lgtm[py/missing-equals]
- """EDNS Client Subnet (ECS, RFC7871)"""
-
- def __init__(self, address: str, srclen: Optional[int] = None, scopelen: int = 0):
- """*address*, a ``str``, is the client address information.
-
- *srclen*, an ``int``, the source prefix length, which is the
- leftmost number of bits of the address to be used for the
- lookup. The default is 24 for IPv4 and 56 for IPv6.
-
- *scopelen*, an ``int``, the scope prefix length. This value
- must be 0 in queries, and should be set in responses.
- """
-
- super().__init__(OptionType.ECS)
- af = dns.inet.af_for_address(address)
-
- if af == socket.AF_INET6:
- self.family = 2
- if srclen is None:
- srclen = 56
- address = dns.rdata.Rdata._as_ipv6_address(address)
- srclen = dns.rdata.Rdata._as_int(srclen, 0, 128)
- scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 128)
- elif af == socket.AF_INET:
- self.family = 1
- if srclen is None:
- srclen = 24
- address = dns.rdata.Rdata._as_ipv4_address(address)
- srclen = dns.rdata.Rdata._as_int(srclen, 0, 32)
- scopelen = dns.rdata.Rdata._as_int(scopelen, 0, 32)
- else: # pragma: no cover (this will never happen)
- raise ValueError("Bad address family")
-
- assert srclen is not None
- self.address = address
- self.srclen = srclen
- self.scopelen = scopelen
-
- addrdata = dns.inet.inet_pton(af, address)
- nbytes = int(math.ceil(srclen / 8.0))
-
- # Truncate to srclen and pad to the end of the last octet needed
- # See RFC section 6
- self.addrdata = addrdata[:nbytes]
- nbits = srclen % 8
- if nbits != 0:
- last = struct.pack("B", ord(self.addrdata[-1:]) & (0xFF << (8 - nbits)))
- self.addrdata = self.addrdata[:-1] + last
-
- def to_text(self) -> str:
- return "ECS {}/{} scope/{}".format(self.address, self.srclen, self.scopelen)
-
- @staticmethod
- def from_text(text: str) -> Option:
- """Convert a string into a `dns.edns.ECSOption`
-
- *text*, a `str`, the text form of the option.
-
- Returns a `dns.edns.ECSOption`.
-
- Examples:
-
- >>> import dns.edns
- >>>
- >>> # basic example
- >>> dns.edns.ECSOption.from_text('1.2.3.4/24')
- >>>
- >>> # also understands scope
- >>> dns.edns.ECSOption.from_text('1.2.3.4/24/32')
- >>>
- >>> # IPv6
- >>> dns.edns.ECSOption.from_text('2001:4b98::1/64/64')
- >>>
- >>> # it understands results from `dns.edns.ECSOption.to_text()`
- >>> dns.edns.ECSOption.from_text('ECS 1.2.3.4/24/32')
- """
- optional_prefix = "ECS"
- tokens = text.split()
- ecs_text = None
- if len(tokens) == 1:
- ecs_text = tokens[0]
- elif len(tokens) == 2:
- if tokens[0] != optional_prefix:
- raise ValueError('could not parse ECS from "{}"'.format(text))
- ecs_text = tokens[1]
- else:
- raise ValueError('could not parse ECS from "{}"'.format(text))
- n_slashes = ecs_text.count("/")
- if n_slashes == 1:
- address, tsrclen = ecs_text.split("/")
- tscope = "0"
- elif n_slashes == 2:
- address, tsrclen, tscope = ecs_text.split("/")
- else:
- raise ValueError('could not parse ECS from "{}"'.format(text))
- try:
- scope = int(tscope)
- except ValueError:
- raise ValueError(
- "invalid scope " + '"{}": scope must be an integer'.format(tscope)
- )
- try:
- srclen = int(tsrclen)
- except ValueError:
- raise ValueError(
- "invalid srclen " + '"{}": srclen must be an integer'.format(tsrclen)
- )
- return ECSOption(address, srclen, scope)
-
- def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]:
- value = (
- struct.pack("!HBB", self.family, self.srclen, self.scopelen) + self.addrdata
- )
- if file:
- file.write(value)
- return None
- else:
- return value
-
- @classmethod
- def from_wire_parser(
- cls, otype: Union[OptionType, str], parser: "dns.wire.Parser"
- ) -> Option:
- family, src, scope = parser.get_struct("!HBB")
- addrlen = int(math.ceil(src / 8.0))
- prefix = parser.get_bytes(addrlen)
- if family == 1:
- pad = 4 - addrlen
- addr = dns.ipv4.inet_ntoa(prefix + b"\x00" * pad)
- elif family == 2:
- pad = 16 - addrlen
- addr = dns.ipv6.inet_ntoa(prefix + b"\x00" * pad)
- else:
- raise ValueError("unsupported family")
-
- return cls(addr, src, scope)
-
-
-class EDECode(dns.enum.IntEnum):
- OTHER = 0
- UNSUPPORTED_DNSKEY_ALGORITHM = 1
- UNSUPPORTED_DS_DIGEST_TYPE = 2
- STALE_ANSWER = 3
- FORGED_ANSWER = 4
- DNSSEC_INDETERMINATE = 5
- DNSSEC_BOGUS = 6
- SIGNATURE_EXPIRED = 7
- SIGNATURE_NOT_YET_VALID = 8
- DNSKEY_MISSING = 9
- RRSIGS_MISSING = 10
- NO_ZONE_KEY_BIT_SET = 11
- NSEC_MISSING = 12
- CACHED_ERROR = 13
- NOT_READY = 14
- BLOCKED = 15
- CENSORED = 16
- FILTERED = 17
- PROHIBITED = 18
- STALE_NXDOMAIN_ANSWER = 19
- NOT_AUTHORITATIVE = 20
- NOT_SUPPORTED = 21
- NO_REACHABLE_AUTHORITY = 22
- NETWORK_ERROR = 23
- INVALID_DATA = 24
-
- @classmethod
- def _maximum(cls):
- return 65535
-
-
-class EDEOption(Option): # lgtm[py/missing-equals]
- """Extended DNS Error (EDE, RFC8914)"""
-
- _preserve_case = {"DNSKEY", "DS", "DNSSEC", "RRSIGs", "NSEC", "NXDOMAIN"}
-
- def __init__(self, code: Union[EDECode, str], text: Optional[str] = None):
- """*code*, a ``dns.edns.EDECode`` or ``str``, the info code of the
- extended error.
-
- *text*, a ``str`` or ``None``, specifying additional information about
- the error.
- """
-
- super().__init__(OptionType.EDE)
-
- self.code = EDECode.make(code)
- if text is not None and not isinstance(text, str):
- raise ValueError("text must be string or None")
- self.text = text
-
- def to_text(self) -> str:
- output = f"EDE {self.code}"
- if self.code in EDECode:
- desc = EDECode.to_text(self.code)
- desc = " ".join(
- word if word in self._preserve_case else word.title()
- for word in desc.split("_")
- )
- output += f" ({desc})"
- if self.text is not None:
- output += f": {self.text}"
- return output
-
- def to_wire(self, file: Optional[Any] = None) -> Optional[bytes]:
- value = struct.pack("!H", self.code)
- if self.text is not None:
- value += self.text.encode("utf8")
-
- if file:
- file.write(value)
- return None
- else:
- return value
-
- @classmethod
- def from_wire_parser(
- cls, otype: Union[OptionType, str], parser: "dns.wire.Parser"
- ) -> Option:
- code = EDECode.make(parser.get_uint16())
- text = parser.get_remaining()
-
- if text:
- if text[-1] == 0: # text MAY be null-terminated
- text = text[:-1]
- btext = text.decode("utf8")
- else:
- btext = None
-
- return cls(code, btext)
-
-
-class NSIDOption(Option):
- def __init__(self, nsid: bytes):
- super().__init__(OptionType.NSID)
- self.nsid = nsid
-
- def to_wire(self, file: Any = None) -> Optional[bytes]:
- if file:
- file.write(self.nsid)
- return None
- else:
- return self.nsid
-
- def to_text(self) -> str:
- if all(c >= 0x20 and c <= 0x7E for c in self.nsid):
- # All ASCII printable, so it's probably a string.
- value = self.nsid.decode()
- else:
- value = binascii.hexlify(self.nsid).decode()
- return f"NSID {value}"
-
- @classmethod
- def from_wire_parser(
- cls, otype: Union[OptionType, str], parser: dns.wire.Parser
- ) -> Option:
- return cls(parser.get_remaining())
-
-
-_type_to_class: Dict[OptionType, Any] = {
- OptionType.ECS: ECSOption,
- OptionType.EDE: EDEOption,
- OptionType.NSID: NSIDOption,
-}
-
-
-def get_option_class(otype: OptionType) -> Any:
- """Return the class for the specified option type.
-
- The GenericOption class is used if a more specific class is not
- known.
- """
-
- cls = _type_to_class.get(otype)
- if cls is None:
- cls = GenericOption
- return cls
-
-
-def option_from_wire_parser(
- otype: Union[OptionType, str], parser: "dns.wire.Parser"
-) -> Option:
- """Build an EDNS option object from wire format.
-
- *otype*, an ``int``, is the option type.
-
- *parser*, a ``dns.wire.Parser``, the parser, which should be
- restricted to the option length.
-
- Returns an instance of a subclass of ``dns.edns.Option``.
- """
- otype = OptionType.make(otype)
- cls = get_option_class(otype)
- return cls.from_wire_parser(otype, parser)
-
-
-def option_from_wire(
- otype: Union[OptionType, str], wire: bytes, current: int, olen: int
-) -> Option:
- """Build an EDNS option object from wire format.
-
- *otype*, an ``int``, is the option type.
-
- *wire*, a ``bytes``, is the wire-format message.
-
- *current*, an ``int``, is the offset in *wire* of the beginning
- of the rdata.
-
- *olen*, an ``int``, is the length of the wire-format option data
-
- Returns an instance of a subclass of ``dns.edns.Option``.
- """
- parser = dns.wire.Parser(wire, current)
- with parser.restrict_to(olen):
- return option_from_wire_parser(otype, parser)
-
-
-def register_type(implementation: Any, otype: OptionType) -> None:
- """Register the implementation of an option type.
-
- *implementation*, a ``class``, is a subclass of ``dns.edns.Option``.
-
- *otype*, an ``int``, is the option type.
- """
-
- _type_to_class[otype] = implementation
-
-
-### BEGIN generated OptionType constants
-
-NSID = OptionType.NSID
-DAU = OptionType.DAU
-DHU = OptionType.DHU
-N3U = OptionType.N3U
-ECS = OptionType.ECS
-EXPIRE = OptionType.EXPIRE
-COOKIE = OptionType.COOKIE
-KEEPALIVE = OptionType.KEEPALIVE
-PADDING = OptionType.PADDING
-CHAIN = OptionType.CHAIN
-EDE = OptionType.EDE
-
-### END generated OptionType constants
diff --git a/.venv/lib/python3.12/site-packages/dns/entropy.py b/.venv/lib/python3.12/site-packages/dns/entropy.py
deleted file mode 100644
index 4dcdc62..0000000
--- a/.venv/lib/python3.12/site-packages/dns/entropy.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2009-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import hashlib
-import os
-import random
-import threading
-import time
-from typing import Any, Optional
-
-
-class EntropyPool:
- # This is an entropy pool for Python implementations that do not
- # have a working SystemRandom. I'm not sure there are any, but
- # leaving this code doesn't hurt anything as the library code
- # is used if present.
-
- def __init__(self, seed: Optional[bytes] = None):
- self.pool_index = 0
- self.digest: Optional[bytearray] = None
- self.next_byte = 0
- self.lock = threading.Lock()
- self.hash = hashlib.sha1()
- self.hash_len = 20
- self.pool = bytearray(b"\0" * self.hash_len)
- if seed is not None:
- self._stir(seed)
- self.seeded = True
- self.seed_pid = os.getpid()
- else:
- self.seeded = False
- self.seed_pid = 0
-
- def _stir(self, entropy: bytes) -> None:
- for c in entropy:
- if self.pool_index == self.hash_len:
- self.pool_index = 0
- b = c & 0xFF
- self.pool[self.pool_index] ^= b
- self.pool_index += 1
-
- def stir(self, entropy: bytes) -> None:
- with self.lock:
- self._stir(entropy)
-
- def _maybe_seed(self) -> None:
- if not self.seeded or self.seed_pid != os.getpid():
- try:
- seed = os.urandom(16)
- except Exception: # pragma: no cover
- try:
- with open("/dev/urandom", "rb", 0) as r:
- seed = r.read(16)
- except Exception:
- seed = str(time.time()).encode()
- self.seeded = True
- self.seed_pid = os.getpid()
- self.digest = None
- seed = bytearray(seed)
- self._stir(seed)
-
- def random_8(self) -> int:
- with self.lock:
- self._maybe_seed()
- if self.digest is None or self.next_byte == self.hash_len:
- self.hash.update(bytes(self.pool))
- self.digest = bytearray(self.hash.digest())
- self._stir(self.digest)
- self.next_byte = 0
- value = self.digest[self.next_byte]
- self.next_byte += 1
- return value
-
- def random_16(self) -> int:
- return self.random_8() * 256 + self.random_8()
-
- def random_32(self) -> int:
- return self.random_16() * 65536 + self.random_16()
-
- def random_between(self, first: int, last: int) -> int:
- size = last - first + 1
- if size > 4294967296:
- raise ValueError("too big")
- if size > 65536:
- rand = self.random_32
- max = 4294967295
- elif size > 256:
- rand = self.random_16
- max = 65535
- else:
- rand = self.random_8
- max = 255
- return first + size * rand() // (max + 1)
-
-
-pool = EntropyPool()
-
-system_random: Optional[Any]
-try:
- system_random = random.SystemRandom()
-except Exception: # pragma: no cover
- system_random = None
-
-
-def random_16() -> int:
- if system_random is not None:
- return system_random.randrange(0, 65536)
- else:
- return pool.random_16()
-
-
-def between(first: int, last: int) -> int:
- if system_random is not None:
- return system_random.randrange(first, last + 1)
- else:
- return pool.random_between(first, last)
diff --git a/.venv/lib/python3.12/site-packages/dns/enum.py b/.venv/lib/python3.12/site-packages/dns/enum.py
deleted file mode 100644
index 71461f1..0000000
--- a/.venv/lib/python3.12/site-packages/dns/enum.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import enum
-from typing import Type, TypeVar, Union
-
-TIntEnum = TypeVar("TIntEnum", bound="IntEnum")
-
-
-class IntEnum(enum.IntEnum):
- @classmethod
- def _missing_(cls, value):
- cls._check_value(value)
- val = int.__new__(cls, value)
- val._name_ = cls._extra_to_text(value, None) or f"{cls._prefix()}{value}"
- val._value_ = value
- return val
-
- @classmethod
- def _check_value(cls, value):
- max = cls._maximum()
- if not isinstance(value, int):
- raise TypeError
- if value < 0 or value > max:
- name = cls._short_name()
- raise ValueError(f"{name} must be an int between >= 0 and <= {max}")
-
- @classmethod
- def from_text(cls: Type[TIntEnum], text: str) -> TIntEnum:
- text = text.upper()
- try:
- return cls[text]
- except KeyError:
- pass
- value = cls._extra_from_text(text)
- if value:
- return value
- prefix = cls._prefix()
- if text.startswith(prefix) and text[len(prefix) :].isdigit():
- value = int(text[len(prefix) :])
- cls._check_value(value)
- try:
- return cls(value)
- except ValueError:
- return value
- raise cls._unknown_exception_class()
-
- @classmethod
- def to_text(cls: Type[TIntEnum], value: int) -> str:
- cls._check_value(value)
- try:
- text = cls(value).name
- except ValueError:
- text = None
- text = cls._extra_to_text(value, text)
- if text is None:
- text = f"{cls._prefix()}{value}"
- return text
-
- @classmethod
- def make(cls: Type[TIntEnum], value: Union[int, str]) -> TIntEnum:
- """Convert text or a value into an enumerated type, if possible.
-
- *value*, the ``int`` or ``str`` to convert.
-
- Raises a class-specific exception if a ``str`` is provided that
- cannot be converted.
-
- Raises ``ValueError`` if the value is out of range.
-
- Returns an enumeration from the calling class corresponding to the
- value, if one is defined, or an ``int`` otherwise.
- """
-
- if isinstance(value, str):
- return cls.from_text(value)
- cls._check_value(value)
- return cls(value)
-
- @classmethod
- def _maximum(cls):
- raise NotImplementedError # pragma: no cover
-
- @classmethod
- def _short_name(cls):
- return cls.__name__.lower()
-
- @classmethod
- def _prefix(cls):
- return ""
-
- @classmethod
- def _extra_from_text(cls, text): # pylint: disable=W0613
- return None
-
- @classmethod
- def _extra_to_text(cls, value, current_text): # pylint: disable=W0613
- return current_text
-
- @classmethod
- def _unknown_exception_class(cls):
- return ValueError
diff --git a/.venv/lib/python3.12/site-packages/dns/exception.py b/.venv/lib/python3.12/site-packages/dns/exception.py
deleted file mode 100644
index 6982373..0000000
--- a/.venv/lib/python3.12/site-packages/dns/exception.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Common DNS Exceptions.
-
-Dnspython modules may also define their own exceptions, which will
-always be subclasses of ``DNSException``.
-"""
-
-
-from typing import Optional, Set
-
-
-class DNSException(Exception):
- """Abstract base class shared by all dnspython exceptions.
-
- It supports two basic modes of operation:
-
- a) Old/compatible mode is used if ``__init__`` was called with
- empty *kwargs*. In compatible mode all *args* are passed
- to the standard Python Exception class as before and all *args* are
- printed by the standard ``__str__`` implementation. Class variable
- ``msg`` (or doc string if ``msg`` is ``None``) is returned from ``str()``
- if *args* is empty.
-
- b) New/parametrized mode is used if ``__init__`` was called with
- non-empty *kwargs*.
- In the new mode *args* must be empty and all kwargs must match
- those set in class variable ``supp_kwargs``. All kwargs are stored inside
- ``self.kwargs`` and used in a new ``__str__`` implementation to construct
- a formatted message based on the ``fmt`` class variable, a ``string``.
-
- In the simplest case it is enough to override the ``supp_kwargs``
- and ``fmt`` class variables to get nice parametrized messages.
- """
-
- msg: Optional[str] = None # non-parametrized message
- supp_kwargs: Set[str] = set() # accepted parameters for _fmt_kwargs (sanity check)
- fmt: Optional[str] = None # message parametrized with results from _fmt_kwargs
-
- def __init__(self, *args, **kwargs):
- self._check_params(*args, **kwargs)
- if kwargs:
- # This call to a virtual method from __init__ is ok in our usage
- self.kwargs = self._check_kwargs(**kwargs) # lgtm[py/init-calls-subclass]
- self.msg = str(self)
- else:
- self.kwargs = dict() # defined but empty for old mode exceptions
- if self.msg is None:
- # doc string is better implicit message than empty string
- self.msg = self.__doc__
- if args:
- super().__init__(*args)
- else:
- super().__init__(self.msg)
-
- def _check_params(self, *args, **kwargs):
- """Old exceptions supported only args and not kwargs.
-
- For sanity we do not allow to mix old and new behavior."""
- if args or kwargs:
- assert bool(args) != bool(
- kwargs
- ), "keyword arguments are mutually exclusive with positional args"
-
- def _check_kwargs(self, **kwargs):
- if kwargs:
- assert (
- set(kwargs.keys()) == self.supp_kwargs
- ), "following set of keyword args is required: %s" % (self.supp_kwargs)
- return kwargs
-
- def _fmt_kwargs(self, **kwargs):
- """Format kwargs before printing them.
-
- Resulting dictionary has to have keys necessary for str.format call
- on fmt class variable.
- """
- fmtargs = {}
- for kw, data in kwargs.items():
- if isinstance(data, (list, set)):
- # convert list of to list of str()
- fmtargs[kw] = list(map(str, data))
- if len(fmtargs[kw]) == 1:
- # remove list brackets [] from single-item lists
- fmtargs[kw] = fmtargs[kw].pop()
- else:
- fmtargs[kw] = data
- return fmtargs
-
- def __str__(self):
- if self.kwargs and self.fmt:
- # provide custom message constructed from keyword arguments
- fmtargs = self._fmt_kwargs(**self.kwargs)
- return self.fmt.format(**fmtargs)
- else:
- # print *args directly in the same way as old DNSException
- return super().__str__()
-
-
-class FormError(DNSException):
- """DNS message is malformed."""
-
-
-class SyntaxError(DNSException):
- """Text input is malformed."""
-
-
-class UnexpectedEnd(SyntaxError):
- """Text input ended unexpectedly."""
-
-
-class TooBig(DNSException):
- """The DNS message is too big."""
-
-
-class Timeout(DNSException):
- """The DNS operation timed out."""
-
- supp_kwargs = {"timeout"}
- fmt = "The DNS operation timed out after {timeout:.3f} seconds"
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
-
-class UnsupportedAlgorithm(DNSException):
- """The DNSSEC algorithm is not supported."""
-
-
-class AlgorithmKeyMismatch(UnsupportedAlgorithm):
- """The DNSSEC algorithm is not supported for the given key type."""
-
-
-class ValidationFailure(DNSException):
- """The DNSSEC signature is invalid."""
-
-
-class DeniedByPolicy(DNSException):
- """Denied by DNSSEC policy."""
-
-
-class ExceptionWrapper:
- def __init__(self, exception_class):
- self.exception_class = exception_class
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- if exc_type is not None and not isinstance(exc_val, self.exception_class):
- raise self.exception_class(str(exc_val)) from exc_val
- return False
diff --git a/.venv/lib/python3.12/site-packages/dns/flags.py b/.venv/lib/python3.12/site-packages/dns/flags.py
deleted file mode 100644
index 4c60be1..0000000
--- a/.venv/lib/python3.12/site-packages/dns/flags.py
+++ /dev/null
@@ -1,123 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Message Flags."""
-
-import enum
-from typing import Any
-
-# Standard DNS flags
-
-
-class Flag(enum.IntFlag):
- #: Query Response
- QR = 0x8000
- #: Authoritative Answer
- AA = 0x0400
- #: Truncated Response
- TC = 0x0200
- #: Recursion Desired
- RD = 0x0100
- #: Recursion Available
- RA = 0x0080
- #: Authentic Data
- AD = 0x0020
- #: Checking Disabled
- CD = 0x0010
-
-
-# EDNS flags
-
-
-class EDNSFlag(enum.IntFlag):
- #: DNSSEC answer OK
- DO = 0x8000
-
-
-def _from_text(text: str, enum_class: Any) -> int:
- flags = 0
- tokens = text.split()
- for t in tokens:
- flags |= enum_class[t.upper()]
- return flags
-
-
-def _to_text(flags: int, enum_class: Any) -> str:
- text_flags = []
- for k, v in enum_class.__members__.items():
- if flags & v != 0:
- text_flags.append(k)
- return " ".join(text_flags)
-
-
-def from_text(text: str) -> int:
- """Convert a space-separated list of flag text values into a flags
- value.
-
- Returns an ``int``
- """
-
- return _from_text(text, Flag)
-
-
-def to_text(flags: int) -> str:
- """Convert a flags value into a space-separated list of flag text
- values.
-
- Returns a ``str``.
- """
-
- return _to_text(flags, Flag)
-
-
-def edns_from_text(text: str) -> int:
- """Convert a space-separated list of EDNS flag text values into a EDNS
- flags value.
-
- Returns an ``int``
- """
-
- return _from_text(text, EDNSFlag)
-
-
-def edns_to_text(flags: int) -> str:
- """Convert an EDNS flags value into a space-separated list of EDNS flag
- text values.
-
- Returns a ``str``.
- """
-
- return _to_text(flags, EDNSFlag)
-
-
-### BEGIN generated Flag constants
-
-QR = Flag.QR
-AA = Flag.AA
-TC = Flag.TC
-RD = Flag.RD
-RA = Flag.RA
-AD = Flag.AD
-CD = Flag.CD
-
-### END generated Flag constants
-
-### BEGIN generated EDNSFlag constants
-
-DO = EDNSFlag.DO
-
-### END generated EDNSFlag constants
diff --git a/.venv/lib/python3.12/site-packages/dns/grange.py b/.venv/lib/python3.12/site-packages/dns/grange.py
deleted file mode 100644
index 3a52278..0000000
--- a/.venv/lib/python3.12/site-packages/dns/grange.py
+++ /dev/null
@@ -1,72 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2012-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS GENERATE range conversion."""
-
-from typing import Tuple
-
-import dns
-
-
-def from_text(text: str) -> Tuple[int, int, int]:
- """Convert the text form of a range in a ``$GENERATE`` statement to an
- integer.
-
- *text*, a ``str``, the textual range in ``$GENERATE`` form.
-
- Returns a tuple of three ``int`` values ``(start, stop, step)``.
- """
-
- start = -1
- stop = -1
- step = 1
- cur = ""
- state = 0
- # state 0 1 2
- # x - y / z
-
- if text and text[0] == "-":
- raise dns.exception.SyntaxError("Start cannot be a negative number")
-
- for c in text:
- if c == "-" and state == 0:
- start = int(cur)
- cur = ""
- state = 1
- elif c == "/":
- stop = int(cur)
- cur = ""
- state = 2
- elif c.isdigit():
- cur += c
- else:
- raise dns.exception.SyntaxError("Could not parse %s" % (c))
-
- if state == 0:
- raise dns.exception.SyntaxError("no stop value specified")
- elif state == 1:
- stop = int(cur)
- else:
- assert state == 2
- step = int(cur)
-
- assert step >= 1
- assert start >= 0
- if start > stop:
- raise dns.exception.SyntaxError("start must be <= stop")
-
- return (start, stop, step)
diff --git a/.venv/lib/python3.12/site-packages/dns/immutable.py b/.venv/lib/python3.12/site-packages/dns/immutable.py
deleted file mode 100644
index 36b0362..0000000
--- a/.venv/lib/python3.12/site-packages/dns/immutable.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import collections.abc
-from typing import Any, Callable
-
-from dns._immutable_ctx import immutable
-
-
-@immutable
-class Dict(collections.abc.Mapping): # lgtm[py/missing-equals]
- def __init__(
- self,
- dictionary: Any,
- no_copy: bool = False,
- map_factory: Callable[[], collections.abc.MutableMapping] = dict,
- ):
- """Make an immutable dictionary from the specified dictionary.
-
- If *no_copy* is `True`, then *dictionary* will be wrapped instead
- of copied. Only set this if you are sure there will be no external
- references to the dictionary.
- """
- if no_copy and isinstance(dictionary, collections.abc.MutableMapping):
- self._odict = dictionary
- else:
- self._odict = map_factory()
- self._odict.update(dictionary)
- self._hash = None
-
- def __getitem__(self, key):
- return self._odict.__getitem__(key)
-
- def __hash__(self): # pylint: disable=invalid-hash-returned
- if self._hash is None:
- h = 0
- for key in sorted(self._odict.keys()):
- h ^= hash(key)
- object.__setattr__(self, "_hash", h)
- # this does return an int, but pylint doesn't figure that out
- return self._hash
-
- def __len__(self):
- return len(self._odict)
-
- def __iter__(self):
- return iter(self._odict)
-
-
-def constify(o: Any) -> Any:
- """
- Convert mutable types to immutable types.
- """
- if isinstance(o, bytearray):
- return bytes(o)
- if isinstance(o, tuple):
- try:
- hash(o)
- return o
- except Exception:
- return tuple(constify(elt) for elt in o)
- if isinstance(o, list):
- return tuple(constify(elt) for elt in o)
- if isinstance(o, dict):
- cdict = dict()
- for k, v in o.items():
- cdict[k] = constify(v)
- return Dict(cdict, True)
- return o
diff --git a/.venv/lib/python3.12/site-packages/dns/inet.py b/.venv/lib/python3.12/site-packages/dns/inet.py
deleted file mode 100644
index 4a03f99..0000000
--- a/.venv/lib/python3.12/site-packages/dns/inet.py
+++ /dev/null
@@ -1,197 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Generic Internet address helper functions."""
-
-import socket
-from typing import Any, Optional, Tuple
-
-import dns.ipv4
-import dns.ipv6
-
-# We assume that AF_INET and AF_INET6 are always defined. We keep
-# these here for the benefit of any old code (unlikely though that
-# is!).
-AF_INET = socket.AF_INET
-AF_INET6 = socket.AF_INET6
-
-
-def inet_pton(family: int, text: str) -> bytes:
- """Convert the textual form of a network address into its binary form.
-
- *family* is an ``int``, the address family.
-
- *text* is a ``str``, the textual address.
-
- Raises ``NotImplementedError`` if the address family specified is not
- implemented.
-
- Returns a ``bytes``.
- """
-
- if family == AF_INET:
- return dns.ipv4.inet_aton(text)
- elif family == AF_INET6:
- return dns.ipv6.inet_aton(text, True)
- else:
- raise NotImplementedError
-
-
-def inet_ntop(family: int, address: bytes) -> str:
- """Convert the binary form of a network address into its textual form.
-
- *family* is an ``int``, the address family.
-
- *address* is a ``bytes``, the network address in binary form.
-
- Raises ``NotImplementedError`` if the address family specified is not
- implemented.
-
- Returns a ``str``.
- """
-
- if family == AF_INET:
- return dns.ipv4.inet_ntoa(address)
- elif family == AF_INET6:
- return dns.ipv6.inet_ntoa(address)
- else:
- raise NotImplementedError
-
-
-def af_for_address(text: str) -> int:
- """Determine the address family of a textual-form network address.
-
- *text*, a ``str``, the textual address.
-
- Raises ``ValueError`` if the address family cannot be determined
- from the input.
-
- Returns an ``int``.
- """
-
- try:
- dns.ipv4.inet_aton(text)
- return AF_INET
- except Exception:
- try:
- dns.ipv6.inet_aton(text, True)
- return AF_INET6
- except Exception:
- raise ValueError
-
-
-def is_multicast(text: str) -> bool:
- """Is the textual-form network address a multicast address?
-
- *text*, a ``str``, the textual address.
-
- Raises ``ValueError`` if the address family cannot be determined
- from the input.
-
- Returns a ``bool``.
- """
-
- try:
- first = dns.ipv4.inet_aton(text)[0]
- return first >= 224 and first <= 239
- except Exception:
- try:
- first = dns.ipv6.inet_aton(text, True)[0]
- return first == 255
- except Exception:
- raise ValueError
-
-
-def is_address(text: str) -> bool:
- """Is the specified string an IPv4 or IPv6 address?
-
- *text*, a ``str``, the textual address.
-
- Returns a ``bool``.
- """
-
- try:
- dns.ipv4.inet_aton(text)
- return True
- except Exception:
- try:
- dns.ipv6.inet_aton(text, True)
- return True
- except Exception:
- return False
-
-
-def low_level_address_tuple(
- high_tuple: Tuple[str, int], af: Optional[int] = None
-) -> Any:
- """Given a "high-level" address tuple, i.e.
- an (address, port) return the appropriate "low-level" address tuple
- suitable for use in socket calls.
-
- If an *af* other than ``None`` is provided, it is assumed the
- address in the high-level tuple is valid and has that af. If af
- is ``None``, then af_for_address will be called.
- """
- address, port = high_tuple
- if af is None:
- af = af_for_address(address)
- if af == AF_INET:
- return (address, port)
- elif af == AF_INET6:
- i = address.find("%")
- if i < 0:
- # no scope, shortcut!
- return (address, port, 0, 0)
- # try to avoid getaddrinfo()
- addrpart = address[:i]
- scope = address[i + 1 :]
- if scope.isdigit():
- return (addrpart, port, 0, int(scope))
- try:
- return (addrpart, port, 0, socket.if_nametoindex(scope))
- except AttributeError: # pragma: no cover (we can't really test this)
- ai_flags = socket.AI_NUMERICHOST
- ((*_, tup), *_) = socket.getaddrinfo(address, port, flags=ai_flags)
- return tup
- else:
- raise NotImplementedError(f"unknown address family {af}")
-
-
-def any_for_af(af):
- """Return the 'any' address for the specified address family."""
- if af == socket.AF_INET:
- return "0.0.0.0"
- elif af == socket.AF_INET6:
- return "::"
- raise NotImplementedError(f"unknown address family {af}")
-
-
-def canonicalize(text: str) -> str:
- """Verify that *address* is a valid text form IPv4 or IPv6 address and return its
- canonical text form. IPv6 addresses with scopes are rejected.
-
- *text*, a ``str``, the address in textual form.
-
- Raises ``ValueError`` if the text is not valid.
- """
- try:
- return dns.ipv6.canonicalize(text)
- except Exception:
- try:
- return dns.ipv4.canonicalize(text)
- except Exception:
- raise ValueError
diff --git a/.venv/lib/python3.12/site-packages/dns/ipv4.py b/.venv/lib/python3.12/site-packages/dns/ipv4.py
deleted file mode 100644
index 65ee69c..0000000
--- a/.venv/lib/python3.12/site-packages/dns/ipv4.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""IPv4 helper functions."""
-
-import struct
-from typing import Union
-
-import dns.exception
-
-
-def inet_ntoa(address: bytes) -> str:
- """Convert an IPv4 address in binary form to text form.
-
- *address*, a ``bytes``, the IPv4 address in binary form.
-
- Returns a ``str``.
- """
-
- if len(address) != 4:
- raise dns.exception.SyntaxError
- return "%u.%u.%u.%u" % (address[0], address[1], address[2], address[3])
-
-
-def inet_aton(text: Union[str, bytes]) -> bytes:
- """Convert an IPv4 address in text form to binary form.
-
- *text*, a ``str`` or ``bytes``, the IPv4 address in textual form.
-
- Returns a ``bytes``.
- """
-
- if not isinstance(text, bytes):
- btext = text.encode()
- else:
- btext = text
- parts = btext.split(b".")
- if len(parts) != 4:
- raise dns.exception.SyntaxError
- for part in parts:
- if not part.isdigit():
- raise dns.exception.SyntaxError
- if len(part) > 1 and part[0] == ord("0"):
- # No leading zeros
- raise dns.exception.SyntaxError
- try:
- b = [int(part) for part in parts]
- return struct.pack("BBBB", *b)
- except Exception:
- raise dns.exception.SyntaxError
-
-
-def canonicalize(text: Union[str, bytes]) -> str:
- """Verify that *address* is a valid text form IPv4 address and return its
- canonical text form.
-
- *text*, a ``str`` or ``bytes``, the IPv4 address in textual form.
-
- Raises ``dns.exception.SyntaxError`` if the text is not valid.
- """
- # Note that inet_aton() only accepts canonial form, but we still run through
- # inet_ntoa() to ensure the output is a str.
- return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text))
diff --git a/.venv/lib/python3.12/site-packages/dns/ipv6.py b/.venv/lib/python3.12/site-packages/dns/ipv6.py
deleted file mode 100644
index 44a1063..0000000
--- a/.venv/lib/python3.12/site-packages/dns/ipv6.py
+++ /dev/null
@@ -1,219 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""IPv6 helper functions."""
-
-import binascii
-import re
-from typing import List, Union
-
-import dns.exception
-import dns.ipv4
-
-_leading_zero = re.compile(r"0+([0-9a-f]+)")
-
-
-def inet_ntoa(address: bytes) -> str:
- """Convert an IPv6 address in binary form to text form.
-
- *address*, a ``bytes``, the IPv6 address in binary form.
-
- Raises ``ValueError`` if the address isn't 16 bytes long.
- Returns a ``str``.
- """
-
- if len(address) != 16:
- raise ValueError("IPv6 addresses are 16 bytes long")
- hex = binascii.hexlify(address)
- chunks = []
- i = 0
- l = len(hex)
- while i < l:
- chunk = hex[i : i + 4].decode()
- # strip leading zeros. we do this with an re instead of
- # with lstrip() because lstrip() didn't support chars until
- # python 2.2.2
- m = _leading_zero.match(chunk)
- if m is not None:
- chunk = m.group(1)
- chunks.append(chunk)
- i += 4
- #
- # Compress the longest subsequence of 0-value chunks to ::
- #
- best_start = 0
- best_len = 0
- start = -1
- last_was_zero = False
- for i in range(8):
- if chunks[i] != "0":
- if last_was_zero:
- end = i
- current_len = end - start
- if current_len > best_len:
- best_start = start
- best_len = current_len
- last_was_zero = False
- elif not last_was_zero:
- start = i
- last_was_zero = True
- if last_was_zero:
- end = 8
- current_len = end - start
- if current_len > best_len:
- best_start = start
- best_len = current_len
- if best_len > 1:
- if best_start == 0 and (best_len == 6 or best_len == 5 and chunks[5] == "ffff"):
- # We have an embedded IPv4 address
- if best_len == 6:
- prefix = "::"
- else:
- prefix = "::ffff:"
- thex = prefix + dns.ipv4.inet_ntoa(address[12:])
- else:
- thex = (
- ":".join(chunks[:best_start])
- + "::"
- + ":".join(chunks[best_start + best_len :])
- )
- else:
- thex = ":".join(chunks)
- return thex
-
-
-_v4_ending = re.compile(rb"(.*):(\d+\.\d+\.\d+\.\d+)$")
-_colon_colon_start = re.compile(rb"::.*")
-_colon_colon_end = re.compile(rb".*::$")
-
-
-def inet_aton(text: Union[str, bytes], ignore_scope: bool = False) -> bytes:
- """Convert an IPv6 address in text form to binary form.
-
- *text*, a ``str`` or ``bytes``, the IPv6 address in textual form.
-
- *ignore_scope*, a ``bool``. If ``True``, a scope will be ignored.
- If ``False``, the default, it is an error for a scope to be present.
-
- Returns a ``bytes``.
- """
-
- #
- # Our aim here is not something fast; we just want something that works.
- #
- if not isinstance(text, bytes):
- btext = text.encode()
- else:
- btext = text
-
- if ignore_scope:
- parts = btext.split(b"%")
- l = len(parts)
- if l == 2:
- btext = parts[0]
- elif l > 2:
- raise dns.exception.SyntaxError
-
- if btext == b"":
- raise dns.exception.SyntaxError
- elif btext.endswith(b":") and not btext.endswith(b"::"):
- raise dns.exception.SyntaxError
- elif btext.startswith(b":") and not btext.startswith(b"::"):
- raise dns.exception.SyntaxError
- elif btext == b"::":
- btext = b"0::"
- #
- # Get rid of the icky dot-quad syntax if we have it.
- #
- m = _v4_ending.match(btext)
- if m is not None:
- b = dns.ipv4.inet_aton(m.group(2))
- btext = (
- "{}:{:02x}{:02x}:{:02x}{:02x}".format(
- m.group(1).decode(), b[0], b[1], b[2], b[3]
- )
- ).encode()
- #
- # Try to turn '::' into ':'; if no match try to
- # turn '::' into ':'
- #
- m = _colon_colon_start.match(btext)
- if m is not None:
- btext = btext[1:]
- else:
- m = _colon_colon_end.match(btext)
- if m is not None:
- btext = btext[:-1]
- #
- # Now canonicalize into 8 chunks of 4 hex digits each
- #
- chunks = btext.split(b":")
- l = len(chunks)
- if l > 8:
- raise dns.exception.SyntaxError
- seen_empty = False
- canonical: List[bytes] = []
- for c in chunks:
- if c == b"":
- if seen_empty:
- raise dns.exception.SyntaxError
- seen_empty = True
- for _ in range(0, 8 - l + 1):
- canonical.append(b"0000")
- else:
- lc = len(c)
- if lc > 4:
- raise dns.exception.SyntaxError
- if lc != 4:
- c = (b"0" * (4 - lc)) + c
- canonical.append(c)
- if l < 8 and not seen_empty:
- raise dns.exception.SyntaxError
- btext = b"".join(canonical)
-
- #
- # Finally we can go to binary.
- #
- try:
- return binascii.unhexlify(btext)
- except (binascii.Error, TypeError):
- raise dns.exception.SyntaxError
-
-
-_mapped_prefix = b"\x00" * 10 + b"\xff\xff"
-
-
-def is_mapped(address: bytes) -> bool:
- """Is the specified address a mapped IPv4 address?
-
- *address*, a ``bytes`` is an IPv6 address in binary form.
-
- Returns a ``bool``.
- """
-
- return address.startswith(_mapped_prefix)
-
-
-def canonicalize(text: Union[str, bytes]) -> str:
- """Verify that *address* is a valid text form IPv6 address and return its
- canonical text form. Addresses with scopes are rejected.
-
- *text*, a ``str`` or ``bytes``, the IPv6 address in textual form.
-
- Raises ``dns.exception.SyntaxError`` if the text is not valid.
- """
- return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
diff --git a/.venv/lib/python3.12/site-packages/dns/message.py b/.venv/lib/python3.12/site-packages/dns/message.py
deleted file mode 100644
index 44cacbd..0000000
--- a/.venv/lib/python3.12/site-packages/dns/message.py
+++ /dev/null
@@ -1,1888 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Messages"""
-
-import contextlib
-import io
-import time
-from typing import Any, Dict, List, Optional, Tuple, Union
-
-import dns.edns
-import dns.entropy
-import dns.enum
-import dns.exception
-import dns.flags
-import dns.name
-import dns.opcode
-import dns.rcode
-import dns.rdata
-import dns.rdataclass
-import dns.rdatatype
-import dns.rdtypes.ANY.OPT
-import dns.rdtypes.ANY.TSIG
-import dns.renderer
-import dns.rrset
-import dns.tsig
-import dns.ttl
-import dns.wire
-
-
-class ShortHeader(dns.exception.FormError):
- """The DNS packet passed to from_wire() is too short."""
-
-
-class TrailingJunk(dns.exception.FormError):
- """The DNS packet passed to from_wire() has extra junk at the end of it."""
-
-
-class UnknownHeaderField(dns.exception.DNSException):
- """The header field name was not recognized when converting from text
- into a message."""
-
-
-class BadEDNS(dns.exception.FormError):
- """An OPT record occurred somewhere other than
- the additional data section."""
-
-
-class BadTSIG(dns.exception.FormError):
- """A TSIG record occurred somewhere other than the end of
- the additional data section."""
-
-
-class UnknownTSIGKey(dns.exception.DNSException):
- """A TSIG with an unknown key was received."""
-
-
-class Truncated(dns.exception.DNSException):
- """The truncated flag is set."""
-
- supp_kwargs = {"message"}
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def message(self):
- """As much of the message as could be processed.
-
- Returns a ``dns.message.Message``.
- """
- return self.kwargs["message"]
-
-
-class NotQueryResponse(dns.exception.DNSException):
- """Message is not a response to a query."""
-
-
-class ChainTooLong(dns.exception.DNSException):
- """The CNAME chain is too long."""
-
-
-class AnswerForNXDOMAIN(dns.exception.DNSException):
- """The rcode is NXDOMAIN but an answer was found."""
-
-
-class NoPreviousName(dns.exception.SyntaxError):
- """No previous name was known."""
-
-
-class MessageSection(dns.enum.IntEnum):
- """Message sections"""
-
- QUESTION = 0
- ANSWER = 1
- AUTHORITY = 2
- ADDITIONAL = 3
-
- @classmethod
- def _maximum(cls):
- return 3
-
-
-class MessageError:
- def __init__(self, exception: Exception, offset: int):
- self.exception = exception
- self.offset = offset
-
-
-DEFAULT_EDNS_PAYLOAD = 1232
-MAX_CHAIN = 16
-
-IndexKeyType = Tuple[
- int,
- dns.name.Name,
- dns.rdataclass.RdataClass,
- dns.rdatatype.RdataType,
- Optional[dns.rdatatype.RdataType],
- Optional[dns.rdataclass.RdataClass],
-]
-IndexType = Dict[IndexKeyType, dns.rrset.RRset]
-SectionType = Union[int, str, List[dns.rrset.RRset]]
-
-
-class Message:
- """A DNS message."""
-
- _section_enum = MessageSection
-
- def __init__(self, id: Optional[int] = None):
- if id is None:
- self.id = dns.entropy.random_16()
- else:
- self.id = id
- self.flags = 0
- self.sections: List[List[dns.rrset.RRset]] = [[], [], [], []]
- self.opt: Optional[dns.rrset.RRset] = None
- self.request_payload = 0
- self.pad = 0
- self.keyring: Any = None
- self.tsig: Optional[dns.rrset.RRset] = None
- self.request_mac = b""
- self.xfr = False
- self.origin: Optional[dns.name.Name] = None
- self.tsig_ctx: Optional[Any] = None
- self.index: IndexType = {}
- self.errors: List[MessageError] = []
- self.time = 0.0
-
- @property
- def question(self) -> List[dns.rrset.RRset]:
- """The question section."""
- return self.sections[0]
-
- @question.setter
- def question(self, v):
- self.sections[0] = v
-
- @property
- def answer(self) -> List[dns.rrset.RRset]:
- """The answer section."""
- return self.sections[1]
-
- @answer.setter
- def answer(self, v):
- self.sections[1] = v
-
- @property
- def authority(self) -> List[dns.rrset.RRset]:
- """The authority section."""
- return self.sections[2]
-
- @authority.setter
- def authority(self, v):
- self.sections[2] = v
-
- @property
- def additional(self) -> List[dns.rrset.RRset]:
- """The additional data section."""
- return self.sections[3]
-
- @additional.setter
- def additional(self, v):
- self.sections[3] = v
-
- def __repr__(self):
- return ""
-
- def __str__(self):
- return self.to_text()
-
- def to_text(
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- **kw: Dict[str, Any],
- ) -> str:
- """Convert the message to text.
-
- The *origin*, *relativize*, and any other keyword
- arguments are passed to the RRset ``to_wire()`` method.
-
- Returns a ``str``.
- """
-
- s = io.StringIO()
- s.write("id %d\n" % self.id)
- s.write("opcode %s\n" % dns.opcode.to_text(self.opcode()))
- s.write("rcode %s\n" % dns.rcode.to_text(self.rcode()))
- s.write("flags %s\n" % dns.flags.to_text(self.flags))
- if self.edns >= 0:
- s.write("edns %s\n" % self.edns)
- if self.ednsflags != 0:
- s.write("eflags %s\n" % dns.flags.edns_to_text(self.ednsflags))
- s.write("payload %d\n" % self.payload)
- for opt in self.options:
- s.write("option %s\n" % opt.to_text())
- for name, which in self._section_enum.__members__.items():
- s.write(f";{name}\n")
- for rrset in self.section_from_number(which):
- s.write(rrset.to_text(origin, relativize, **kw))
- s.write("\n")
- #
- # We strip off the final \n so the caller can print the result without
- # doing weird things to get around eccentricities in Python print
- # formatting
- #
- return s.getvalue()[:-1]
-
- def __eq__(self, other):
- """Two messages are equal if they have the same content in the
- header, question, answer, and authority sections.
-
- Returns a ``bool``.
- """
-
- if not isinstance(other, Message):
- return False
- if self.id != other.id:
- return False
- if self.flags != other.flags:
- return False
- for i, section in enumerate(self.sections):
- other_section = other.sections[i]
- for n in section:
- if n not in other_section:
- return False
- for n in other_section:
- if n not in section:
- return False
- return True
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def is_response(self, other: "Message") -> bool:
- """Is *other*, also a ``dns.message.Message``, a response to this
- message?
-
- Returns a ``bool``.
- """
-
- if (
- other.flags & dns.flags.QR == 0
- or self.id != other.id
- or dns.opcode.from_flags(self.flags) != dns.opcode.from_flags(other.flags)
- ):
- return False
- if other.rcode() in {
- dns.rcode.FORMERR,
- dns.rcode.SERVFAIL,
- dns.rcode.NOTIMP,
- dns.rcode.REFUSED,
- }:
- # We don't check the question section in these cases if
- # the other question section is empty, even though they
- # still really ought to have a question section.
- if len(other.question) == 0:
- return True
- if dns.opcode.is_update(self.flags):
- # This is assuming the "sender doesn't include anything
- # from the update", but we don't care to check the other
- # case, which is that all the sections are returned and
- # identical.
- return True
- for n in self.question:
- if n not in other.question:
- return False
- for n in other.question:
- if n not in self.question:
- return False
- return True
-
- def section_number(self, section: List[dns.rrset.RRset]) -> int:
- """Return the "section number" of the specified section for use
- in indexing.
-
- *section* is one of the section attributes of this message.
-
- Raises ``ValueError`` if the section isn't known.
-
- Returns an ``int``.
- """
-
- for i, our_section in enumerate(self.sections):
- if section is our_section:
- return self._section_enum(i)
- raise ValueError("unknown section")
-
- def section_from_number(self, number: int) -> List[dns.rrset.RRset]:
- """Return the section list associated with the specified section
- number.
-
- *number* is a section number `int` or the text form of a section
- name.
-
- Raises ``ValueError`` if the section isn't known.
-
- Returns a ``list``.
- """
-
- section = self._section_enum.make(number)
- return self.sections[section]
-
- def find_rrset(
- self,
- section: SectionType,
- name: dns.name.Name,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- deleting: Optional[dns.rdataclass.RdataClass] = None,
- create: bool = False,
- force_unique: bool = False,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- ) -> dns.rrset.RRset:
- """Find the RRset with the given attributes in the specified section.
-
- *section*, an ``int`` section number, a ``str`` section name, or one of
- the section attributes of this message. This specifies the
- the section of the message to search. For example::
-
- my_message.find_rrset(my_message.answer, name, rdclass, rdtype)
- my_message.find_rrset(dns.message.ANSWER, name, rdclass, rdtype)
- my_message.find_rrset("ANSWER", name, rdclass, rdtype)
-
- *name*, a ``dns.name.Name`` or ``str``, the name of the RRset.
-
- *rdclass*, an ``int`` or ``str``, the class of the RRset.
-
- *rdtype*, an ``int`` or ``str``, the type of the RRset.
-
- *covers*, an ``int`` or ``str``, the covers value of the RRset.
- The default is ``dns.rdatatype.NONE``.
-
- *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the
- RRset. The default is ``None``.
-
- *create*, a ``bool``. If ``True``, create the RRset if it is not found.
- The created RRset is appended to *section*.
-
- *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``,
- create a new RRset regardless of whether a matching RRset exists
- already. The default is ``False``. This is useful when creating
- DDNS Update messages, as order matters for them.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- Raises ``KeyError`` if the RRset was not found and create was
- ``False``.
-
- Returns a ``dns.rrset.RRset object``.
- """
-
- if isinstance(section, int):
- section_number = section
- section = self.section_from_number(section_number)
- elif isinstance(section, str):
- section_number = self._section_enum.from_text(section)
- section = self.section_from_number(section_number)
- else:
- section_number = self.section_number(section)
- if isinstance(name, str):
- name = dns.name.from_text(name, idna_codec=idna_codec)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- covers = dns.rdatatype.RdataType.make(covers)
- if deleting is not None:
- deleting = dns.rdataclass.RdataClass.make(deleting)
- key = (section_number, name, rdclass, rdtype, covers, deleting)
- if not force_unique:
- if self.index is not None:
- rrset = self.index.get(key)
- if rrset is not None:
- return rrset
- else:
- for rrset in section:
- if rrset.full_match(name, rdclass, rdtype, covers, deleting):
- return rrset
- if not create:
- raise KeyError
- rrset = dns.rrset.RRset(name, rdclass, rdtype, covers, deleting)
- section.append(rrset)
- if self.index is not None:
- self.index[key] = rrset
- return rrset
-
- def get_rrset(
- self,
- section: SectionType,
- name: dns.name.Name,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- deleting: Optional[dns.rdataclass.RdataClass] = None,
- create: bool = False,
- force_unique: bool = False,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- ) -> Optional[dns.rrset.RRset]:
- """Get the RRset with the given attributes in the specified section.
-
- If the RRset is not found, None is returned.
-
- *section*, an ``int`` section number, a ``str`` section name, or one of
- the section attributes of this message. This specifies the
- the section of the message to search. For example::
-
- my_message.get_rrset(my_message.answer, name, rdclass, rdtype)
- my_message.get_rrset(dns.message.ANSWER, name, rdclass, rdtype)
- my_message.get_rrset("ANSWER", name, rdclass, rdtype)
-
- *name*, a ``dns.name.Name`` or ``str``, the name of the RRset.
-
- *rdclass*, an ``int`` or ``str``, the class of the RRset.
-
- *rdtype*, an ``int`` or ``str``, the type of the RRset.
-
- *covers*, an ``int`` or ``str``, the covers value of the RRset.
- The default is ``dns.rdatatype.NONE``.
-
- *deleting*, an ``int``, ``str``, or ``None``, the deleting value of the
- RRset. The default is ``None``.
-
- *create*, a ``bool``. If ``True``, create the RRset if it is not found.
- The created RRset is appended to *section*.
-
- *force_unique*, a ``bool``. If ``True`` and *create* is also ``True``,
- create a new RRset regardless of whether a matching RRset exists
- already. The default is ``False``. This is useful when creating
- DDNS Update messages, as order matters for them.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- Returns a ``dns.rrset.RRset object`` or ``None``.
- """
-
- try:
- rrset = self.find_rrset(
- section,
- name,
- rdclass,
- rdtype,
- covers,
- deleting,
- create,
- force_unique,
- idna_codec,
- )
- except KeyError:
- rrset = None
- return rrset
-
- def section_count(self, section: SectionType) -> int:
- """Returns the number of records in the specified section.
-
- *section*, an ``int`` section number, a ``str`` section name, or one of
- the section attributes of this message. This specifies the
- the section of the message to count. For example::
-
- my_message.section_count(my_message.answer)
- my_message.section_count(dns.message.ANSWER)
- my_message.section_count("ANSWER")
- """
-
- if isinstance(section, int):
- section_number = section
- section = self.section_from_number(section_number)
- elif isinstance(section, str):
- section_number = self._section_enum.from_text(section)
- section = self.section_from_number(section_number)
- else:
- section_number = self.section_number(section)
- count = sum(max(1, len(rrs)) for rrs in section)
- if section_number == MessageSection.ADDITIONAL:
- if self.opt is not None:
- count += 1
- if self.tsig is not None:
- count += 1
- return count
-
- def _compute_opt_reserve(self) -> int:
- """Compute the size required for the OPT RR, padding excluded"""
- if not self.opt:
- return 0
- # 1 byte for the root name, 10 for the standard RR fields
- size = 11
- # This would be more efficient if options had a size() method, but we won't
- # worry about that for now. We also don't worry if there is an existing padding
- # option, as it is unlikely and probably harmless, as the worst case is that we
- # may add another, and this seems to be legal.
- for option in self.opt[0].options:
- wire = option.to_wire()
- # We add 4 here to account for the option type and length
- size += len(wire) + 4
- if self.pad:
- # Padding will be added, so again add the option type and length.
- size += 4
- return size
-
- def _compute_tsig_reserve(self) -> int:
- """Compute the size required for the TSIG RR"""
- # This would be more efficient if TSIGs had a size method, but we won't
- # worry about for now. Also, we can't really cope with the potential
- # compressibility of the TSIG owner name, so we estimate with the uncompressed
- # size. We will disable compression when TSIG and padding are both is active
- # so that the padding comes out right.
- if not self.tsig:
- return 0
- f = io.BytesIO()
- self.tsig.to_wire(f)
- return len(f.getvalue())
-
- def to_wire(
- self,
- origin: Optional[dns.name.Name] = None,
- max_size: int = 0,
- multi: bool = False,
- tsig_ctx: Optional[Any] = None,
- prepend_length: bool = False,
- prefer_truncation: bool = False,
- **kw: Dict[str, Any],
- ) -> bytes:
- """Return a string containing the message in DNS compressed wire
- format.
-
- Additional keyword arguments are passed to the RRset ``to_wire()``
- method.
-
- *origin*, a ``dns.name.Name`` or ``None``, the origin to be appended
- to any relative names. If ``None``, and the message has an origin
- attribute that is not ``None``, then it will be used.
-
- *max_size*, an ``int``, the maximum size of the wire format
- output; default is 0, which means "the message's request
- payload, if nonzero, or 65535".
-
- *multi*, a ``bool``, should be set to ``True`` if this message is
- part of a multiple message sequence.
-
- *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the
- ongoing TSIG context, used when signing zone transfers.
-
- *prepend_length*, a ``bool``, should be set to ``True`` if the caller
- wants the message length prepended to the message itself. This is
- useful for messages sent over TCP, TLS (DoT), or QUIC (DoQ).
-
- *prefer_truncation*, a ``bool``, should be set to ``True`` if the caller
- wants the message to be truncated if it would otherwise exceed the
- maximum length. If the truncation occurs before the additional section,
- the TC bit will be set.
-
- Raises ``dns.exception.TooBig`` if *max_size* was exceeded.
-
- Returns a ``bytes``.
- """
-
- if origin is None and self.origin is not None:
- origin = self.origin
- if max_size == 0:
- if self.request_payload != 0:
- max_size = self.request_payload
- else:
- max_size = 65535
- if max_size < 512:
- max_size = 512
- elif max_size > 65535:
- max_size = 65535
- r = dns.renderer.Renderer(self.id, self.flags, max_size, origin)
- opt_reserve = self._compute_opt_reserve()
- r.reserve(opt_reserve)
- tsig_reserve = self._compute_tsig_reserve()
- r.reserve(tsig_reserve)
- try:
- for rrset in self.question:
- r.add_question(rrset.name, rrset.rdtype, rrset.rdclass)
- for rrset in self.answer:
- r.add_rrset(dns.renderer.ANSWER, rrset, **kw)
- for rrset in self.authority:
- r.add_rrset(dns.renderer.AUTHORITY, rrset, **kw)
- for rrset in self.additional:
- r.add_rrset(dns.renderer.ADDITIONAL, rrset, **kw)
- except dns.exception.TooBig:
- if prefer_truncation:
- if r.section < dns.renderer.ADDITIONAL:
- r.flags |= dns.flags.TC
- else:
- raise
- r.release_reserved()
- if self.opt is not None:
- r.add_opt(self.opt, self.pad, opt_reserve, tsig_reserve)
- r.write_header()
- if self.tsig is not None:
- (new_tsig, ctx) = dns.tsig.sign(
- r.get_wire(),
- self.keyring,
- self.tsig[0],
- int(time.time()),
- self.request_mac,
- tsig_ctx,
- multi,
- )
- self.tsig.clear()
- self.tsig.add(new_tsig)
- r.add_rrset(dns.renderer.ADDITIONAL, self.tsig)
- r.write_header()
- if multi:
- self.tsig_ctx = ctx
- wire = r.get_wire()
- if prepend_length:
- wire = len(wire).to_bytes(2, "big") + wire
- return wire
-
- @staticmethod
- def _make_tsig(
- keyname, algorithm, time_signed, fudge, mac, original_id, error, other
- ):
- tsig = dns.rdtypes.ANY.TSIG.TSIG(
- dns.rdataclass.ANY,
- dns.rdatatype.TSIG,
- algorithm,
- time_signed,
- fudge,
- mac,
- original_id,
- error,
- other,
- )
- return dns.rrset.from_rdata(keyname, 0, tsig)
-
- def use_tsig(
- self,
- keyring: Any,
- keyname: Optional[Union[dns.name.Name, str]] = None,
- fudge: int = 300,
- original_id: Optional[int] = None,
- tsig_error: int = 0,
- other_data: bytes = b"",
- algorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm,
- ) -> None:
- """When sending, a TSIG signature using the specified key
- should be added.
-
- *key*, a ``dns.tsig.Key`` is the key to use. If a key is specified,
- the *keyring* and *algorithm* fields are not used.
-
- *keyring*, a ``dict``, ``callable`` or ``dns.tsig.Key``, is either
- the TSIG keyring or key to use.
-
- The format of a keyring dict is a mapping from TSIG key name, as
- ``dns.name.Name`` to ``dns.tsig.Key`` or a TSIG secret, a ``bytes``.
- If a ``dict`` *keyring* is specified but a *keyname* is not, the key
- used will be the first key in the *keyring*. Note that the order of
- keys in a dictionary is not defined, so applications should supply a
- keyname when a ``dict`` keyring is used, unless they know the keyring
- contains only one key. If a ``callable`` keyring is specified, the
- callable will be called with the message and the keyname, and is
- expected to return a key.
-
- *keyname*, a ``dns.name.Name``, ``str`` or ``None``, the name of
- this TSIG key to use; defaults to ``None``. If *keyring* is a
- ``dict``, the key must be defined in it. If *keyring* is a
- ``dns.tsig.Key``, this is ignored.
-
- *fudge*, an ``int``, the TSIG time fudge.
-
- *original_id*, an ``int``, the TSIG original id. If ``None``,
- the message's id is used.
-
- *tsig_error*, an ``int``, the TSIG error code.
-
- *other_data*, a ``bytes``, the TSIG other data.
-
- *algorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use. This is
- only used if *keyring* is a ``dict``, and the key entry is a ``bytes``.
- """
-
- if isinstance(keyring, dns.tsig.Key):
- key = keyring
- keyname = key.name
- elif callable(keyring):
- key = keyring(self, keyname)
- else:
- if isinstance(keyname, str):
- keyname = dns.name.from_text(keyname)
- if keyname is None:
- keyname = next(iter(keyring))
- key = keyring[keyname]
- if isinstance(key, bytes):
- key = dns.tsig.Key(keyname, key, algorithm)
- self.keyring = key
- if original_id is None:
- original_id = self.id
- self.tsig = self._make_tsig(
- keyname,
- self.keyring.algorithm,
- 0,
- fudge,
- b"\x00" * dns.tsig.mac_sizes[self.keyring.algorithm],
- original_id,
- tsig_error,
- other_data,
- )
-
- @property
- def keyname(self) -> Optional[dns.name.Name]:
- if self.tsig:
- return self.tsig.name
- else:
- return None
-
- @property
- def keyalgorithm(self) -> Optional[dns.name.Name]:
- if self.tsig:
- return self.tsig[0].algorithm
- else:
- return None
-
- @property
- def mac(self) -> Optional[bytes]:
- if self.tsig:
- return self.tsig[0].mac
- else:
- return None
-
- @property
- def tsig_error(self) -> Optional[int]:
- if self.tsig:
- return self.tsig[0].error
- else:
- return None
-
- @property
- def had_tsig(self) -> bool:
- return bool(self.tsig)
-
- @staticmethod
- def _make_opt(flags=0, payload=DEFAULT_EDNS_PAYLOAD, options=None):
- opt = dns.rdtypes.ANY.OPT.OPT(payload, dns.rdatatype.OPT, options or ())
- return dns.rrset.from_rdata(dns.name.root, int(flags), opt)
-
- def use_edns(
- self,
- edns: Optional[Union[int, bool]] = 0,
- ednsflags: int = 0,
- payload: int = DEFAULT_EDNS_PAYLOAD,
- request_payload: Optional[int] = None,
- options: Optional[List[dns.edns.Option]] = None,
- pad: int = 0,
- ) -> None:
- """Configure EDNS behavior.
-
- *edns*, an ``int``, is the EDNS level to use. Specifying ``None``, ``False``,
- or ``-1`` means "do not use EDNS", and in this case the other parameters are
- ignored. Specifying ``True`` is equivalent to specifying 0, i.e. "use EDNS0".
-
- *ednsflags*, an ``int``, the EDNS flag values.
-
- *payload*, an ``int``, is the EDNS sender's payload field, which is the maximum
- size of UDP datagram the sender can handle. I.e. how big a response to this
- message can be.
-
- *request_payload*, an ``int``, is the EDNS payload size to use when sending this
- message. If not specified, defaults to the value of *payload*.
-
- *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS options.
-
- *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add
- padding bytes to make the message size a multiple of *pad*. Note that if
- padding is non-zero, an EDNS PADDING option will always be added to the
- message.
- """
-
- if edns is None or edns is False:
- edns = -1
- elif edns is True:
- edns = 0
- if edns < 0:
- self.opt = None
- self.request_payload = 0
- else:
- # make sure the EDNS version in ednsflags agrees with edns
- ednsflags &= 0xFF00FFFF
- ednsflags |= edns << 16
- if options is None:
- options = []
- self.opt = self._make_opt(ednsflags, payload, options)
- if request_payload is None:
- request_payload = payload
- self.request_payload = request_payload
- if pad < 0:
- raise ValueError("pad must be non-negative")
- self.pad = pad
-
- @property
- def edns(self) -> int:
- if self.opt:
- return (self.ednsflags & 0xFF0000) >> 16
- else:
- return -1
-
- @property
- def ednsflags(self) -> int:
- if self.opt:
- return self.opt.ttl
- else:
- return 0
-
- @ednsflags.setter
- def ednsflags(self, v):
- if self.opt:
- self.opt.ttl = v
- elif v:
- self.opt = self._make_opt(v)
-
- @property
- def payload(self) -> int:
- if self.opt:
- return self.opt[0].payload
- else:
- return 0
-
- @property
- def options(self) -> Tuple:
- if self.opt:
- return self.opt[0].options
- else:
- return ()
-
- def want_dnssec(self, wanted: bool = True) -> None:
- """Enable or disable 'DNSSEC desired' flag in requests.
-
- *wanted*, a ``bool``. If ``True``, then DNSSEC data is
- desired in the response, EDNS is enabled if required, and then
- the DO bit is set. If ``False``, the DO bit is cleared if
- EDNS is enabled.
- """
-
- if wanted:
- self.ednsflags |= dns.flags.DO
- elif self.opt:
- self.ednsflags &= ~int(dns.flags.DO)
-
- def rcode(self) -> dns.rcode.Rcode:
- """Return the rcode.
-
- Returns a ``dns.rcode.Rcode``.
- """
- return dns.rcode.from_flags(int(self.flags), int(self.ednsflags))
-
- def set_rcode(self, rcode: dns.rcode.Rcode) -> None:
- """Set the rcode.
-
- *rcode*, a ``dns.rcode.Rcode``, is the rcode to set.
- """
- (value, evalue) = dns.rcode.to_flags(rcode)
- self.flags &= 0xFFF0
- self.flags |= value
- self.ednsflags &= 0x00FFFFFF
- self.ednsflags |= evalue
-
- def opcode(self) -> dns.opcode.Opcode:
- """Return the opcode.
-
- Returns a ``dns.opcode.Opcode``.
- """
- return dns.opcode.from_flags(int(self.flags))
-
- def set_opcode(self, opcode: dns.opcode.Opcode) -> None:
- """Set the opcode.
-
- *opcode*, a ``dns.opcode.Opcode``, is the opcode to set.
- """
- self.flags &= 0x87FF
- self.flags |= dns.opcode.to_flags(opcode)
-
- def _get_one_rr_per_rrset(self, value):
- # What the caller picked is fine.
- return value
-
- # pylint: disable=unused-argument
-
- def _parse_rr_header(self, section, name, rdclass, rdtype):
- return (rdclass, rdtype, None, False)
-
- # pylint: enable=unused-argument
-
- def _parse_special_rr_header(self, section, count, position, name, rdclass, rdtype):
- if rdtype == dns.rdatatype.OPT:
- if (
- section != MessageSection.ADDITIONAL
- or self.opt
- or name != dns.name.root
- ):
- raise BadEDNS
- elif rdtype == dns.rdatatype.TSIG:
- if (
- section != MessageSection.ADDITIONAL
- or rdclass != dns.rdatatype.ANY
- or position != count - 1
- ):
- raise BadTSIG
- return (rdclass, rdtype, None, False)
-
-
-class ChainingResult:
- """The result of a call to dns.message.QueryMessage.resolve_chaining().
-
- The ``answer`` attribute is the answer RRSet, or ``None`` if it doesn't
- exist.
-
- The ``canonical_name`` attribute is the canonical name after all
- chaining has been applied (this is the same name as ``rrset.name`` in cases
- where rrset is not ``None``).
-
- The ``minimum_ttl`` attribute is the minimum TTL, i.e. the TTL to
- use if caching the data. It is the smallest of all the CNAME TTLs
- and either the answer TTL if it exists or the SOA TTL and SOA
- minimum values for negative answers.
-
- The ``cnames`` attribute is a list of all the CNAME RRSets followed to
- get to the canonical name.
- """
-
- def __init__(
- self,
- canonical_name: dns.name.Name,
- answer: Optional[dns.rrset.RRset],
- minimum_ttl: int,
- cnames: List[dns.rrset.RRset],
- ):
- self.canonical_name = canonical_name
- self.answer = answer
- self.minimum_ttl = minimum_ttl
- self.cnames = cnames
-
-
-class QueryMessage(Message):
- def resolve_chaining(self) -> ChainingResult:
- """Follow the CNAME chain in the response to determine the answer
- RRset.
-
- Raises ``dns.message.NotQueryResponse`` if the message is not
- a response.
-
- Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long.
-
- Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN
- but an answer was found.
-
- Raises ``dns.exception.FormError`` if the question count is not 1.
-
- Returns a ChainingResult object.
- """
- if self.flags & dns.flags.QR == 0:
- raise NotQueryResponse
- if len(self.question) != 1:
- raise dns.exception.FormError
- question = self.question[0]
- qname = question.name
- min_ttl = dns.ttl.MAX_TTL
- answer = None
- count = 0
- cnames = []
- while count < MAX_CHAIN:
- try:
- answer = self.find_rrset(
- self.answer, qname, question.rdclass, question.rdtype
- )
- min_ttl = min(min_ttl, answer.ttl)
- break
- except KeyError:
- if question.rdtype != dns.rdatatype.CNAME:
- try:
- crrset = self.find_rrset(
- self.answer, qname, question.rdclass, dns.rdatatype.CNAME
- )
- cnames.append(crrset)
- min_ttl = min(min_ttl, crrset.ttl)
- for rd in crrset:
- qname = rd.target
- break
- count += 1
- continue
- except KeyError:
- # Exit the chaining loop
- break
- else:
- # Exit the chaining loop
- break
- if count >= MAX_CHAIN:
- raise ChainTooLong
- if self.rcode() == dns.rcode.NXDOMAIN and answer is not None:
- raise AnswerForNXDOMAIN
- if answer is None:
- # Further minimize the TTL with NCACHE.
- auname = qname
- while True:
- # Look for an SOA RR whose owner name is a superdomain
- # of qname.
- try:
- srrset = self.find_rrset(
- self.authority, auname, question.rdclass, dns.rdatatype.SOA
- )
- min_ttl = min(min_ttl, srrset.ttl, srrset[0].minimum)
- break
- except KeyError:
- try:
- auname = auname.parent()
- except dns.name.NoParent:
- break
- return ChainingResult(qname, answer, min_ttl, cnames)
-
- def canonical_name(self) -> dns.name.Name:
- """Return the canonical name of the first name in the question
- section.
-
- Raises ``dns.message.NotQueryResponse`` if the message is not
- a response.
-
- Raises ``dns.message.ChainTooLong`` if the CNAME chain is too long.
-
- Raises ``dns.message.AnswerForNXDOMAIN`` if the rcode is NXDOMAIN
- but an answer was found.
-
- Raises ``dns.exception.FormError`` if the question count is not 1.
- """
- return self.resolve_chaining().canonical_name
-
-
-def _maybe_import_update():
- # We avoid circular imports by doing this here. We do it in another
- # function as doing it in _message_factory_from_opcode() makes "dns"
- # a local symbol, and the first line fails :)
-
- # pylint: disable=redefined-outer-name,import-outside-toplevel,unused-import
- import dns.update # noqa: F401
-
-
-def _message_factory_from_opcode(opcode):
- if opcode == dns.opcode.QUERY:
- return QueryMessage
- elif opcode == dns.opcode.UPDATE:
- _maybe_import_update()
- return dns.update.UpdateMessage
- else:
- return Message
-
-
-class _WireReader:
- """Wire format reader.
-
- parser: the binary parser
- message: The message object being built
- initialize_message: Callback to set message parsing options
- question_only: Are we only reading the question?
- one_rr_per_rrset: Put each RR into its own RRset?
- keyring: TSIG keyring
- ignore_trailing: Ignore trailing junk at end of request?
- multi: Is this message part of a multi-message sequence?
- DNS dynamic updates.
- continue_on_error: try to extract as much information as possible from
- the message, accumulating MessageErrors in the *errors* attribute instead of
- raising them.
- """
-
- def __init__(
- self,
- wire,
- initialize_message,
- question_only=False,
- one_rr_per_rrset=False,
- ignore_trailing=False,
- keyring=None,
- multi=False,
- continue_on_error=False,
- ):
- self.parser = dns.wire.Parser(wire)
- self.message = None
- self.initialize_message = initialize_message
- self.question_only = question_only
- self.one_rr_per_rrset = one_rr_per_rrset
- self.ignore_trailing = ignore_trailing
- self.keyring = keyring
- self.multi = multi
- self.continue_on_error = continue_on_error
- self.errors = []
-
- def _get_question(self, section_number, qcount):
- """Read the next *qcount* records from the wire data and add them to
- the question section.
- """
- assert self.message is not None
- section = self.message.sections[section_number]
- for _ in range(qcount):
- qname = self.parser.get_name(self.message.origin)
- (rdtype, rdclass) = self.parser.get_struct("!HH")
- (rdclass, rdtype, _, _) = self.message._parse_rr_header(
- section_number, qname, rdclass, rdtype
- )
- self.message.find_rrset(
- section, qname, rdclass, rdtype, create=True, force_unique=True
- )
-
- def _add_error(self, e):
- self.errors.append(MessageError(e, self.parser.current))
-
- def _get_section(self, section_number, count):
- """Read the next I{count} records from the wire data and add them to
- the specified section.
-
- section_number: the section of the message to which to add records
- count: the number of records to read
- """
- assert self.message is not None
- section = self.message.sections[section_number]
- force_unique = self.one_rr_per_rrset
- for i in range(count):
- rr_start = self.parser.current
- absolute_name = self.parser.get_name()
- if self.message.origin is not None:
- name = absolute_name.relativize(self.message.origin)
- else:
- name = absolute_name
- (rdtype, rdclass, ttl, rdlen) = self.parser.get_struct("!HHIH")
- if rdtype in (dns.rdatatype.OPT, dns.rdatatype.TSIG):
- (
- rdclass,
- rdtype,
- deleting,
- empty,
- ) = self.message._parse_special_rr_header(
- section_number, count, i, name, rdclass, rdtype
- )
- else:
- (rdclass, rdtype, deleting, empty) = self.message._parse_rr_header(
- section_number, name, rdclass, rdtype
- )
- rdata_start = self.parser.current
- try:
- if empty:
- if rdlen > 0:
- raise dns.exception.FormError
- rd = None
- covers = dns.rdatatype.NONE
- else:
- with self.parser.restrict_to(rdlen):
- rd = dns.rdata.from_wire_parser(
- rdclass, rdtype, self.parser, self.message.origin
- )
- covers = rd.covers()
- if self.message.xfr and rdtype == dns.rdatatype.SOA:
- force_unique = True
- if rdtype == dns.rdatatype.OPT:
- self.message.opt = dns.rrset.from_rdata(name, ttl, rd)
- elif rdtype == dns.rdatatype.TSIG:
- if self.keyring is None:
- raise UnknownTSIGKey("got signed message without keyring")
- if isinstance(self.keyring, dict):
- key = self.keyring.get(absolute_name)
- if isinstance(key, bytes):
- key = dns.tsig.Key(absolute_name, key, rd.algorithm)
- elif callable(self.keyring):
- key = self.keyring(self.message, absolute_name)
- else:
- key = self.keyring
- if key is None:
- raise UnknownTSIGKey("key '%s' unknown" % name)
- self.message.keyring = key
- self.message.tsig_ctx = dns.tsig.validate(
- self.parser.wire,
- key,
- absolute_name,
- rd,
- int(time.time()),
- self.message.request_mac,
- rr_start,
- self.message.tsig_ctx,
- self.multi,
- )
- self.message.tsig = dns.rrset.from_rdata(absolute_name, 0, rd)
- else:
- rrset = self.message.find_rrset(
- section,
- name,
- rdclass,
- rdtype,
- covers,
- deleting,
- True,
- force_unique,
- )
- if rd is not None:
- if ttl > 0x7FFFFFFF:
- ttl = 0
- rrset.add(rd, ttl)
- except Exception as e:
- if self.continue_on_error:
- self._add_error(e)
- self.parser.seek(rdata_start + rdlen)
- else:
- raise
-
- def read(self):
- """Read a wire format DNS message and build a dns.message.Message
- object."""
-
- if self.parser.remaining() < 12:
- raise ShortHeader
- (id, flags, qcount, ancount, aucount, adcount) = self.parser.get_struct(
- "!HHHHHH"
- )
- factory = _message_factory_from_opcode(dns.opcode.from_flags(flags))
- self.message = factory(id=id)
- self.message.flags = dns.flags.Flag(flags)
- self.initialize_message(self.message)
- self.one_rr_per_rrset = self.message._get_one_rr_per_rrset(
- self.one_rr_per_rrset
- )
- try:
- self._get_question(MessageSection.QUESTION, qcount)
- if self.question_only:
- return self.message
- self._get_section(MessageSection.ANSWER, ancount)
- self._get_section(MessageSection.AUTHORITY, aucount)
- self._get_section(MessageSection.ADDITIONAL, adcount)
- if not self.ignore_trailing and self.parser.remaining() != 0:
- raise TrailingJunk
- if self.multi and self.message.tsig_ctx and not self.message.had_tsig:
- self.message.tsig_ctx.update(self.parser.wire)
- except Exception as e:
- if self.continue_on_error:
- self._add_error(e)
- else:
- raise
- return self.message
-
-
-def from_wire(
- wire: bytes,
- keyring: Optional[Any] = None,
- request_mac: Optional[bytes] = b"",
- xfr: bool = False,
- origin: Optional[dns.name.Name] = None,
- tsig_ctx: Optional[Union[dns.tsig.HMACTSig, dns.tsig.GSSTSig]] = None,
- multi: bool = False,
- question_only: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- raise_on_truncation: bool = False,
- continue_on_error: bool = False,
-) -> Message:
- """Convert a DNS wire format message into a message object.
-
- *keyring*, a ``dns.tsig.Key`` or ``dict``, the key or keyring to use if the message
- is signed.
-
- *request_mac*, a ``bytes`` or ``None``. If the message is a response to a
- TSIG-signed request, *request_mac* should be set to the MAC of that request.
-
- *xfr*, a ``bool``, should be set to ``True`` if this message is part of a zone
- transfer.
-
- *origin*, a ``dns.name.Name`` or ``None``. If the message is part of a zone
- transfer, *origin* should be the origin name of the zone. If not ``None``, names
- will be relativized to the origin.
-
- *tsig_ctx*, a ``dns.tsig.HMACTSig`` or ``dns.tsig.GSSTSig`` object, the ongoing TSIG
- context, used when validating zone transfers.
-
- *multi*, a ``bool``, should be set to ``True`` if this message is part of a multiple
- message sequence.
-
- *question_only*, a ``bool``. If ``True``, read only up to the end of the question
- section.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
- message.
-
- *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if the TC bit is
- set.
-
- *continue_on_error*, a ``bool``. If ``True``, try to continue parsing even if
- errors occur. Erroneous rdata will be ignored. Errors will be accumulated as a
- list of MessageError objects in the message's ``errors`` attribute. This option is
- recommended only for DNS analysis tools, or for use in a server as part of an error
- handling path. The default is ``False``.
-
- Raises ``dns.message.ShortHeader`` if the message is less than 12 octets long.
-
- Raises ``dns.message.TrailingJunk`` if there were octets in the message past the end
- of the proper DNS message, and *ignore_trailing* is ``False``.
-
- Raises ``dns.message.BadEDNS`` if an OPT record was in the wrong section, or
- occurred more than once.
-
- Raises ``dns.message.BadTSIG`` if a TSIG record was not the last record of the
- additional data section.
-
- Raises ``dns.message.Truncated`` if the TC flag is set and *raise_on_truncation* is
- ``True``.
-
- Returns a ``dns.message.Message``.
- """
-
- # We permit None for request_mac solely for backwards compatibility
- if request_mac is None:
- request_mac = b""
-
- def initialize_message(message):
- message.request_mac = request_mac
- message.xfr = xfr
- message.origin = origin
- message.tsig_ctx = tsig_ctx
-
- reader = _WireReader(
- wire,
- initialize_message,
- question_only,
- one_rr_per_rrset,
- ignore_trailing,
- keyring,
- multi,
- continue_on_error,
- )
- try:
- m = reader.read()
- except dns.exception.FormError:
- if (
- reader.message
- and (reader.message.flags & dns.flags.TC)
- and raise_on_truncation
- ):
- raise Truncated(message=reader.message)
- else:
- raise
- # Reading a truncated message might not have any errors, so we
- # have to do this check here too.
- if m.flags & dns.flags.TC and raise_on_truncation:
- raise Truncated(message=m)
- if continue_on_error:
- m.errors = reader.errors
-
- return m
-
-
-class _TextReader:
- """Text format reader.
-
- tok: the tokenizer.
- message: The message object being built.
- DNS dynamic updates.
- last_name: The most recently read name when building a message object.
- one_rr_per_rrset: Put each RR into its own RRset?
- origin: The origin for relative names
- relativize: relativize names?
- relativize_to: the origin to relativize to.
- """
-
- def __init__(
- self,
- text,
- idna_codec,
- one_rr_per_rrset=False,
- origin=None,
- relativize=True,
- relativize_to=None,
- ):
- self.message = None
- self.tok = dns.tokenizer.Tokenizer(text, idna_codec=idna_codec)
- self.last_name = None
- self.one_rr_per_rrset = one_rr_per_rrset
- self.origin = origin
- self.relativize = relativize
- self.relativize_to = relativize_to
- self.id = None
- self.edns = -1
- self.ednsflags = 0
- self.payload = DEFAULT_EDNS_PAYLOAD
- self.rcode = None
- self.opcode = dns.opcode.QUERY
- self.flags = 0
-
- def _header_line(self, _):
- """Process one line from the text format header section."""
-
- token = self.tok.get()
- what = token.value
- if what == "id":
- self.id = self.tok.get_int()
- elif what == "flags":
- while True:
- token = self.tok.get()
- if not token.is_identifier():
- self.tok.unget(token)
- break
- self.flags = self.flags | dns.flags.from_text(token.value)
- elif what == "edns":
- self.edns = self.tok.get_int()
- self.ednsflags = self.ednsflags | (self.edns << 16)
- elif what == "eflags":
- if self.edns < 0:
- self.edns = 0
- while True:
- token = self.tok.get()
- if not token.is_identifier():
- self.tok.unget(token)
- break
- self.ednsflags = self.ednsflags | dns.flags.edns_from_text(token.value)
- elif what == "payload":
- self.payload = self.tok.get_int()
- if self.edns < 0:
- self.edns = 0
- elif what == "opcode":
- text = self.tok.get_string()
- self.opcode = dns.opcode.from_text(text)
- self.flags = self.flags | dns.opcode.to_flags(self.opcode)
- elif what == "rcode":
- text = self.tok.get_string()
- self.rcode = dns.rcode.from_text(text)
- else:
- raise UnknownHeaderField
- self.tok.get_eol()
-
- def _question_line(self, section_number):
- """Process one line from the text format question section."""
-
- section = self.message.sections[section_number]
- token = self.tok.get(want_leading=True)
- if not token.is_whitespace():
- self.last_name = self.tok.as_name(
- token, self.message.origin, self.relativize, self.relativize_to
- )
- name = self.last_name
- if name is None:
- raise NoPreviousName
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- # Class
- try:
- rdclass = dns.rdataclass.from_text(token.value)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except dns.exception.SyntaxError:
- raise dns.exception.SyntaxError
- except Exception:
- rdclass = dns.rdataclass.IN
- # Type
- rdtype = dns.rdatatype.from_text(token.value)
- (rdclass, rdtype, _, _) = self.message._parse_rr_header(
- section_number, name, rdclass, rdtype
- )
- self.message.find_rrset(
- section, name, rdclass, rdtype, create=True, force_unique=True
- )
- self.tok.get_eol()
-
- def _rr_line(self, section_number):
- """Process one line from the text format answer, authority, or
- additional data sections.
- """
-
- section = self.message.sections[section_number]
- # Name
- token = self.tok.get(want_leading=True)
- if not token.is_whitespace():
- self.last_name = self.tok.as_name(
- token, self.message.origin, self.relativize, self.relativize_to
- )
- name = self.last_name
- if name is None:
- raise NoPreviousName
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- # TTL
- try:
- ttl = int(token.value, 0)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except dns.exception.SyntaxError:
- raise dns.exception.SyntaxError
- except Exception:
- ttl = 0
- # Class
- try:
- rdclass = dns.rdataclass.from_text(token.value)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except dns.exception.SyntaxError:
- raise dns.exception.SyntaxError
- except Exception:
- rdclass = dns.rdataclass.IN
- # Type
- rdtype = dns.rdatatype.from_text(token.value)
- (rdclass, rdtype, deleting, empty) = self.message._parse_rr_header(
- section_number, name, rdclass, rdtype
- )
- token = self.tok.get()
- if empty and not token.is_eol_or_eof():
- raise dns.exception.SyntaxError
- if not empty and token.is_eol_or_eof():
- raise dns.exception.UnexpectedEnd
- if not token.is_eol_or_eof():
- self.tok.unget(token)
- rd = dns.rdata.from_text(
- rdclass,
- rdtype,
- self.tok,
- self.message.origin,
- self.relativize,
- self.relativize_to,
- )
- covers = rd.covers()
- else:
- rd = None
- covers = dns.rdatatype.NONE
- rrset = self.message.find_rrset(
- section,
- name,
- rdclass,
- rdtype,
- covers,
- deleting,
- True,
- self.one_rr_per_rrset,
- )
- if rd is not None:
- rrset.add(rd, ttl)
-
- def _make_message(self):
- factory = _message_factory_from_opcode(self.opcode)
- message = factory(id=self.id)
- message.flags = self.flags
- if self.edns >= 0:
- message.use_edns(self.edns, self.ednsflags, self.payload)
- if self.rcode:
- message.set_rcode(self.rcode)
- if self.origin:
- message.origin = self.origin
- return message
-
- def read(self):
- """Read a text format DNS message and build a dns.message.Message
- object."""
-
- line_method = self._header_line
- section_number = None
- while 1:
- token = self.tok.get(True, True)
- if token.is_eol_or_eof():
- break
- if token.is_comment():
- u = token.value.upper()
- if u == "HEADER":
- line_method = self._header_line
-
- if self.message:
- message = self.message
- else:
- # If we don't have a message, create one with the current
- # opcode, so that we know which section names to parse.
- message = self._make_message()
- try:
- section_number = message._section_enum.from_text(u)
- # We found a section name. If we don't have a message,
- # use the one we just created.
- if not self.message:
- self.message = message
- self.one_rr_per_rrset = message._get_one_rr_per_rrset(
- self.one_rr_per_rrset
- )
- if section_number == MessageSection.QUESTION:
- line_method = self._question_line
- else:
- line_method = self._rr_line
- except Exception:
- # It's just a comment.
- pass
- self.tok.get_eol()
- continue
- self.tok.unget(token)
- line_method(section_number)
- if not self.message:
- self.message = self._make_message()
- return self.message
-
-
-def from_text(
- text: str,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- one_rr_per_rrset: bool = False,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
-) -> Message:
- """Convert the text format message into a message object.
-
- The reader stops after reading the first blank line in the input to
- facilitate reading multiple messages from a single file with
- ``dns.message.from_file()``.
-
- *text*, a ``str``, the text format message.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put
- into its own rrset. The default is ``False``.
-
- *origin*, a ``dns.name.Name`` (or ``None``), the
- origin to use for relative names.
-
- *relativize*, a ``bool``. If true, name will be relativized.
-
- *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
- when relativizing names. If not set, the *origin* value will be used.
-
- Raises ``dns.message.UnknownHeaderField`` if a header is unknown.
-
- Raises ``dns.exception.SyntaxError`` if the text is badly formed.
-
- Returns a ``dns.message.Message object``
- """
-
- # 'text' can also be a file, but we don't publish that fact
- # since it's an implementation detail. The official file
- # interface is from_file().
-
- reader = _TextReader(
- text, idna_codec, one_rr_per_rrset, origin, relativize, relativize_to
- )
- return reader.read()
-
-
-def from_file(
- f: Any,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- one_rr_per_rrset: bool = False,
-) -> Message:
- """Read the next text format message from the specified file.
-
- Message blocks are separated by a single blank line.
-
- *f*, a ``file`` or ``str``. If *f* is text, it is treated as the
- pathname of a file to open.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, then each RR is put
- into its own rrset. The default is ``False``.
-
- Raises ``dns.message.UnknownHeaderField`` if a header is unknown.
-
- Raises ``dns.exception.SyntaxError`` if the text is badly formed.
-
- Returns a ``dns.message.Message object``
- """
-
- if isinstance(f, str):
- cm: contextlib.AbstractContextManager = open(f)
- else:
- cm = contextlib.nullcontext(f)
- with cm as f:
- return from_text(f, idna_codec, one_rr_per_rrset)
- assert False # for mypy lgtm[py/unreachable-statement]
-
-
-def make_query(
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- use_edns: Optional[Union[int, bool]] = None,
- want_dnssec: bool = False,
- ednsflags: Optional[int] = None,
- payload: Optional[int] = None,
- request_payload: Optional[int] = None,
- options: Optional[List[dns.edns.Option]] = None,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- id: Optional[int] = None,
- flags: int = dns.flags.RD,
- pad: int = 0,
-) -> QueryMessage:
- """Make a query message.
-
- The query name, type, and class may all be specified either
- as objects of the appropriate type, or as strings.
-
- The query will have a randomly chosen query id, and its DNS flags
- will be set to dns.flags.RD.
-
- qname, a ``dns.name.Name`` or ``str``, the query name.
-
- *rdtype*, an ``int`` or ``str``, the desired rdata type.
-
- *rdclass*, an ``int`` or ``str``, the desired rdata class; the default
- is class IN.
-
- *use_edns*, an ``int``, ``bool`` or ``None``. The EDNS level to use; the
- default is ``None``. If ``None``, EDNS will be enabled only if other
- parameters (*ednsflags*, *payload*, *request_payload*, or *options*) are
- set.
- See the description of dns.message.Message.use_edns() for the possible
- values for use_edns and their meanings.
-
- *want_dnssec*, a ``bool``. If ``True``, DNSSEC data is desired.
-
- *ednsflags*, an ``int``, the EDNS flag values.
-
- *payload*, an ``int``, is the EDNS sender's payload field, which is the
- maximum size of UDP datagram the sender can handle. I.e. how big
- a response to this message can be.
-
- *request_payload*, an ``int``, is the EDNS payload size to use when
- sending this message. If not specified, defaults to the value of
- *payload*.
-
- *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS
- options.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- *id*, an ``int`` or ``None``, the desired query id. The default is
- ``None``, which generates a random query id.
-
- *flags*, an ``int``, the desired query flags. The default is
- ``dns.flags.RD``.
-
- *pad*, a non-negative ``int``. If 0, the default, do not pad; otherwise add
- padding bytes to make the message size a multiple of *pad*. Note that if
- padding is non-zero, an EDNS PADDING option will always be added to the
- message.
-
- Returns a ``dns.message.QueryMessage``
- """
-
- if isinstance(qname, str):
- qname = dns.name.from_text(qname, idna_codec=idna_codec)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- m = QueryMessage(id=id)
- m.flags = dns.flags.Flag(flags)
- m.find_rrset(m.question, qname, rdclass, rdtype, create=True, force_unique=True)
- # only pass keywords on to use_edns if they have been set to a
- # non-None value. Setting a field will turn EDNS on if it hasn't
- # been configured.
- kwargs: Dict[str, Any] = {}
- if ednsflags is not None:
- kwargs["ednsflags"] = ednsflags
- if payload is not None:
- kwargs["payload"] = payload
- if request_payload is not None:
- kwargs["request_payload"] = request_payload
- if options is not None:
- kwargs["options"] = options
- if kwargs and use_edns is None:
- use_edns = 0
- kwargs["edns"] = use_edns
- kwargs["pad"] = pad
- m.use_edns(**kwargs)
- m.want_dnssec(want_dnssec)
- return m
-
-
-def make_response(
- query: Message,
- recursion_available: bool = False,
- our_payload: int = 8192,
- fudge: int = 300,
- tsig_error: int = 0,
- pad: Optional[int] = None,
-) -> Message:
- """Make a message which is a response for the specified query.
- The message returned is really a response skeleton; it has all of the infrastructure
- required of a response, but none of the content.
-
- The response's question section is a shallow copy of the query's question section,
- so the query's question RRsets should not be changed.
-
- *query*, a ``dns.message.Message``, the query to respond to.
-
- *recursion_available*, a ``bool``, should RA be set in the response?
-
- *our_payload*, an ``int``, the payload size to advertise in EDNS responses.
-
- *fudge*, an ``int``, the TSIG time fudge.
-
- *tsig_error*, an ``int``, the TSIG error.
-
- *pad*, a non-negative ``int`` or ``None``. If 0, the default, do not pad; otherwise
- if not ``None`` add padding bytes to make the message size a multiple of *pad*.
- Note that if padding is non-zero, an EDNS PADDING option will always be added to the
- message. If ``None``, add padding following RFC 8467, namely if the request is
- padded, pad the response to 468 otherwise do not pad.
-
- Returns a ``dns.message.Message`` object whose specific class is appropriate for the
- query. For example, if query is a ``dns.update.UpdateMessage``, response will be
- too.
- """
-
- if query.flags & dns.flags.QR:
- raise dns.exception.FormError("specified query message is not a query")
- factory = _message_factory_from_opcode(query.opcode())
- response = factory(id=query.id)
- response.flags = dns.flags.QR | (query.flags & dns.flags.RD)
- if recursion_available:
- response.flags |= dns.flags.RA
- response.set_opcode(query.opcode())
- response.question = list(query.question)
- if query.edns >= 0:
- if pad is None:
- # Set response padding per RFC 8467
- pad = 0
- for option in query.options:
- if option.otype == dns.edns.OptionType.PADDING:
- pad = 468
- response.use_edns(0, 0, our_payload, query.payload, pad=pad)
- if query.had_tsig:
- response.use_tsig(
- query.keyring,
- query.keyname,
- fudge,
- None,
- tsig_error,
- b"",
- query.keyalgorithm,
- )
- response.request_mac = query.mac
- return response
-
-
-### BEGIN generated MessageSection constants
-
-QUESTION = MessageSection.QUESTION
-ANSWER = MessageSection.ANSWER
-AUTHORITY = MessageSection.AUTHORITY
-ADDITIONAL = MessageSection.ADDITIONAL
-
-### END generated MessageSection constants
diff --git a/.venv/lib/python3.12/site-packages/dns/name.py b/.venv/lib/python3.12/site-packages/dns/name.py
deleted file mode 100644
index 22ccb39..0000000
--- a/.venv/lib/python3.12/site-packages/dns/name.py
+++ /dev/null
@@ -1,1283 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Names.
-"""
-
-import copy
-import encodings.idna # type: ignore
-import functools
-import struct
-from typing import Any, Callable, Dict, Iterable, Optional, Tuple, Union
-
-import dns._features
-import dns.enum
-import dns.exception
-import dns.immutable
-import dns.wire
-
-if dns._features.have("idna"):
- import idna # type: ignore
-
- have_idna_2008 = True
-else: # pragma: no cover
- have_idna_2008 = False
-
-CompressType = Dict["Name", int]
-
-
-class NameRelation(dns.enum.IntEnum):
- """Name relation result from fullcompare()."""
-
- # This is an IntEnum for backwards compatibility in case anyone
- # has hardwired the constants.
-
- #: The compared names have no relationship to each other.
- NONE = 0
- #: the first name is a superdomain of the second.
- SUPERDOMAIN = 1
- #: The first name is a subdomain of the second.
- SUBDOMAIN = 2
- #: The compared names are equal.
- EQUAL = 3
- #: The compared names have a common ancestor.
- COMMONANCESTOR = 4
-
- @classmethod
- def _maximum(cls):
- return cls.COMMONANCESTOR
-
- @classmethod
- def _short_name(cls):
- return cls.__name__
-
-
-# Backwards compatibility
-NAMERELN_NONE = NameRelation.NONE
-NAMERELN_SUPERDOMAIN = NameRelation.SUPERDOMAIN
-NAMERELN_SUBDOMAIN = NameRelation.SUBDOMAIN
-NAMERELN_EQUAL = NameRelation.EQUAL
-NAMERELN_COMMONANCESTOR = NameRelation.COMMONANCESTOR
-
-
-class EmptyLabel(dns.exception.SyntaxError):
- """A DNS label is empty."""
-
-
-class BadEscape(dns.exception.SyntaxError):
- """An escaped code in a text format of DNS name is invalid."""
-
-
-class BadPointer(dns.exception.FormError):
- """A DNS compression pointer points forward instead of backward."""
-
-
-class BadLabelType(dns.exception.FormError):
- """The label type in DNS name wire format is unknown."""
-
-
-class NeedAbsoluteNameOrOrigin(dns.exception.DNSException):
- """An attempt was made to convert a non-absolute name to
- wire when there was also a non-absolute (or missing) origin."""
-
-
-class NameTooLong(dns.exception.FormError):
- """A DNS name is > 255 octets long."""
-
-
-class LabelTooLong(dns.exception.SyntaxError):
- """A DNS label is > 63 octets long."""
-
-
-class AbsoluteConcatenation(dns.exception.DNSException):
- """An attempt was made to append anything other than the
- empty name to an absolute DNS name."""
-
-
-class NoParent(dns.exception.DNSException):
- """An attempt was made to get the parent of the root name
- or the empty name."""
-
-
-class NoIDNA2008(dns.exception.DNSException):
- """IDNA 2008 processing was requested but the idna module is not
- available."""
-
-
-class IDNAException(dns.exception.DNSException):
- """IDNA processing raised an exception."""
-
- supp_kwargs = {"idna_exception"}
- fmt = "IDNA processing exception: {idna_exception}"
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
-
-class NeedSubdomainOfOrigin(dns.exception.DNSException):
- """An absolute name was provided that is not a subdomain of the specified origin."""
-
-
-_escaped = b'"().;\\@$'
-_escaped_text = '"().;\\@$'
-
-
-def _escapify(label: Union[bytes, str]) -> str:
- """Escape the characters in label which need it.
- @returns: the escaped string
- @rtype: string"""
- if isinstance(label, bytes):
- # Ordinary DNS label mode. Escape special characters and values
- # < 0x20 or > 0x7f.
- text = ""
- for c in label:
- if c in _escaped:
- text += "\\" + chr(c)
- elif c > 0x20 and c < 0x7F:
- text += chr(c)
- else:
- text += "\\%03d" % c
- return text
-
- # Unicode label mode. Escape only special characters and values < 0x20
- text = ""
- for uc in label:
- if uc in _escaped_text:
- text += "\\" + uc
- elif uc <= "\x20":
- text += "\\%03d" % ord(uc)
- else:
- text += uc
- return text
-
-
-class IDNACodec:
- """Abstract base class for IDNA encoder/decoders."""
-
- def __init__(self):
- pass
-
- def is_idna(self, label: bytes) -> bool:
- return label.lower().startswith(b"xn--")
-
- def encode(self, label: str) -> bytes:
- raise NotImplementedError # pragma: no cover
-
- def decode(self, label: bytes) -> str:
- # We do not apply any IDNA policy on decode.
- if self.is_idna(label):
- try:
- slabel = label[4:].decode("punycode")
- return _escapify(slabel)
- except Exception as e:
- raise IDNAException(idna_exception=e)
- else:
- return _escapify(label)
-
-
-class IDNA2003Codec(IDNACodec):
- """IDNA 2003 encoder/decoder."""
-
- def __init__(self, strict_decode: bool = False):
- """Initialize the IDNA 2003 encoder/decoder.
-
- *strict_decode* is a ``bool``. If `True`, then IDNA2003 checking
- is done when decoding. This can cause failures if the name
- was encoded with IDNA2008. The default is `False`.
- """
-
- super().__init__()
- self.strict_decode = strict_decode
-
- def encode(self, label: str) -> bytes:
- """Encode *label*."""
-
- if label == "":
- return b""
- try:
- return encodings.idna.ToASCII(label)
- except UnicodeError:
- raise LabelTooLong
-
- def decode(self, label: bytes) -> str:
- """Decode *label*."""
- if not self.strict_decode:
- return super().decode(label)
- if label == b"":
- return ""
- try:
- return _escapify(encodings.idna.ToUnicode(label))
- except Exception as e:
- raise IDNAException(idna_exception=e)
-
-
-class IDNA2008Codec(IDNACodec):
- """IDNA 2008 encoder/decoder."""
-
- def __init__(
- self,
- uts_46: bool = False,
- transitional: bool = False,
- allow_pure_ascii: bool = False,
- strict_decode: bool = False,
- ):
- """Initialize the IDNA 2008 encoder/decoder.
-
- *uts_46* is a ``bool``. If True, apply Unicode IDNA
- compatibility processing as described in Unicode Technical
- Standard #46 (https://unicode.org/reports/tr46/).
- If False, do not apply the mapping. The default is False.
-
- *transitional* is a ``bool``: If True, use the
- "transitional" mode described in Unicode Technical Standard
- #46. The default is False.
-
- *allow_pure_ascii* is a ``bool``. If True, then a label which
- consists of only ASCII characters is allowed. This is less
- strict than regular IDNA 2008, but is also necessary for mixed
- names, e.g. a name with starting with "_sip._tcp." and ending
- in an IDN suffix which would otherwise be disallowed. The
- default is False.
-
- *strict_decode* is a ``bool``: If True, then IDNA2008 checking
- is done when decoding. This can cause failures if the name
- was encoded with IDNA2003. The default is False.
- """
- super().__init__()
- self.uts_46 = uts_46
- self.transitional = transitional
- self.allow_pure_ascii = allow_pure_ascii
- self.strict_decode = strict_decode
-
- def encode(self, label: str) -> bytes:
- if label == "":
- return b""
- if self.allow_pure_ascii and is_all_ascii(label):
- encoded = label.encode("ascii")
- if len(encoded) > 63:
- raise LabelTooLong
- return encoded
- if not have_idna_2008:
- raise NoIDNA2008
- try:
- if self.uts_46:
- label = idna.uts46_remap(label, False, self.transitional)
- return idna.alabel(label)
- except idna.IDNAError as e:
- if e.args[0] == "Label too long":
- raise LabelTooLong
- else:
- raise IDNAException(idna_exception=e)
-
- def decode(self, label: bytes) -> str:
- if not self.strict_decode:
- return super().decode(label)
- if label == b"":
- return ""
- if not have_idna_2008:
- raise NoIDNA2008
- try:
- ulabel = idna.ulabel(label)
- if self.uts_46:
- ulabel = idna.uts46_remap(ulabel, False, self.transitional)
- return _escapify(ulabel)
- except (idna.IDNAError, UnicodeError) as e:
- raise IDNAException(idna_exception=e)
-
-
-IDNA_2003_Practical = IDNA2003Codec(False)
-IDNA_2003_Strict = IDNA2003Codec(True)
-IDNA_2003 = IDNA_2003_Practical
-IDNA_2008_Practical = IDNA2008Codec(True, False, True, False)
-IDNA_2008_UTS_46 = IDNA2008Codec(True, False, False, False)
-IDNA_2008_Strict = IDNA2008Codec(False, False, False, True)
-IDNA_2008_Transitional = IDNA2008Codec(True, True, False, False)
-IDNA_2008 = IDNA_2008_Practical
-
-
-def _validate_labels(labels: Tuple[bytes, ...]) -> None:
- """Check for empty labels in the middle of a label sequence,
- labels that are too long, and for too many labels.
-
- Raises ``dns.name.NameTooLong`` if the name as a whole is too long.
-
- Raises ``dns.name.EmptyLabel`` if a label is empty (i.e. the root
- label) and appears in a position other than the end of the label
- sequence
-
- """
-
- l = len(labels)
- total = 0
- i = -1
- j = 0
- for label in labels:
- ll = len(label)
- total += ll + 1
- if ll > 63:
- raise LabelTooLong
- if i < 0 and label == b"":
- i = j
- j += 1
- if total > 255:
- raise NameTooLong
- if i >= 0 and i != l - 1:
- raise EmptyLabel
-
-
-def _maybe_convert_to_binary(label: Union[bytes, str]) -> bytes:
- """If label is ``str``, convert it to ``bytes``. If it is already
- ``bytes`` just return it.
-
- """
-
- if isinstance(label, bytes):
- return label
- if isinstance(label, str):
- return label.encode()
- raise ValueError # pragma: no cover
-
-
-@dns.immutable.immutable
-class Name:
- """A DNS name.
-
- The dns.name.Name class represents a DNS name as a tuple of
- labels. Each label is a ``bytes`` in DNS wire format. Instances
- of the class are immutable.
- """
-
- __slots__ = ["labels"]
-
- def __init__(self, labels: Iterable[Union[bytes, str]]):
- """*labels* is any iterable whose values are ``str`` or ``bytes``."""
-
- blabels = [_maybe_convert_to_binary(x) for x in labels]
- self.labels = tuple(blabels)
- _validate_labels(self.labels)
-
- def __copy__(self):
- return Name(self.labels)
-
- def __deepcopy__(self, memo):
- return Name(copy.deepcopy(self.labels, memo))
-
- def __getstate__(self):
- # Names can be pickled
- return {"labels": self.labels}
-
- def __setstate__(self, state):
- super().__setattr__("labels", state["labels"])
- _validate_labels(self.labels)
-
- def is_absolute(self) -> bool:
- """Is the most significant label of this name the root label?
-
- Returns a ``bool``.
- """
-
- return len(self.labels) > 0 and self.labels[-1] == b""
-
- def is_wild(self) -> bool:
- """Is this name wild? (I.e. Is the least significant label '*'?)
-
- Returns a ``bool``.
- """
-
- return len(self.labels) > 0 and self.labels[0] == b"*"
-
- def __hash__(self) -> int:
- """Return a case-insensitive hash of the name.
-
- Returns an ``int``.
- """
-
- h = 0
- for label in self.labels:
- for c in label.lower():
- h += (h << 3) + c
- return h
-
- def fullcompare(self, other: "Name") -> Tuple[NameRelation, int, int]:
- """Compare two names, returning a 3-tuple
- ``(relation, order, nlabels)``.
-
- *relation* describes the relation ship between the names,
- and is one of: ``dns.name.NameRelation.NONE``,
- ``dns.name.NameRelation.SUPERDOMAIN``, ``dns.name.NameRelation.SUBDOMAIN``,
- ``dns.name.NameRelation.EQUAL``, or ``dns.name.NameRelation.COMMONANCESTOR``.
-
- *order* is < 0 if *self* < *other*, > 0 if *self* > *other*, and ==
- 0 if *self* == *other*. A relative name is always less than an
- absolute name. If both names have the same relativity, then
- the DNSSEC order relation is used to order them.
-
- *nlabels* is the number of significant labels that the two names
- have in common.
-
- Here are some examples. Names ending in "." are absolute names,
- those not ending in "." are relative names.
-
- ============= ============= =========== ===== =======
- self other relation order nlabels
- ============= ============= =========== ===== =======
- www.example. www.example. equal 0 3
- www.example. example. subdomain > 0 2
- example. www.example. superdomain < 0 2
- example1.com. example2.com. common anc. < 0 2
- example1 example2. none < 0 0
- example1. example2 none > 0 0
- ============= ============= =========== ===== =======
- """
-
- sabs = self.is_absolute()
- oabs = other.is_absolute()
- if sabs != oabs:
- if sabs:
- return (NameRelation.NONE, 1, 0)
- else:
- return (NameRelation.NONE, -1, 0)
- l1 = len(self.labels)
- l2 = len(other.labels)
- ldiff = l1 - l2
- if ldiff < 0:
- l = l1
- else:
- l = l2
-
- order = 0
- nlabels = 0
- namereln = NameRelation.NONE
- while l > 0:
- l -= 1
- l1 -= 1
- l2 -= 1
- label1 = self.labels[l1].lower()
- label2 = other.labels[l2].lower()
- if label1 < label2:
- order = -1
- if nlabels > 0:
- namereln = NameRelation.COMMONANCESTOR
- return (namereln, order, nlabels)
- elif label1 > label2:
- order = 1
- if nlabels > 0:
- namereln = NameRelation.COMMONANCESTOR
- return (namereln, order, nlabels)
- nlabels += 1
- order = ldiff
- if ldiff < 0:
- namereln = NameRelation.SUPERDOMAIN
- elif ldiff > 0:
- namereln = NameRelation.SUBDOMAIN
- else:
- namereln = NameRelation.EQUAL
- return (namereln, order, nlabels)
-
- def is_subdomain(self, other: "Name") -> bool:
- """Is self a subdomain of other?
-
- Note that the notion of subdomain includes equality, e.g.
- "dnspython.org" is a subdomain of itself.
-
- Returns a ``bool``.
- """
-
- (nr, _, _) = self.fullcompare(other)
- if nr == NameRelation.SUBDOMAIN or nr == NameRelation.EQUAL:
- return True
- return False
-
- def is_superdomain(self, other: "Name") -> bool:
- """Is self a superdomain of other?
-
- Note that the notion of superdomain includes equality, e.g.
- "dnspython.org" is a superdomain of itself.
-
- Returns a ``bool``.
- """
-
- (nr, _, _) = self.fullcompare(other)
- if nr == NameRelation.SUPERDOMAIN or nr == NameRelation.EQUAL:
- return True
- return False
-
- def canonicalize(self) -> "Name":
- """Return a name which is equal to the current name, but is in
- DNSSEC canonical form.
- """
-
- return Name([x.lower() for x in self.labels])
-
- def __eq__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] == 0
- else:
- return False
-
- def __ne__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] != 0
- else:
- return True
-
- def __lt__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] < 0
- else:
- return NotImplemented
-
- def __le__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] <= 0
- else:
- return NotImplemented
-
- def __ge__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] >= 0
- else:
- return NotImplemented
-
- def __gt__(self, other):
- if isinstance(other, Name):
- return self.fullcompare(other)[1] > 0
- else:
- return NotImplemented
-
- def __repr__(self):
- return ""
-
- def __str__(self):
- return self.to_text(False)
-
- def to_text(self, omit_final_dot: bool = False) -> str:
- """Convert name to DNS text format.
-
- *omit_final_dot* is a ``bool``. If True, don't emit the final
- dot (denoting the root label) for absolute names. The default
- is False.
-
- Returns a ``str``.
- """
-
- if len(self.labels) == 0:
- return "@"
- if len(self.labels) == 1 and self.labels[0] == b"":
- return "."
- if omit_final_dot and self.is_absolute():
- l = self.labels[:-1]
- else:
- l = self.labels
- s = ".".join(map(_escapify, l))
- return s
-
- def to_unicode(
- self, omit_final_dot: bool = False, idna_codec: Optional[IDNACodec] = None
- ) -> str:
- """Convert name to Unicode text format.
-
- IDN ACE labels are converted to Unicode.
-
- *omit_final_dot* is a ``bool``. If True, don't emit the final
- dot (denoting the root label) for absolute names. The default
- is False.
- *idna_codec* specifies the IDNA encoder/decoder. If None, the
- dns.name.IDNA_2003_Practical encoder/decoder is used.
- The IDNA_2003_Practical decoder does
- not impose any policy, it just decodes punycode, so if you
- don't want checking for compliance, you can use this decoder
- for IDNA2008 as well.
-
- Returns a ``str``.
- """
-
- if len(self.labels) == 0:
- return "@"
- if len(self.labels) == 1 and self.labels[0] == b"":
- return "."
- if omit_final_dot and self.is_absolute():
- l = self.labels[:-1]
- else:
- l = self.labels
- if idna_codec is None:
- idna_codec = IDNA_2003_Practical
- return ".".join([idna_codec.decode(x) for x in l])
-
- def to_digestable(self, origin: Optional["Name"] = None) -> bytes:
- """Convert name to a format suitable for digesting in hashes.
-
- The name is canonicalized and converted to uncompressed wire
- format. All names in wire format are absolute. If the name
- is a relative name, then an origin must be supplied.
-
- *origin* is a ``dns.name.Name`` or ``None``. If the name is
- relative and origin is not ``None``, then origin will be appended
- to the name.
-
- Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
- relative and no origin was provided.
-
- Returns a ``bytes``.
- """
-
- digest = self.to_wire(origin=origin, canonicalize=True)
- assert digest is not None
- return digest
-
- def to_wire(
- self,
- file: Optional[Any] = None,
- compress: Optional[CompressType] = None,
- origin: Optional["Name"] = None,
- canonicalize: bool = False,
- ) -> Optional[bytes]:
- """Convert name to wire format, possibly compressing it.
-
- *file* is the file where the name is emitted (typically an
- io.BytesIO file). If ``None`` (the default), a ``bytes``
- containing the wire name will be returned.
-
- *compress*, a ``dict``, is the compression table to use. If
- ``None`` (the default), names will not be compressed. Note that
- the compression code assumes that compression offset 0 is the
- start of *file*, and thus compression will not be correct
- if this is not the case.
-
- *origin* is a ``dns.name.Name`` or ``None``. If the name is
- relative and origin is not ``None``, then *origin* will be appended
- to it.
-
- *canonicalize*, a ``bool``, indicates whether the name should
- be canonicalized; that is, converted to a format suitable for
- digesting in hashes.
-
- Raises ``dns.name.NeedAbsoluteNameOrOrigin`` if the name is
- relative and no origin was provided.
-
- Returns a ``bytes`` or ``None``.
- """
-
- if file is None:
- out = bytearray()
- for label in self.labels:
- out.append(len(label))
- if canonicalize:
- out += label.lower()
- else:
- out += label
- if not self.is_absolute():
- if origin is None or not origin.is_absolute():
- raise NeedAbsoluteNameOrOrigin
- for label in origin.labels:
- out.append(len(label))
- if canonicalize:
- out += label.lower()
- else:
- out += label
- return bytes(out)
-
- labels: Iterable[bytes]
- if not self.is_absolute():
- if origin is None or not origin.is_absolute():
- raise NeedAbsoluteNameOrOrigin
- labels = list(self.labels)
- labels.extend(list(origin.labels))
- else:
- labels = self.labels
- i = 0
- for label in labels:
- n = Name(labels[i:])
- i += 1
- if compress is not None:
- pos = compress.get(n)
- else:
- pos = None
- if pos is not None:
- value = 0xC000 + pos
- s = struct.pack("!H", value)
- file.write(s)
- break
- else:
- if compress is not None and len(n) > 1:
- pos = file.tell()
- if pos <= 0x3FFF:
- compress[n] = pos
- l = len(label)
- file.write(struct.pack("!B", l))
- if l > 0:
- if canonicalize:
- file.write(label.lower())
- else:
- file.write(label)
- return None
-
- def __len__(self) -> int:
- """The length of the name (in labels).
-
- Returns an ``int``.
- """
-
- return len(self.labels)
-
- def __getitem__(self, index):
- return self.labels[index]
-
- def __add__(self, other):
- return self.concatenate(other)
-
- def __sub__(self, other):
- return self.relativize(other)
-
- def split(self, depth: int) -> Tuple["Name", "Name"]:
- """Split a name into a prefix and suffix names at the specified depth.
-
- *depth* is an ``int`` specifying the number of labels in the suffix
-
- Raises ``ValueError`` if *depth* was not >= 0 and <= the length of the
- name.
-
- Returns the tuple ``(prefix, suffix)``.
- """
-
- l = len(self.labels)
- if depth == 0:
- return (self, dns.name.empty)
- elif depth == l:
- return (dns.name.empty, self)
- elif depth < 0 or depth > l:
- raise ValueError("depth must be >= 0 and <= the length of the name")
- return (Name(self[:-depth]), Name(self[-depth:]))
-
- def concatenate(self, other: "Name") -> "Name":
- """Return a new name which is the concatenation of self and other.
-
- Raises ``dns.name.AbsoluteConcatenation`` if the name is
- absolute and *other* is not the empty name.
-
- Returns a ``dns.name.Name``.
- """
-
- if self.is_absolute() and len(other) > 0:
- raise AbsoluteConcatenation
- labels = list(self.labels)
- labels.extend(list(other.labels))
- return Name(labels)
-
- def relativize(self, origin: "Name") -> "Name":
- """If the name is a subdomain of *origin*, return a new name which is
- the name relative to origin. Otherwise return the name.
-
- For example, relativizing ``www.dnspython.org.`` to origin
- ``dnspython.org.`` returns the name ``www``. Relativizing ``example.``
- to origin ``dnspython.org.`` returns ``example.``.
-
- Returns a ``dns.name.Name``.
- """
-
- if origin is not None and self.is_subdomain(origin):
- return Name(self[: -len(origin)])
- else:
- return self
-
- def derelativize(self, origin: "Name") -> "Name":
- """If the name is a relative name, return a new name which is the
- concatenation of the name and origin. Otherwise return the name.
-
- For example, derelativizing ``www`` to origin ``dnspython.org.``
- returns the name ``www.dnspython.org.``. Derelativizing ``example.``
- to origin ``dnspython.org.`` returns ``example.``.
-
- Returns a ``dns.name.Name``.
- """
-
- if not self.is_absolute():
- return self.concatenate(origin)
- else:
- return self
-
- def choose_relativity(
- self, origin: Optional["Name"] = None, relativize: bool = True
- ) -> "Name":
- """Return a name with the relativity desired by the caller.
-
- If *origin* is ``None``, then the name is returned.
- Otherwise, if *relativize* is ``True`` the name is
- relativized, and if *relativize* is ``False`` the name is
- derelativized.
-
- Returns a ``dns.name.Name``.
- """
-
- if origin:
- if relativize:
- return self.relativize(origin)
- else:
- return self.derelativize(origin)
- else:
- return self
-
- def parent(self) -> "Name":
- """Return the parent of the name.
-
- For example, the parent of ``www.dnspython.org.`` is ``dnspython.org``.
-
- Raises ``dns.name.NoParent`` if the name is either the root name or the
- empty name, and thus has no parent.
-
- Returns a ``dns.name.Name``.
- """
-
- if self == root or self == empty:
- raise NoParent
- return Name(self.labels[1:])
-
- def predecessor(self, origin: "Name", prefix_ok: bool = True) -> "Name":
- """Return the maximal predecessor of *name* in the DNSSEC ordering in the zone
- whose origin is *origin*, or return the longest name under *origin* if the
- name is origin (i.e. wrap around to the longest name, which may still be
- *origin* due to length considerations.
-
- The relativity of the name is preserved, so if this name is relative
- then the method will return a relative name, and likewise if this name
- is absolute then the predecessor will be absolute.
-
- *prefix_ok* indicates if prefixing labels is allowed, and
- defaults to ``True``. Normally it is good to allow this, but if computing
- a maximal predecessor at a zone cut point then ``False`` must be specified.
- """
- return _handle_relativity_and_call(
- _absolute_predecessor, self, origin, prefix_ok
- )
-
- def successor(self, origin: "Name", prefix_ok: bool = True) -> "Name":
- """Return the minimal successor of *name* in the DNSSEC ordering in the zone
- whose origin is *origin*, or return *origin* if the successor cannot be
- computed due to name length limitations.
-
- Note that *origin* is returned in the "too long" cases because wrapping
- around to the origin is how NSEC records express "end of the zone".
-
- The relativity of the name is preserved, so if this name is relative
- then the method will return a relative name, and likewise if this name
- is absolute then the successor will be absolute.
-
- *prefix_ok* indicates if prefixing a new minimal label is allowed, and
- defaults to ``True``. Normally it is good to allow this, but if computing
- a minimal successor at a zone cut point then ``False`` must be specified.
- """
- return _handle_relativity_and_call(_absolute_successor, self, origin, prefix_ok)
-
-
-#: The root name, '.'
-root = Name([b""])
-
-#: The empty name.
-empty = Name([])
-
-
-def from_unicode(
- text: str, origin: Optional[Name] = root, idna_codec: Optional[IDNACodec] = None
-) -> Name:
- """Convert unicode text into a Name object.
-
- Labels are encoded in IDN ACE form according to rules specified by
- the IDNA codec.
-
- *text*, a ``str``, is the text to convert into a name.
-
- *origin*, a ``dns.name.Name``, specifies the origin to
- append to non-absolute names. The default is the root name.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- Returns a ``dns.name.Name``.
- """
-
- if not isinstance(text, str):
- raise ValueError("input to from_unicode() must be a unicode string")
- if not (origin is None or isinstance(origin, Name)):
- raise ValueError("origin must be a Name or None")
- labels = []
- label = ""
- escaping = False
- edigits = 0
- total = 0
- if idna_codec is None:
- idna_codec = IDNA_2003
- if text == "@":
- text = ""
- if text:
- if text in [".", "\u3002", "\uff0e", "\uff61"]:
- return Name([b""]) # no Unicode "u" on this constant!
- for c in text:
- if escaping:
- if edigits == 0:
- if c.isdigit():
- total = int(c)
- edigits += 1
- else:
- label += c
- escaping = False
- else:
- if not c.isdigit():
- raise BadEscape
- total *= 10
- total += int(c)
- edigits += 1
- if edigits == 3:
- escaping = False
- label += chr(total)
- elif c in [".", "\u3002", "\uff0e", "\uff61"]:
- if len(label) == 0:
- raise EmptyLabel
- labels.append(idna_codec.encode(label))
- label = ""
- elif c == "\\":
- escaping = True
- edigits = 0
- total = 0
- else:
- label += c
- if escaping:
- raise BadEscape
- if len(label) > 0:
- labels.append(idna_codec.encode(label))
- else:
- labels.append(b"")
-
- if (len(labels) == 0 or labels[-1] != b"") and origin is not None:
- labels.extend(list(origin.labels))
- return Name(labels)
-
-
-def is_all_ascii(text: str) -> bool:
- for c in text:
- if ord(c) > 0x7F:
- return False
- return True
-
-
-def from_text(
- text: Union[bytes, str],
- origin: Optional[Name] = root,
- idna_codec: Optional[IDNACodec] = None,
-) -> Name:
- """Convert text into a Name object.
-
- *text*, a ``bytes`` or ``str``, is the text to convert into a name.
-
- *origin*, a ``dns.name.Name``, specifies the origin to
- append to non-absolute names. The default is the root name.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- Returns a ``dns.name.Name``.
- """
-
- if isinstance(text, str):
- if not is_all_ascii(text):
- # Some codepoint in the input text is > 127, so IDNA applies.
- return from_unicode(text, origin, idna_codec)
- # The input is all ASCII, so treat this like an ordinary non-IDNA
- # domain name. Note that "all ASCII" is about the input text,
- # not the codepoints in the domain name. E.g. if text has value
- #
- # r'\150\151\152\153\154\155\156\157\158\159'
- #
- # then it's still "all ASCII" even though the domain name has
- # codepoints > 127.
- text = text.encode("ascii")
- if not isinstance(text, bytes):
- raise ValueError("input to from_text() must be a string")
- if not (origin is None or isinstance(origin, Name)):
- raise ValueError("origin must be a Name or None")
- labels = []
- label = b""
- escaping = False
- edigits = 0
- total = 0
- if text == b"@":
- text = b""
- if text:
- if text == b".":
- return Name([b""])
- for c in text:
- byte_ = struct.pack("!B", c)
- if escaping:
- if edigits == 0:
- if byte_.isdigit():
- total = int(byte_)
- edigits += 1
- else:
- label += byte_
- escaping = False
- else:
- if not byte_.isdigit():
- raise BadEscape
- total *= 10
- total += int(byte_)
- edigits += 1
- if edigits == 3:
- escaping = False
- label += struct.pack("!B", total)
- elif byte_ == b".":
- if len(label) == 0:
- raise EmptyLabel
- labels.append(label)
- label = b""
- elif byte_ == b"\\":
- escaping = True
- edigits = 0
- total = 0
- else:
- label += byte_
- if escaping:
- raise BadEscape
- if len(label) > 0:
- labels.append(label)
- else:
- labels.append(b"")
- if (len(labels) == 0 or labels[-1] != b"") and origin is not None:
- labels.extend(list(origin.labels))
- return Name(labels)
-
-
-# we need 'dns.wire.Parser' quoted as dns.name and dns.wire depend on each other.
-
-
-def from_wire_parser(parser: "dns.wire.Parser") -> Name:
- """Convert possibly compressed wire format into a Name.
-
- *parser* is a dns.wire.Parser.
-
- Raises ``dns.name.BadPointer`` if a compression pointer did not
- point backwards in the message.
-
- Raises ``dns.name.BadLabelType`` if an invalid label type was encountered.
-
- Returns a ``dns.name.Name``
- """
-
- labels = []
- biggest_pointer = parser.current
- with parser.restore_furthest():
- count = parser.get_uint8()
- while count != 0:
- if count < 64:
- labels.append(parser.get_bytes(count))
- elif count >= 192:
- current = (count & 0x3F) * 256 + parser.get_uint8()
- if current >= biggest_pointer:
- raise BadPointer
- biggest_pointer = current
- parser.seek(current)
- else:
- raise BadLabelType
- count = parser.get_uint8()
- labels.append(b"")
- return Name(labels)
-
-
-def from_wire(message: bytes, current: int) -> Tuple[Name, int]:
- """Convert possibly compressed wire format into a Name.
-
- *message* is a ``bytes`` containing an entire DNS message in DNS
- wire form.
-
- *current*, an ``int``, is the offset of the beginning of the name
- from the start of the message
-
- Raises ``dns.name.BadPointer`` if a compression pointer did not
- point backwards in the message.
-
- Raises ``dns.name.BadLabelType`` if an invalid label type was encountered.
-
- Returns a ``(dns.name.Name, int)`` tuple consisting of the name
- that was read and the number of bytes of the wire format message
- which were consumed reading it.
- """
-
- if not isinstance(message, bytes):
- raise ValueError("input to from_wire() must be a byte string")
- parser = dns.wire.Parser(message, current)
- name = from_wire_parser(parser)
- return (name, parser.current - current)
-
-
-# RFC 4471 Support
-
-_MINIMAL_OCTET = b"\x00"
-_MINIMAL_OCTET_VALUE = ord(_MINIMAL_OCTET)
-_SUCCESSOR_PREFIX = Name([_MINIMAL_OCTET])
-_MAXIMAL_OCTET = b"\xff"
-_MAXIMAL_OCTET_VALUE = ord(_MAXIMAL_OCTET)
-_AT_SIGN_VALUE = ord("@")
-_LEFT_SQUARE_BRACKET_VALUE = ord("[")
-
-
-def _wire_length(labels):
- return functools.reduce(lambda v, x: v + len(x) + 1, labels, 0)
-
-
-def _pad_to_max_name(name):
- needed = 255 - _wire_length(name.labels)
- new_labels = []
- while needed > 64:
- new_labels.append(_MAXIMAL_OCTET * 63)
- needed -= 64
- if needed >= 2:
- new_labels.append(_MAXIMAL_OCTET * (needed - 1))
- # Note we're already maximal in the needed == 1 case as while we'd like
- # to add one more byte as a new label, we can't, as adding a new non-empty
- # label requires at least 2 bytes.
- new_labels = list(reversed(new_labels))
- new_labels.extend(name.labels)
- return Name(new_labels)
-
-
-def _pad_to_max_label(label, suffix_labels):
- length = len(label)
- # We have to subtract one here to account for the length byte of label.
- remaining = 255 - _wire_length(suffix_labels) - length - 1
- if remaining <= 0:
- # Shouldn't happen!
- return label
- needed = min(63 - length, remaining)
- return label + _MAXIMAL_OCTET * needed
-
-
-def _absolute_predecessor(name: Name, origin: Name, prefix_ok: bool) -> Name:
- # This is the RFC 4471 predecessor algorithm using the "absolute method" of section
- # 3.1.1.
- #
- # Our caller must ensure that the name and origin are absolute, and that name is a
- # subdomain of origin.
- if name == origin:
- return _pad_to_max_name(name)
- least_significant_label = name[0]
- if least_significant_label == _MINIMAL_OCTET:
- return name.parent()
- least_octet = least_significant_label[-1]
- suffix_labels = name.labels[1:]
- if least_octet == _MINIMAL_OCTET_VALUE:
- new_labels = [least_significant_label[:-1]]
- else:
- octets = bytearray(least_significant_label)
- octet = octets[-1]
- if octet == _LEFT_SQUARE_BRACKET_VALUE:
- octet = _AT_SIGN_VALUE
- else:
- octet -= 1
- octets[-1] = octet
- least_significant_label = bytes(octets)
- new_labels = [_pad_to_max_label(least_significant_label, suffix_labels)]
- new_labels.extend(suffix_labels)
- name = Name(new_labels)
- if prefix_ok:
- return _pad_to_max_name(name)
- else:
- return name
-
-
-def _absolute_successor(name: Name, origin: Name, prefix_ok: bool) -> Name:
- # This is the RFC 4471 successor algorithm using the "absolute method" of section
- # 3.1.2.
- #
- # Our caller must ensure that the name and origin are absolute, and that name is a
- # subdomain of origin.
- if prefix_ok:
- # Try prefixing \000 as new label
- try:
- return _SUCCESSOR_PREFIX.concatenate(name)
- except NameTooLong:
- pass
- while name != origin:
- # Try extending the least significant label.
- least_significant_label = name[0]
- if len(least_significant_label) < 63:
- # We may be able to extend the least label with a minimal additional byte.
- # This is only "may" because we could have a maximal length name even though
- # the least significant label isn't maximally long.
- new_labels = [least_significant_label + _MINIMAL_OCTET]
- new_labels.extend(name.labels[1:])
- try:
- return dns.name.Name(new_labels)
- except dns.name.NameTooLong:
- pass
- # We can't extend the label either, so we'll try to increment the least
- # signficant non-maximal byte in it.
- octets = bytearray(least_significant_label)
- # We do this reversed iteration with an explicit indexing variable because
- # if we find something to increment, we're going to want to truncate everything
- # to the right of it.
- for i in range(len(octets) - 1, -1, -1):
- octet = octets[i]
- if octet == _MAXIMAL_OCTET_VALUE:
- # We can't increment this, so keep looking.
- continue
- # Finally, something we can increment. We have to apply a special rule for
- # incrementing "@", sending it to "[", because RFC 4034 6.1 says that when
- # comparing names, uppercase letters compare as if they were their
- # lower-case equivalents. If we increment "@" to "A", then it would compare
- # as "a", which is after "[", "\", "]", "^", "_", and "`", so we would have
- # skipped the most minimal successor, namely "[".
- if octet == _AT_SIGN_VALUE:
- octet = _LEFT_SQUARE_BRACKET_VALUE
- else:
- octet += 1
- octets[i] = octet
- # We can now truncate all of the maximal values we skipped (if any)
- new_labels = [bytes(octets[: i + 1])]
- new_labels.extend(name.labels[1:])
- # We haven't changed the length of the name, so the Name constructor will
- # always work.
- return Name(new_labels)
- # We couldn't increment, so chop off the least significant label and try
- # again.
- name = name.parent()
-
- # We couldn't increment at all, so return the origin, as wrapping around is the
- # DNSSEC way.
- return origin
-
-
-def _handle_relativity_and_call(
- function: Callable[[Name, Name, bool], Name],
- name: Name,
- origin: Name,
- prefix_ok: bool,
-) -> Name:
- # Make "name" absolute if needed, ensure that the origin is absolute,
- # call function(), and then relativize the result if needed.
- if not origin.is_absolute():
- raise NeedAbsoluteNameOrOrigin
- relative = not name.is_absolute()
- if relative:
- name = name.derelativize(origin)
- elif not name.is_subdomain(origin):
- raise NeedSubdomainOfOrigin
- result_name = function(name, origin, prefix_ok)
- if relative:
- result_name = result_name.relativize(origin)
- return result_name
diff --git a/.venv/lib/python3.12/site-packages/dns/namedict.py b/.venv/lib/python3.12/site-packages/dns/namedict.py
deleted file mode 100644
index ca8b197..0000000
--- a/.venv/lib/python3.12/site-packages/dns/namedict.py
+++ /dev/null
@@ -1,109 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-# Copyright (C) 2016 Coresec Systems AB
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND CORESEC SYSTEMS AB DISCLAIMS ALL
-# WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-# WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL CORESEC
-# SYSTEMS AB BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
-# CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
-# OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
-# NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
-# WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS name dictionary"""
-
-# pylint seems to be confused about this one!
-from collections.abc import MutableMapping # pylint: disable=no-name-in-module
-
-import dns.name
-
-
-class NameDict(MutableMapping):
- """A dictionary whose keys are dns.name.Name objects.
-
- In addition to being like a regular Python dictionary, this
- dictionary can also get the deepest match for a given key.
- """
-
- __slots__ = ["max_depth", "max_depth_items", "__store"]
-
- def __init__(self, *args, **kwargs):
- super().__init__()
- self.__store = dict()
- #: the maximum depth of the keys that have ever been added
- self.max_depth = 0
- #: the number of items of maximum depth
- self.max_depth_items = 0
- self.update(dict(*args, **kwargs))
-
- def __update_max_depth(self, key):
- if len(key) == self.max_depth:
- self.max_depth_items = self.max_depth_items + 1
- elif len(key) > self.max_depth:
- self.max_depth = len(key)
- self.max_depth_items = 1
-
- def __getitem__(self, key):
- return self.__store[key]
-
- def __setitem__(self, key, value):
- if not isinstance(key, dns.name.Name):
- raise ValueError("NameDict key must be a name")
- self.__store[key] = value
- self.__update_max_depth(key)
-
- def __delitem__(self, key):
- self.__store.pop(key)
- if len(key) == self.max_depth:
- self.max_depth_items = self.max_depth_items - 1
- if self.max_depth_items == 0:
- self.max_depth = 0
- for k in self.__store:
- self.__update_max_depth(k)
-
- def __iter__(self):
- return iter(self.__store)
-
- def __len__(self):
- return len(self.__store)
-
- def has_key(self, key):
- return key in self.__store
-
- def get_deepest_match(self, name):
- """Find the deepest match to *name* in the dictionary.
-
- The deepest match is the longest name in the dictionary which is
- a superdomain of *name*. Note that *superdomain* includes matching
- *name* itself.
-
- *name*, a ``dns.name.Name``, the name to find.
-
- Returns a ``(key, value)`` where *key* is the deepest
- ``dns.name.Name``, and *value* is the value associated with *key*.
- """
-
- depth = len(name)
- if depth > self.max_depth:
- depth = self.max_depth
- for i in range(-depth, 0):
- n = dns.name.Name(name[i:])
- if n in self:
- return (n, self[n])
- v = self[dns.name.empty]
- return (dns.name.empty, v)
diff --git a/.venv/lib/python3.12/site-packages/dns/nameserver.py b/.venv/lib/python3.12/site-packages/dns/nameserver.py
deleted file mode 100644
index 5dbb4e8..0000000
--- a/.venv/lib/python3.12/site-packages/dns/nameserver.py
+++ /dev/null
@@ -1,359 +0,0 @@
-from typing import Optional, Union
-from urllib.parse import urlparse
-
-import dns.asyncbackend
-import dns.asyncquery
-import dns.inet
-import dns.message
-import dns.query
-
-
-class Nameserver:
- def __init__(self):
- pass
-
- def __str__(self):
- raise NotImplementedError
-
- def kind(self) -> str:
- raise NotImplementedError
-
- def is_always_max_size(self) -> bool:
- raise NotImplementedError
-
- def answer_nameserver(self) -> str:
- raise NotImplementedError
-
- def answer_port(self) -> int:
- raise NotImplementedError
-
- def query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- raise NotImplementedError
-
- async def async_query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- backend: dns.asyncbackend.Backend,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- raise NotImplementedError
-
-
-class AddressAndPortNameserver(Nameserver):
- def __init__(self, address: str, port: int):
- super().__init__()
- self.address = address
- self.port = port
-
- def kind(self) -> str:
- raise NotImplementedError
-
- def is_always_max_size(self) -> bool:
- return False
-
- def __str__(self):
- ns_kind = self.kind()
- return f"{ns_kind}:{self.address}@{self.port}"
-
- def answer_nameserver(self) -> str:
- return self.address
-
- def answer_port(self) -> int:
- return self.port
-
-
-class Do53Nameserver(AddressAndPortNameserver):
- def __init__(self, address: str, port: int = 53):
- super().__init__(address, port)
-
- def kind(self):
- return "Do53"
-
- def query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- if max_size:
- response = dns.query.tcp(
- request,
- self.address,
- timeout=timeout,
- port=self.port,
- source=source,
- source_port=source_port,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- else:
- response = dns.query.udp(
- request,
- self.address,
- timeout=timeout,
- port=self.port,
- source=source,
- source_port=source_port,
- raise_on_truncation=True,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- ignore_errors=True,
- ignore_unexpected=True,
- )
- return response
-
- async def async_query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- backend: dns.asyncbackend.Backend,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- if max_size:
- response = await dns.asyncquery.tcp(
- request,
- self.address,
- timeout=timeout,
- port=self.port,
- source=source,
- source_port=source_port,
- backend=backend,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- else:
- response = await dns.asyncquery.udp(
- request,
- self.address,
- timeout=timeout,
- port=self.port,
- source=source,
- source_port=source_port,
- raise_on_truncation=True,
- backend=backend,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- ignore_errors=True,
- ignore_unexpected=True,
- )
- return response
-
-
-class DoHNameserver(Nameserver):
- def __init__(
- self,
- url: str,
- bootstrap_address: Optional[str] = None,
- verify: Union[bool, str] = True,
- want_get: bool = False,
- ):
- super().__init__()
- self.url = url
- self.bootstrap_address = bootstrap_address
- self.verify = verify
- self.want_get = want_get
-
- def kind(self):
- return "DoH"
-
- def is_always_max_size(self) -> bool:
- return True
-
- def __str__(self):
- return self.url
-
- def answer_nameserver(self) -> str:
- return self.url
-
- def answer_port(self) -> int:
- port = urlparse(self.url).port
- if port is None:
- port = 443
- return port
-
- def query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return dns.query.https(
- request,
- self.url,
- timeout=timeout,
- source=source,
- source_port=source_port,
- bootstrap_address=self.bootstrap_address,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- verify=self.verify,
- post=(not self.want_get),
- )
-
- async def async_query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- backend: dns.asyncbackend.Backend,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return await dns.asyncquery.https(
- request,
- self.url,
- timeout=timeout,
- source=source,
- source_port=source_port,
- bootstrap_address=self.bootstrap_address,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- verify=self.verify,
- post=(not self.want_get),
- )
-
-
-class DoTNameserver(AddressAndPortNameserver):
- def __init__(
- self,
- address: str,
- port: int = 853,
- hostname: Optional[str] = None,
- verify: Union[bool, str] = True,
- ):
- super().__init__(address, port)
- self.hostname = hostname
- self.verify = verify
-
- def kind(self):
- return "DoT"
-
- def query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return dns.query.tls(
- request,
- self.address,
- port=self.port,
- timeout=timeout,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- server_hostname=self.hostname,
- verify=self.verify,
- )
-
- async def async_query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- backend: dns.asyncbackend.Backend,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return await dns.asyncquery.tls(
- request,
- self.address,
- port=self.port,
- timeout=timeout,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- server_hostname=self.hostname,
- verify=self.verify,
- )
-
-
-class DoQNameserver(AddressAndPortNameserver):
- def __init__(
- self,
- address: str,
- port: int = 853,
- verify: Union[bool, str] = True,
- server_hostname: Optional[str] = None,
- ):
- super().__init__(address, port)
- self.verify = verify
- self.server_hostname = server_hostname
-
- def kind(self):
- return "DoQ"
-
- def query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return dns.query.quic(
- request,
- self.address,
- port=self.port,
- timeout=timeout,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- verify=self.verify,
- server_hostname=self.server_hostname,
- )
-
- async def async_query(
- self,
- request: dns.message.QueryMessage,
- timeout: float,
- source: Optional[str],
- source_port: int,
- max_size: bool,
- backend: dns.asyncbackend.Backend,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- ) -> dns.message.Message:
- return await dns.asyncquery.quic(
- request,
- self.address,
- port=self.port,
- timeout=timeout,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- verify=self.verify,
- server_hostname=self.server_hostname,
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/node.py b/.venv/lib/python3.12/site-packages/dns/node.py
deleted file mode 100644
index de85a82..0000000
--- a/.venv/lib/python3.12/site-packages/dns/node.py
+++ /dev/null
@@ -1,359 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS nodes. A node is a set of rdatasets."""
-
-import enum
-import io
-from typing import Any, Dict, Optional
-
-import dns.immutable
-import dns.name
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.renderer
-import dns.rrset
-
-_cname_types = {
- dns.rdatatype.CNAME,
-}
-
-# "neutral" types can coexist with a CNAME and thus are not "other data"
-_neutral_types = {
- dns.rdatatype.NSEC, # RFC 4035 section 2.5
- dns.rdatatype.NSEC3, # This is not likely to happen, but not impossible!
- dns.rdatatype.KEY, # RFC 4035 section 2.5, RFC 3007
-}
-
-
-def _matches_type_or_its_signature(rdtypes, rdtype, covers):
- return rdtype in rdtypes or (rdtype == dns.rdatatype.RRSIG and covers in rdtypes)
-
-
-@enum.unique
-class NodeKind(enum.Enum):
- """Rdatasets in nodes"""
-
- REGULAR = 0 # a.k.a "other data"
- NEUTRAL = 1
- CNAME = 2
-
- @classmethod
- def classify(
- cls, rdtype: dns.rdatatype.RdataType, covers: dns.rdatatype.RdataType
- ) -> "NodeKind":
- if _matches_type_or_its_signature(_cname_types, rdtype, covers):
- return NodeKind.CNAME
- elif _matches_type_or_its_signature(_neutral_types, rdtype, covers):
- return NodeKind.NEUTRAL
- else:
- return NodeKind.REGULAR
-
- @classmethod
- def classify_rdataset(cls, rdataset: dns.rdataset.Rdataset) -> "NodeKind":
- return cls.classify(rdataset.rdtype, rdataset.covers)
-
-
-class Node:
- """A Node is a set of rdatasets.
-
- A node is either a CNAME node or an "other data" node. A CNAME
- node contains only CNAME, KEY, NSEC, and NSEC3 rdatasets along with their
- covering RRSIG rdatasets. An "other data" node contains any
- rdataset other than a CNAME or RRSIG(CNAME) rdataset. When
- changes are made to a node, the CNAME or "other data" state is
- always consistent with the update, i.e. the most recent change
- wins. For example, if you have a node which contains a CNAME
- rdataset, and then add an MX rdataset to it, then the CNAME
- rdataset will be deleted. Likewise if you have a node containing
- an MX rdataset and add a CNAME rdataset, the MX rdataset will be
- deleted.
- """
-
- __slots__ = ["rdatasets"]
-
- def __init__(self):
- # the set of rdatasets, represented as a list.
- self.rdatasets = []
-
- def to_text(self, name: dns.name.Name, **kw: Dict[str, Any]) -> str:
- """Convert a node to text format.
-
- Each rdataset at the node is printed. Any keyword arguments
- to this method are passed on to the rdataset's to_text() method.
-
- *name*, a ``dns.name.Name``, the owner name of the
- rdatasets.
-
- Returns a ``str``.
-
- """
-
- s = io.StringIO()
- for rds in self.rdatasets:
- if len(rds) > 0:
- s.write(rds.to_text(name, **kw)) # type: ignore[arg-type]
- s.write("\n")
- return s.getvalue()[:-1]
-
- def __repr__(self):
- return ""
-
- def __eq__(self, other):
- #
- # This is inefficient. Good thing we don't need to do it much.
- #
- for rd in self.rdatasets:
- if rd not in other.rdatasets:
- return False
- for rd in other.rdatasets:
- if rd not in self.rdatasets:
- return False
- return True
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def __len__(self):
- return len(self.rdatasets)
-
- def __iter__(self):
- return iter(self.rdatasets)
-
- def _append_rdataset(self, rdataset):
- """Append rdataset to the node with special handling for CNAME and
- other data conditions.
-
- Specifically, if the rdataset being appended has ``NodeKind.CNAME``,
- then all rdatasets other than KEY, NSEC, NSEC3, and their covering
- RRSIGs are deleted. If the rdataset being appended has
- ``NodeKind.REGULAR`` then CNAME and RRSIG(CNAME) are deleted.
- """
- # Make having just one rdataset at the node fast.
- if len(self.rdatasets) > 0:
- kind = NodeKind.classify_rdataset(rdataset)
- if kind == NodeKind.CNAME:
- self.rdatasets = [
- rds
- for rds in self.rdatasets
- if NodeKind.classify_rdataset(rds) != NodeKind.REGULAR
- ]
- elif kind == NodeKind.REGULAR:
- self.rdatasets = [
- rds
- for rds in self.rdatasets
- if NodeKind.classify_rdataset(rds) != NodeKind.CNAME
- ]
- # Otherwise the rdataset is NodeKind.NEUTRAL and we do not need to
- # edit self.rdatasets.
- self.rdatasets.append(rdataset)
-
- def find_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> dns.rdataset.Rdataset:
- """Find an rdataset matching the specified properties in the
- current node.
-
- *rdclass*, a ``dns.rdataclass.RdataClass``, the class of the rdataset.
-
- *rdtype*, a ``dns.rdatatype.RdataType``, the type of the rdataset.
-
- *covers*, a ``dns.rdatatype.RdataType``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
-
- *create*, a ``bool``. If True, create the rdataset if it is not found.
-
- Raises ``KeyError`` if an rdataset of the desired type and class does
- not exist and *create* is not ``True``.
-
- Returns a ``dns.rdataset.Rdataset``.
- """
-
- for rds in self.rdatasets:
- if rds.match(rdclass, rdtype, covers):
- return rds
- if not create:
- raise KeyError
- rds = dns.rdataset.Rdataset(rdclass, rdtype, covers)
- self._append_rdataset(rds)
- return rds
-
- def get_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> Optional[dns.rdataset.Rdataset]:
- """Get an rdataset matching the specified properties in the
- current node.
-
- None is returned if an rdataset of the specified type and
- class does not exist and *create* is not ``True``.
-
- *rdclass*, an ``int``, the class of the rdataset.
-
- *rdtype*, an ``int``, the type of the rdataset.
-
- *covers*, an ``int``, the covered type. Usually this value is
- dns.rdatatype.NONE, but if the rdtype is dns.rdatatype.SIG or
- dns.rdatatype.RRSIG, then the covers value will be the rdata
- type the SIG/RRSIG covers. The library treats the SIG and RRSIG
- types as if they were a family of
- types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This makes RRSIGs much
- easier to work with than if RRSIGs covering different rdata
- types were aggregated into a single RRSIG rdataset.
-
- *create*, a ``bool``. If True, create the rdataset if it is not found.
-
- Returns a ``dns.rdataset.Rdataset`` or ``None``.
- """
-
- try:
- rds = self.find_rdataset(rdclass, rdtype, covers, create)
- except KeyError:
- rds = None
- return rds
-
- def delete_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- ) -> None:
- """Delete the rdataset matching the specified properties in the
- current node.
-
- If a matching rdataset does not exist, it is not an error.
-
- *rdclass*, an ``int``, the class of the rdataset.
-
- *rdtype*, an ``int``, the type of the rdataset.
-
- *covers*, an ``int``, the covered type.
- """
-
- rds = self.get_rdataset(rdclass, rdtype, covers)
- if rds is not None:
- self.rdatasets.remove(rds)
-
- def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None:
- """Replace an rdataset.
-
- It is not an error if there is no rdataset matching *replacement*.
-
- Ownership of the *replacement* object is transferred to the node;
- in other words, this method does not store a copy of *replacement*
- at the node, it stores *replacement* itself.
-
- *replacement*, a ``dns.rdataset.Rdataset``.
-
- Raises ``ValueError`` if *replacement* is not a
- ``dns.rdataset.Rdataset``.
- """
-
- if not isinstance(replacement, dns.rdataset.Rdataset):
- raise ValueError("replacement is not an rdataset")
- if isinstance(replacement, dns.rrset.RRset):
- # RRsets are not good replacements as the match() method
- # is not compatible.
- replacement = replacement.to_rdataset()
- self.delete_rdataset(
- replacement.rdclass, replacement.rdtype, replacement.covers
- )
- self._append_rdataset(replacement)
-
- def classify(self) -> NodeKind:
- """Classify a node.
-
- A node which contains a CNAME or RRSIG(CNAME) is a
- ``NodeKind.CNAME`` node.
-
- A node which contains only "neutral" types, i.e. types allowed to
- co-exist with a CNAME, is a ``NodeKind.NEUTRAL`` node. The neutral
- types are NSEC, NSEC3, KEY, and their associated RRSIGS. An empty node
- is also considered neutral.
-
- A node which contains some rdataset which is not a CNAME, RRSIG(CNAME),
- or a neutral type is a a ``NodeKind.REGULAR`` node. Regular nodes are
- also commonly referred to as "other data".
- """
- for rdataset in self.rdatasets:
- kind = NodeKind.classify(rdataset.rdtype, rdataset.covers)
- if kind != NodeKind.NEUTRAL:
- return kind
- return NodeKind.NEUTRAL
-
- def is_immutable(self) -> bool:
- return False
-
-
-@dns.immutable.immutable
-class ImmutableNode(Node):
- def __init__(self, node):
- super().__init__()
- self.rdatasets = tuple(
- [dns.rdataset.ImmutableRdataset(rds) for rds in node.rdatasets]
- )
-
- def find_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> dns.rdataset.Rdataset:
- if create:
- raise TypeError("immutable")
- return super().find_rdataset(rdclass, rdtype, covers, False)
-
- def get_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> Optional[dns.rdataset.Rdataset]:
- if create:
- raise TypeError("immutable")
- return super().get_rdataset(rdclass, rdtype, covers, False)
-
- def delete_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- ) -> None:
- raise TypeError("immutable")
-
- def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None:
- raise TypeError("immutable")
-
- def is_immutable(self) -> bool:
- return True
diff --git a/.venv/lib/python3.12/site-packages/dns/opcode.py b/.venv/lib/python3.12/site-packages/dns/opcode.py
deleted file mode 100644
index 78b43d2..0000000
--- a/.venv/lib/python3.12/site-packages/dns/opcode.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Opcodes."""
-
-import dns.enum
-import dns.exception
-
-
-class Opcode(dns.enum.IntEnum):
- #: Query
- QUERY = 0
- #: Inverse Query (historical)
- IQUERY = 1
- #: Server Status (unspecified and unimplemented anywhere)
- STATUS = 2
- #: Notify
- NOTIFY = 4
- #: Dynamic Update
- UPDATE = 5
-
- @classmethod
- def _maximum(cls):
- return 15
-
- @classmethod
- def _unknown_exception_class(cls):
- return UnknownOpcode
-
-
-class UnknownOpcode(dns.exception.DNSException):
- """An DNS opcode is unknown."""
-
-
-def from_text(text: str) -> Opcode:
- """Convert text into an opcode.
-
- *text*, a ``str``, the textual opcode
-
- Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
-
- Returns an ``int``.
- """
-
- return Opcode.from_text(text)
-
-
-def from_flags(flags: int) -> Opcode:
- """Extract an opcode from DNS message flags.
-
- *flags*, an ``int``, the DNS flags.
-
- Returns an ``int``.
- """
-
- return Opcode((flags & 0x7800) >> 11)
-
-
-def to_flags(value: Opcode) -> int:
- """Convert an opcode to a value suitable for ORing into DNS message
- flags.
-
- *value*, an ``int``, the DNS opcode value.
-
- Returns an ``int``.
- """
-
- return (value << 11) & 0x7800
-
-
-def to_text(value: Opcode) -> str:
- """Convert an opcode to text.
-
- *value*, an ``int`` the opcode value,
-
- Raises ``dns.opcode.UnknownOpcode`` if the opcode is unknown.
-
- Returns a ``str``.
- """
-
- return Opcode.to_text(value)
-
-
-def is_update(flags: int) -> bool:
- """Is the opcode in flags UPDATE?
-
- *flags*, an ``int``, the DNS message flags.
-
- Returns a ``bool``.
- """
-
- return from_flags(flags) == Opcode.UPDATE
-
-
-### BEGIN generated Opcode constants
-
-QUERY = Opcode.QUERY
-IQUERY = Opcode.IQUERY
-STATUS = Opcode.STATUS
-NOTIFY = Opcode.NOTIFY
-UPDATE = Opcode.UPDATE
-
-### END generated Opcode constants
diff --git a/.venv/lib/python3.12/site-packages/dns/py.typed b/.venv/lib/python3.12/site-packages/dns/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/dns/query.py b/.venv/lib/python3.12/site-packages/dns/query.py
deleted file mode 100644
index f0ee916..0000000
--- a/.venv/lib/python3.12/site-packages/dns/query.py
+++ /dev/null
@@ -1,1578 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Talk to a DNS server."""
-
-import base64
-import contextlib
-import enum
-import errno
-import os
-import os.path
-import selectors
-import socket
-import struct
-import time
-from typing import Any, Dict, Optional, Tuple, Union
-
-import dns._features
-import dns.exception
-import dns.inet
-import dns.message
-import dns.name
-import dns.quic
-import dns.rcode
-import dns.rdataclass
-import dns.rdatatype
-import dns.serial
-import dns.transaction
-import dns.tsig
-import dns.xfr
-
-
-def _remaining(expiration):
- if expiration is None:
- return None
- timeout = expiration - time.time()
- if timeout <= 0.0:
- raise dns.exception.Timeout
- return timeout
-
-
-def _expiration_for_this_attempt(timeout, expiration):
- if expiration is None:
- return None
- return min(time.time() + timeout, expiration)
-
-
-_have_httpx = dns._features.have("doh")
-if _have_httpx:
- import httpcore._backends.sync
- import httpx
-
- _CoreNetworkBackend = httpcore.NetworkBackend
- _CoreSyncStream = httpcore._backends.sync.SyncStream
-
- class _NetworkBackend(_CoreNetworkBackend):
- def __init__(self, resolver, local_port, bootstrap_address, family):
- super().__init__()
- self._local_port = local_port
- self._resolver = resolver
- self._bootstrap_address = bootstrap_address
- self._family = family
-
- def connect_tcp(
- self, host, port, timeout, local_address, socket_options=None
- ): # pylint: disable=signature-differs
- addresses = []
- _, expiration = _compute_times(timeout)
- if dns.inet.is_address(host):
- addresses.append(host)
- elif self._bootstrap_address is not None:
- addresses.append(self._bootstrap_address)
- else:
- timeout = _remaining(expiration)
- family = self._family
- if local_address:
- family = dns.inet.af_for_address(local_address)
- answers = self._resolver.resolve_name(
- host, family=family, lifetime=timeout
- )
- addresses = answers.addresses()
- for address in addresses:
- af = dns.inet.af_for_address(address)
- if local_address is not None or self._local_port != 0:
- source = dns.inet.low_level_address_tuple(
- (local_address, self._local_port), af
- )
- else:
- source = None
- sock = _make_socket(af, socket.SOCK_STREAM, source)
- attempt_expiration = _expiration_for_this_attempt(2.0, expiration)
- try:
- _connect(
- sock,
- dns.inet.low_level_address_tuple((address, port), af),
- attempt_expiration,
- )
- return _CoreSyncStream(sock)
- except Exception:
- pass
- raise httpcore.ConnectError
-
- def connect_unix_socket(
- self, path, timeout, socket_options=None
- ): # pylint: disable=signature-differs
- raise NotImplementedError
-
- class _HTTPTransport(httpx.HTTPTransport):
- def __init__(
- self,
- *args,
- local_port=0,
- bootstrap_address=None,
- resolver=None,
- family=socket.AF_UNSPEC,
- **kwargs,
- ):
- if resolver is None:
- # pylint: disable=import-outside-toplevel,redefined-outer-name
- import dns.resolver
-
- resolver = dns.resolver.Resolver()
- super().__init__(*args, **kwargs)
- self._pool._network_backend = _NetworkBackend(
- resolver, local_port, bootstrap_address, family
- )
-
-else:
-
- class _HTTPTransport: # type: ignore
- def connect_tcp(self, host, port, timeout, local_address):
- raise NotImplementedError
-
-
-have_doh = _have_httpx
-
-try:
- import ssl
-except ImportError: # pragma: no cover
-
- class ssl: # type: ignore
- CERT_NONE = 0
-
- class WantReadException(Exception):
- pass
-
- class WantWriteException(Exception):
- pass
-
- class SSLContext:
- pass
-
- class SSLSocket:
- pass
-
- @classmethod
- def create_default_context(cls, *args, **kwargs):
- raise Exception("no ssl support") # pylint: disable=broad-exception-raised
-
-
-# Function used to create a socket. Can be overridden if needed in special
-# situations.
-socket_factory = socket.socket
-
-
-class UnexpectedSource(dns.exception.DNSException):
- """A DNS query response came from an unexpected address or port."""
-
-
-class BadResponse(dns.exception.FormError):
- """A DNS query response does not respond to the question asked."""
-
-
-class NoDOH(dns.exception.DNSException):
- """DNS over HTTPS (DOH) was requested but the httpx module is not
- available."""
-
-
-class NoDOQ(dns.exception.DNSException):
- """DNS over QUIC (DOQ) was requested but the aioquic module is not
- available."""
-
-
-# for backwards compatibility
-TransferError = dns.xfr.TransferError
-
-
-def _compute_times(timeout):
- now = time.time()
- if timeout is None:
- return (now, None)
- else:
- return (now, now + timeout)
-
-
-def _wait_for(fd, readable, writable, _, expiration):
- # Use the selected selector class to wait for any of the specified
- # events. An "expiration" absolute time is converted into a relative
- # timeout.
- #
- # The unused parameter is 'error', which is always set when
- # selecting for read or write, and we have no error-only selects.
-
- if readable and isinstance(fd, ssl.SSLSocket) and fd.pending() > 0:
- return True
- sel = _selector_class()
- events = 0
- if readable:
- events |= selectors.EVENT_READ
- if writable:
- events |= selectors.EVENT_WRITE
- if events:
- sel.register(fd, events)
- if expiration is None:
- timeout = None
- else:
- timeout = expiration - time.time()
- if timeout <= 0.0:
- raise dns.exception.Timeout
- if not sel.select(timeout):
- raise dns.exception.Timeout
-
-
-def _set_selector_class(selector_class):
- # Internal API. Do not use.
-
- global _selector_class
-
- _selector_class = selector_class
-
-
-if hasattr(selectors, "PollSelector"):
- # Prefer poll() on platforms that support it because it has no
- # limits on the maximum value of a file descriptor (plus it will
- # be more efficient for high values).
- #
- # We ignore typing here as we can't say _selector_class is Any
- # on python < 3.8 due to a bug.
- _selector_class = selectors.PollSelector # type: ignore
-else:
- _selector_class = selectors.SelectSelector # type: ignore
-
-
-def _wait_for_readable(s, expiration):
- _wait_for(s, True, False, True, expiration)
-
-
-def _wait_for_writable(s, expiration):
- _wait_for(s, False, True, True, expiration)
-
-
-def _addresses_equal(af, a1, a2):
- # Convert the first value of the tuple, which is a textual format
- # address into binary form, so that we are not confused by different
- # textual representations of the same address
- try:
- n1 = dns.inet.inet_pton(af, a1[0])
- n2 = dns.inet.inet_pton(af, a2[0])
- except dns.exception.SyntaxError:
- return False
- return n1 == n2 and a1[1:] == a2[1:]
-
-
-def _matches_destination(af, from_address, destination, ignore_unexpected):
- # Check that from_address is appropriate for a response to a query
- # sent to destination.
- if not destination:
- return True
- if _addresses_equal(af, from_address, destination) or (
- dns.inet.is_multicast(destination[0]) and from_address[1:] == destination[1:]
- ):
- return True
- elif ignore_unexpected:
- return False
- raise UnexpectedSource(
- f"got a response from {from_address} instead of " f"{destination}"
- )
-
-
-def _destination_and_source(
- where, port, source, source_port, where_must_be_address=True
-):
- # Apply defaults and compute destination and source tuples
- # suitable for use in connect(), sendto(), or bind().
- af = None
- destination = None
- try:
- af = dns.inet.af_for_address(where)
- destination = where
- except Exception:
- if where_must_be_address:
- raise
- # URLs are ok so eat the exception
- if source:
- saf = dns.inet.af_for_address(source)
- if af:
- # We know the destination af, so source had better agree!
- if saf != af:
- raise ValueError(
- "different address families for source and destination"
- )
- else:
- # We didn't know the destination af, but we know the source,
- # so that's our af.
- af = saf
- if source_port and not source:
- # Caller has specified a source_port but not an address, so we
- # need to return a source, and we need to use the appropriate
- # wildcard address as the address.
- try:
- source = dns.inet.any_for_af(af)
- except Exception:
- # we catch this and raise ValueError for backwards compatibility
- raise ValueError("source_port specified but address family is unknown")
- # Convert high-level (address, port) tuples into low-level address
- # tuples.
- if destination:
- destination = dns.inet.low_level_address_tuple((destination, port), af)
- if source:
- source = dns.inet.low_level_address_tuple((source, source_port), af)
- return (af, destination, source)
-
-
-def _make_socket(af, type, source, ssl_context=None, server_hostname=None):
- s = socket_factory(af, type)
- try:
- s.setblocking(False)
- if source is not None:
- s.bind(source)
- if ssl_context:
- # LGTM gets a false positive here, as our default context is OK
- return ssl_context.wrap_socket(
- s,
- do_handshake_on_connect=False, # lgtm[py/insecure-protocol]
- server_hostname=server_hostname,
- )
- else:
- return s
- except Exception:
- s.close()
- raise
-
-
-def https(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 443,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- session: Optional[Any] = None,
- path: str = "/dns-query",
- post: bool = True,
- bootstrap_address: Optional[str] = None,
- verify: Union[bool, str] = True,
- resolver: Optional["dns.resolver.Resolver"] = None,
- family: Optional[int] = socket.AF_UNSPEC,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via DNS-over-HTTPS.
-
- *q*, a ``dns.message.Message``, the query to send.
-
- *where*, a ``str``, the nameserver IP address or the full URL. If an IP address is
- given, the URL will be constructed using the following schema:
- https://:/.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query
- times out. If ``None``, the default, wait forever.
-
- *port*, a ``int``, the port to send the query to. The default is 443.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source
- address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message. The default is
- 0.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
- received message.
-
- *session*, an ``httpx.Client``. If provided, the client session to use to send the
- queries.
-
- *path*, a ``str``. If *where* is an IP address, then *path* will be used to
- construct the URL to send the DNS query to.
-
- *post*, a ``bool``. If ``True``, the default, POST method will be used.
-
- *bootstrap_address*, a ``str``, the IP address to use to bypass resolution.
-
- *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification
- of the server is done using the default CA bundle; if ``False``, then no
- verification is done; if a `str` then it specifies the path to a certificate file or
- directory which will be used for verification.
-
- *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for
- resolution of hostnames in URLs. If not specified, a new resolver with a default
- configuration will be used; note this is *not* the default resolver as that resolver
- might have been configured to use DoH causing a chicken-and-egg problem. This
- parameter only has an effect if the HTTP library is httpx.
-
- *family*, an ``int``, the address family. If socket.AF_UNSPEC (the default), both A
- and AAAA records will be retrieved.
-
- Returns a ``dns.message.Message``.
- """
-
- if not have_doh:
- raise NoDOH # pragma: no cover
- if session and not isinstance(session, httpx.Client):
- raise ValueError("session parameter must be an httpx.Client")
-
- wire = q.to_wire()
- (af, _, the_source) = _destination_and_source(
- where, port, source, source_port, False
- )
- transport = None
- headers = {"accept": "application/dns-message"}
- if af is not None and dns.inet.is_address(where):
- if af == socket.AF_INET:
- url = "https://{}:{}{}".format(where, port, path)
- elif af == socket.AF_INET6:
- url = "https://[{}]:{}{}".format(where, port, path)
- else:
- url = where
-
- # set source port and source address
-
- if the_source is None:
- local_address = None
- local_port = 0
- else:
- local_address = the_source[0]
- local_port = the_source[1]
- transport = _HTTPTransport(
- local_address=local_address,
- http1=True,
- http2=True,
- verify=verify,
- local_port=local_port,
- bootstrap_address=bootstrap_address,
- resolver=resolver,
- family=family,
- )
-
- if session:
- cm: contextlib.AbstractContextManager = contextlib.nullcontext(session)
- else:
- cm = httpx.Client(http1=True, http2=True, verify=verify, transport=transport)
- with cm as session:
- # see https://tools.ietf.org/html/rfc8484#section-4.1.1 for DoH
- # GET and POST examples
- if post:
- headers.update(
- {
- "content-type": "application/dns-message",
- "content-length": str(len(wire)),
- }
- )
- response = session.post(url, headers=headers, content=wire, timeout=timeout)
- else:
- wire = base64.urlsafe_b64encode(wire).rstrip(b"=")
- twire = wire.decode() # httpx does a repr() if we give it bytes
- response = session.get(
- url, headers=headers, timeout=timeout, params={"dns": twire}
- )
-
- # see https://tools.ietf.org/html/rfc8484#section-4.2.1 for info about DoH
- # status codes
- if response.status_code < 200 or response.status_code > 299:
- raise ValueError(
- "{} responded with status code {}"
- "\nResponse body: {}".format(where, response.status_code, response.content)
- )
- r = dns.message.from_wire(
- response.content,
- keyring=q.keyring,
- request_mac=q.request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- r.time = response.elapsed.total_seconds()
- if not q.is_response(r):
- raise BadResponse
- return r
-
-
-def _udp_recv(sock, max_size, expiration):
- """Reads a datagram from the socket.
- A Timeout exception will be raised if the operation is not completed
- by the expiration time.
- """
- while True:
- try:
- return sock.recvfrom(max_size)
- except BlockingIOError:
- _wait_for_readable(sock, expiration)
-
-
-def _udp_send(sock, data, destination, expiration):
- """Sends the specified datagram to destination over the socket.
- A Timeout exception will be raised if the operation is not completed
- by the expiration time.
- """
- while True:
- try:
- if destination:
- return sock.sendto(data, destination)
- else:
- return sock.send(data)
- except BlockingIOError: # pragma: no cover
- _wait_for_writable(sock, expiration)
-
-
-def send_udp(
- sock: Any,
- what: Union[dns.message.Message, bytes],
- destination: Any,
- expiration: Optional[float] = None,
-) -> Tuple[int, float]:
- """Send a DNS message to the specified UDP socket.
-
- *sock*, a ``socket``.
-
- *what*, a ``bytes`` or ``dns.message.Message``, the message to send.
-
- *destination*, a destination tuple appropriate for the address family
- of the socket, specifying where to send the query.
-
- *expiration*, a ``float`` or ``None``, the absolute time at which
- a timeout exception should be raised. If ``None``, no timeout will
- occur.
-
- Returns an ``(int, float)`` tuple of bytes sent and the sent time.
- """
-
- if isinstance(what, dns.message.Message):
- what = what.to_wire()
- sent_time = time.time()
- n = _udp_send(sock, what, destination, expiration)
- return (n, sent_time)
-
-
-def receive_udp(
- sock: Any,
- destination: Optional[Any] = None,
- expiration: Optional[float] = None,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None,
- request_mac: Optional[bytes] = b"",
- ignore_trailing: bool = False,
- raise_on_truncation: bool = False,
- ignore_errors: bool = False,
- query: Optional[dns.message.Message] = None,
-) -> Any:
- """Read a DNS message from a UDP socket.
-
- *sock*, a ``socket``.
-
- *destination*, a destination tuple appropriate for the address family
- of the socket, specifying where the message is expected to arrive from.
- When receiving a response, this would be where the associated query was
- sent.
-
- *expiration*, a ``float`` or ``None``, the absolute time at which
- a timeout exception should be raised. If ``None``, no timeout will
- occur.
-
- *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
- unexpected sources.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
-
- *keyring*, a ``dict``, the keyring to use for TSIG.
-
- *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG).
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
-
- *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if
- the TC bit is set.
-
- Raises if the message is malformed, if network errors occur, of if
- there is a timeout.
-
- If *destination* is not ``None``, returns a ``(dns.message.Message, float)``
- tuple of the received message and the received time.
-
- If *destination* is ``None``, returns a
- ``(dns.message.Message, float, tuple)``
- tuple of the received message, the received time, and the address where
- the message arrived from.
-
- *ignore_errors*, a ``bool``. If various format errors or response
- mismatches occur, ignore them and keep listening for a valid response.
- The default is ``False``.
-
- *query*, a ``dns.message.Message`` or ``None``. If not ``None`` and
- *ignore_errors* is ``True``, check that the received message is a response
- to this query, and if not keep listening for a valid response.
- """
-
- wire = b""
- while True:
- (wire, from_address) = _udp_recv(sock, 65535, expiration)
- if not _matches_destination(
- sock.family, from_address, destination, ignore_unexpected
- ):
- continue
- received_time = time.time()
- try:
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- raise_on_truncation=raise_on_truncation,
- )
- except dns.message.Truncated as e:
- # If we got Truncated and not FORMERR, we at least got the header with TC
- # set, and very likely the question section, so we'll re-raise if the
- # message seems to be a response as we need to know when truncation happens.
- # We need to check that it seems to be a response as we don't want a random
- # injected message with TC set to cause us to bail out.
- if (
- ignore_errors
- and query is not None
- and not query.is_response(e.message())
- ):
- continue
- else:
- raise
- except Exception:
- if ignore_errors:
- continue
- else:
- raise
- if ignore_errors and query is not None and not query.is_response(r):
- continue
- if destination:
- return (r, received_time)
- else:
- return (r, received_time, from_address)
-
-
-def udp(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- raise_on_truncation: bool = False,
- sock: Optional[Any] = None,
- ignore_errors: bool = False,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via UDP.
-
- *q*, a ``dns.message.Message``, the query to send
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the
- query times out. If ``None``, the default, wait forever.
-
- *port*, an ``int``, the port send the message to. The default is 53.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
-
- *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from
- unexpected sources.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
-
- *raise_on_truncation*, a ``bool``. If ``True``, raise an exception if
- the TC bit is set.
-
- *sock*, a ``socket.socket``, or ``None``, the socket to use for the
- query. If ``None``, the default, a socket is created. Note that
- if a socket is provided, it must be a nonblocking datagram socket,
- and the *source* and *source_port* are ignored.
-
- *ignore_errors*, a ``bool``. If various format errors or response
- mismatches occur, ignore them and keep listening for a valid response.
- The default is ``False``.
-
- Returns a ``dns.message.Message``.
- """
-
- wire = q.to_wire()
- (af, destination, source) = _destination_and_source(
- where, port, source, source_port
- )
- (begin_time, expiration) = _compute_times(timeout)
- if sock:
- cm: contextlib.AbstractContextManager = contextlib.nullcontext(sock)
- else:
- cm = _make_socket(af, socket.SOCK_DGRAM, source)
- with cm as s:
- send_udp(s, wire, destination, expiration)
- (r, received_time) = receive_udp(
- s,
- destination,
- expiration,
- ignore_unexpected,
- one_rr_per_rrset,
- q.keyring,
- q.mac,
- ignore_trailing,
- raise_on_truncation,
- ignore_errors,
- q,
- )
- r.time = received_time - begin_time
- # We don't need to check q.is_response() if we are in ignore_errors mode
- # as receive_udp() will have checked it.
- if not (ignore_errors or q.is_response(r)):
- raise BadResponse
- return r
- assert (
- False # help mypy figure out we can't get here lgtm[py/unreachable-statement]
- )
-
-
-def udp_with_fallback(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- ignore_unexpected: bool = False,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- udp_sock: Optional[Any] = None,
- tcp_sock: Optional[Any] = None,
- ignore_errors: bool = False,
-) -> Tuple[dns.message.Message, bool]:
- """Return the response to the query, trying UDP first and falling back
- to TCP if UDP results in a truncated response.
-
- *q*, a ``dns.message.Message``, the query to send
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where to send the message.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query
- times out. If ``None``, the default, wait forever.
-
- *port*, an ``int``, the port send the message to. The default is 53.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source
- address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message. The default is
- 0.
-
- *ignore_unexpected*, a ``bool``. If ``True``, ignore responses from unexpected
- sources.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
- received message.
-
- *udp_sock*, a ``socket.socket``, or ``None``, the socket to use for the UDP query.
- If ``None``, the default, a socket is created. Note that if a socket is provided,
- it must be a nonblocking datagram socket, and the *source* and *source_port* are
- ignored for the UDP query.
-
- *tcp_sock*, a ``socket.socket``, or ``None``, the connected socket to use for the
- TCP query. If ``None``, the default, a socket is created. Note that if a socket is
- provided, it must be a nonblocking connected stream socket, and *where*, *source*
- and *source_port* are ignored for the TCP query.
-
- *ignore_errors*, a ``bool``. If various format errors or response mismatches occur
- while listening for UDP, ignore them and keep listening for a valid response. The
- default is ``False``.
-
- Returns a (``dns.message.Message``, tcp) tuple where tcp is ``True`` if and only if
- TCP was used.
- """
- try:
- response = udp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- ignore_unexpected,
- one_rr_per_rrset,
- ignore_trailing,
- True,
- udp_sock,
- ignore_errors,
- )
- return (response, False)
- except dns.message.Truncated:
- response = tcp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- one_rr_per_rrset,
- ignore_trailing,
- tcp_sock,
- )
- return (response, True)
-
-
-def _net_read(sock, count, expiration):
- """Read the specified number of bytes from sock. Keep trying until we
- either get the desired amount, or we hit EOF.
- A Timeout exception will be raised if the operation is not completed
- by the expiration time.
- """
- s = b""
- while count > 0:
- try:
- n = sock.recv(count)
- if n == b"":
- raise EOFError
- count -= len(n)
- s += n
- except (BlockingIOError, ssl.SSLWantReadError):
- _wait_for_readable(sock, expiration)
- except ssl.SSLWantWriteError: # pragma: no cover
- _wait_for_writable(sock, expiration)
- return s
-
-
-def _net_write(sock, data, expiration):
- """Write the specified data to the socket.
- A Timeout exception will be raised if the operation is not completed
- by the expiration time.
- """
- current = 0
- l = len(data)
- while current < l:
- try:
- current += sock.send(data[current:])
- except (BlockingIOError, ssl.SSLWantWriteError):
- _wait_for_writable(sock, expiration)
- except ssl.SSLWantReadError: # pragma: no cover
- _wait_for_readable(sock, expiration)
-
-
-def send_tcp(
- sock: Any,
- what: Union[dns.message.Message, bytes],
- expiration: Optional[float] = None,
-) -> Tuple[int, float]:
- """Send a DNS message to the specified TCP socket.
-
- *sock*, a ``socket``.
-
- *what*, a ``bytes`` or ``dns.message.Message``, the message to send.
-
- *expiration*, a ``float`` or ``None``, the absolute time at which
- a timeout exception should be raised. If ``None``, no timeout will
- occur.
-
- Returns an ``(int, float)`` tuple of bytes sent and the sent time.
- """
-
- if isinstance(what, dns.message.Message):
- tcpmsg = what.to_wire(prepend_length=True)
- else:
- # copying the wire into tcpmsg is inefficient, but lets us
- # avoid writev() or doing a short write that would get pushed
- # onto the net
- tcpmsg = len(what).to_bytes(2, "big") + what
- sent_time = time.time()
- _net_write(sock, tcpmsg, expiration)
- return (len(tcpmsg), sent_time)
-
-
-def receive_tcp(
- sock: Any,
- expiration: Optional[float] = None,
- one_rr_per_rrset: bool = False,
- keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None,
- request_mac: Optional[bytes] = b"",
- ignore_trailing: bool = False,
-) -> Tuple[dns.message.Message, float]:
- """Read a DNS message from a TCP socket.
-
- *sock*, a ``socket``.
-
- *expiration*, a ``float`` or ``None``, the absolute time at which
- a timeout exception should be raised. If ``None``, no timeout will
- occur.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
-
- *keyring*, a ``dict``, the keyring to use for TSIG.
-
- *request_mac*, a ``bytes`` or ``None``, the MAC of the request (for TSIG).
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
-
- Raises if the message is malformed, if network errors occur, of if
- there is a timeout.
-
- Returns a ``(dns.message.Message, float)`` tuple of the received message
- and the received time.
- """
-
- ldata = _net_read(sock, 2, expiration)
- (l,) = struct.unpack("!H", ldata)
- wire = _net_read(sock, l, expiration)
- received_time = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=keyring,
- request_mac=request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- return (r, received_time)
-
-
-def _connect(s, address, expiration):
- err = s.connect_ex(address)
- if err == 0:
- return
- if err in (errno.EINPROGRESS, errno.EWOULDBLOCK, errno.EALREADY):
- _wait_for_writable(s, expiration)
- err = s.getsockopt(socket.SOL_SOCKET, socket.SO_ERROR)
- if err != 0:
- raise OSError(err, os.strerror(err))
-
-
-def tcp(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 53,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- sock: Optional[Any] = None,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via TCP.
-
- *q*, a ``dns.message.Message``, the query to send
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the
- query times out. If ``None``, the default, wait forever.
-
- *port*, an ``int``, the port send the message to. The default is 53.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
-
- *sock*, a ``socket.socket``, or ``None``, the connected socket to use for the
- query. If ``None``, the default, a socket is created. Note that
- if a socket is provided, it must be a nonblocking connected stream
- socket, and *where*, *port*, *source* and *source_port* are ignored.
-
- Returns a ``dns.message.Message``.
- """
-
- wire = q.to_wire()
- (begin_time, expiration) = _compute_times(timeout)
- if sock:
- cm: contextlib.AbstractContextManager = contextlib.nullcontext(sock)
- else:
- (af, destination, source) = _destination_and_source(
- where, port, source, source_port
- )
- cm = _make_socket(af, socket.SOCK_STREAM, source)
- with cm as s:
- if not sock:
- _connect(s, destination, expiration)
- send_tcp(s, wire, expiration)
- (r, received_time) = receive_tcp(
- s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing
- )
- r.time = received_time - begin_time
- if not q.is_response(r):
- raise BadResponse
- return r
- assert (
- False # help mypy figure out we can't get here lgtm[py/unreachable-statement]
- )
-
-
-def _tls_handshake(s, expiration):
- while True:
- try:
- s.do_handshake()
- return
- except ssl.SSLWantReadError:
- _wait_for_readable(s, expiration)
- except ssl.SSLWantWriteError: # pragma: no cover
- _wait_for_writable(s, expiration)
-
-
-def _make_dot_ssl_context(
- server_hostname: Optional[str], verify: Union[bool, str]
-) -> ssl.SSLContext:
- cafile: Optional[str] = None
- capath: Optional[str] = None
- if isinstance(verify, str):
- if os.path.isfile(verify):
- cafile = verify
- elif os.path.isdir(verify):
- capath = verify
- else:
- raise ValueError("invalid verify string")
- ssl_context = ssl.create_default_context(cafile=cafile, capath=capath)
- ssl_context.minimum_version = ssl.TLSVersion.TLSv1_2
- if server_hostname is None:
- ssl_context.check_hostname = False
- ssl_context.set_alpn_protocols(["dot"])
- if verify is False:
- ssl_context.verify_mode = ssl.CERT_NONE
- return ssl_context
-
-
-def tls(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 853,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- sock: Optional[ssl.SSLSocket] = None,
- ssl_context: Optional[ssl.SSLContext] = None,
- server_hostname: Optional[str] = None,
- verify: Union[bool, str] = True,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via TLS.
-
- *q*, a ``dns.message.Message``, the query to send
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the
- query times out. If ``None``, the default, wait forever.
-
- *port*, an ``int``, the port send the message to. The default is 853.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own
- RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing
- junk at end of the received message.
-
- *sock*, an ``ssl.SSLSocket``, or ``None``, the socket to use for
- the query. If ``None``, the default, a socket is created. Note
- that if a socket is provided, it must be a nonblocking connected
- SSL stream socket, and *where*, *port*, *source*, *source_port*,
- and *ssl_context* are ignored.
-
- *ssl_context*, an ``ssl.SSLContext``, the context to use when establishing
- a TLS connection. If ``None``, the default, creates one with the default
- configuration.
-
- *server_hostname*, a ``str`` containing the server's hostname. The
- default is ``None``, which means that no hostname is known, and if an
- SSL context is created, hostname checking will be disabled.
-
- *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification
- of the server is done using the default CA bundle; if ``False``, then no
- verification is done; if a `str` then it specifies the path to a certificate file or
- directory which will be used for verification.
-
- Returns a ``dns.message.Message``.
-
- """
-
- if sock:
- #
- # If a socket was provided, there's no special TLS handling needed.
- #
- return tcp(
- q,
- where,
- timeout,
- port,
- source,
- source_port,
- one_rr_per_rrset,
- ignore_trailing,
- sock,
- )
-
- wire = q.to_wire()
- (begin_time, expiration) = _compute_times(timeout)
- (af, destination, source) = _destination_and_source(
- where, port, source, source_port
- )
- if ssl_context is None and not sock:
- ssl_context = _make_dot_ssl_context(server_hostname, verify)
-
- with _make_socket(
- af,
- socket.SOCK_STREAM,
- source,
- ssl_context=ssl_context,
- server_hostname=server_hostname,
- ) as s:
- _connect(s, destination, expiration)
- _tls_handshake(s, expiration)
- send_tcp(s, wire, expiration)
- (r, received_time) = receive_tcp(
- s, expiration, one_rr_per_rrset, q.keyring, q.mac, ignore_trailing
- )
- r.time = received_time - begin_time
- if not q.is_response(r):
- raise BadResponse
- return r
- assert (
- False # help mypy figure out we can't get here lgtm[py/unreachable-statement]
- )
-
-
-def quic(
- q: dns.message.Message,
- where: str,
- timeout: Optional[float] = None,
- port: int = 853,
- source: Optional[str] = None,
- source_port: int = 0,
- one_rr_per_rrset: bool = False,
- ignore_trailing: bool = False,
- connection: Optional[dns.quic.SyncQuicConnection] = None,
- verify: Union[bool, str] = True,
- server_hostname: Optional[str] = None,
-) -> dns.message.Message:
- """Return the response obtained after sending a query via DNS-over-QUIC.
-
- *q*, a ``dns.message.Message``, the query to send.
-
- *where*, a ``str``, the nameserver IP address.
-
- *timeout*, a ``float`` or ``None``, the number of seconds to wait before the query
- times out. If ``None``, the default, wait forever.
-
- *port*, a ``int``, the port to send the query to. The default is 853.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying the source
- address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message. The default is
- 0.
-
- *one_rr_per_rrset*, a ``bool``. If ``True``, put each RR into its own RRset.
-
- *ignore_trailing*, a ``bool``. If ``True``, ignore trailing junk at end of the
- received message.
-
- *connection*, a ``dns.quic.SyncQuicConnection``. If provided, the
- connection to use to send the query.
-
- *verify*, a ``bool`` or ``str``. If a ``True``, then TLS certificate verification
- of the server is done using the default CA bundle; if ``False``, then no
- verification is done; if a `str` then it specifies the path to a certificate file or
- directory which will be used for verification.
-
- *server_hostname*, a ``str`` containing the server's hostname. The
- default is ``None``, which means that no hostname is known, and if an
- SSL context is created, hostname checking will be disabled.
-
- Returns a ``dns.message.Message``.
- """
-
- if not dns.quic.have_quic:
- raise NoDOQ("DNS-over-QUIC is not available.") # pragma: no cover
-
- q.id = 0
- wire = q.to_wire()
- the_connection: dns.quic.SyncQuicConnection
- the_manager: dns.quic.SyncQuicManager
- if connection:
- manager: contextlib.AbstractContextManager = contextlib.nullcontext(None)
- the_connection = connection
- else:
- manager = dns.quic.SyncQuicManager(
- verify_mode=verify, server_name=server_hostname
- )
- the_manager = manager # for type checking happiness
-
- with manager:
- if not connection:
- the_connection = the_manager.connect(where, port, source, source_port)
- (start, expiration) = _compute_times(timeout)
- with the_connection.make_stream(timeout) as stream:
- stream.send(wire, True)
- wire = stream.receive(_remaining(expiration))
- finish = time.time()
- r = dns.message.from_wire(
- wire,
- keyring=q.keyring,
- request_mac=q.request_mac,
- one_rr_per_rrset=one_rr_per_rrset,
- ignore_trailing=ignore_trailing,
- )
- r.time = max(finish - start, 0.0)
- if not q.is_response(r):
- raise BadResponse
- return r
-
-
-def xfr(
- where: str,
- zone: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.AXFR,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- timeout: Optional[float] = None,
- port: int = 53,
- keyring: Optional[Dict[dns.name.Name, dns.tsig.Key]] = None,
- keyname: Optional[Union[dns.name.Name, str]] = None,
- relativize: bool = True,
- lifetime: Optional[float] = None,
- source: Optional[str] = None,
- source_port: int = 0,
- serial: int = 0,
- use_udp: bool = False,
- keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm,
-) -> Any:
- """Return a generator for the responses to a zone transfer.
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
-
- *zone*, a ``dns.name.Name`` or ``str``, the name of the zone to transfer.
-
- *rdtype*, an ``int`` or ``str``, the type of zone transfer. The
- default is ``dns.rdatatype.AXFR``. ``dns.rdatatype.IXFR`` can be
- used to do an incremental transfer instead.
-
- *rdclass*, an ``int`` or ``str``, the class of the zone transfer.
- The default is ``dns.rdataclass.IN``.
-
- *timeout*, a ``float``, the number of seconds to wait for each
- response message. If None, the default, wait forever.
-
- *port*, an ``int``, the port send the message to. The default is 53.
-
- *keyring*, a ``dict``, the keyring to use for TSIG.
-
- *keyname*, a ``dns.name.Name`` or ``str``, the name of the TSIG
- key to use.
-
- *relativize*, a ``bool``. If ``True``, all names in the zone will be
- relativized to the zone origin. It is essential that the
- relativize setting matches the one specified to
- ``dns.zone.from_xfr()`` if using this generator to make a zone.
-
- *lifetime*, a ``float``, the total number of seconds to spend
- doing the transfer. If ``None``, the default, then there is no
- limit on the time the transfer may take.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
-
- *serial*, an ``int``, the SOA serial number to use as the base for
- an IXFR diff sequence (only meaningful if *rdtype* is
- ``dns.rdatatype.IXFR``).
-
- *use_udp*, a ``bool``. If ``True``, use UDP (only meaningful for IXFR).
-
- *keyalgorithm*, a ``dns.name.Name`` or ``str``, the TSIG algorithm to use.
-
- Raises on errors, and so does the generator.
-
- Returns a generator of ``dns.message.Message`` objects.
- """
-
- if isinstance(zone, str):
- zone = dns.name.from_text(zone)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- q = dns.message.make_query(zone, rdtype, rdclass)
- if rdtype == dns.rdatatype.IXFR:
- rrset = dns.rrset.from_text(zone, 0, "IN", "SOA", ". . %u 0 0 0 0" % serial)
- q.authority.append(rrset)
- if keyring is not None:
- q.use_tsig(keyring, keyname, algorithm=keyalgorithm)
- wire = q.to_wire()
- (af, destination, source) = _destination_and_source(
- where, port, source, source_port
- )
- if use_udp and rdtype != dns.rdatatype.IXFR:
- raise ValueError("cannot do a UDP AXFR")
- sock_type = socket.SOCK_DGRAM if use_udp else socket.SOCK_STREAM
- with _make_socket(af, sock_type, source) as s:
- (_, expiration) = _compute_times(lifetime)
- _connect(s, destination, expiration)
- l = len(wire)
- if use_udp:
- _udp_send(s, wire, None, expiration)
- else:
- tcpmsg = struct.pack("!H", l) + wire
- _net_write(s, tcpmsg, expiration)
- done = False
- delete_mode = True
- expecting_SOA = False
- soa_rrset = None
- if relativize:
- origin = zone
- oname = dns.name.empty
- else:
- origin = None
- oname = zone
- tsig_ctx = None
- while not done:
- (_, mexpiration) = _compute_times(timeout)
- if mexpiration is None or (
- expiration is not None and mexpiration > expiration
- ):
- mexpiration = expiration
- if use_udp:
- (wire, _) = _udp_recv(s, 65535, mexpiration)
- else:
- ldata = _net_read(s, 2, mexpiration)
- (l,) = struct.unpack("!H", ldata)
- wire = _net_read(s, l, mexpiration)
- is_ixfr = rdtype == dns.rdatatype.IXFR
- r = dns.message.from_wire(
- wire,
- keyring=q.keyring,
- request_mac=q.mac,
- xfr=True,
- origin=origin,
- tsig_ctx=tsig_ctx,
- multi=True,
- one_rr_per_rrset=is_ixfr,
- )
- rcode = r.rcode()
- if rcode != dns.rcode.NOERROR:
- raise TransferError(rcode)
- tsig_ctx = r.tsig_ctx
- answer_index = 0
- if soa_rrset is None:
- if not r.answer or r.answer[0].name != oname:
- raise dns.exception.FormError("No answer or RRset not for qname")
- rrset = r.answer[0]
- if rrset.rdtype != dns.rdatatype.SOA:
- raise dns.exception.FormError("first RRset is not an SOA")
- answer_index = 1
- soa_rrset = rrset.copy()
- if rdtype == dns.rdatatype.IXFR:
- if dns.serial.Serial(soa_rrset[0].serial) <= serial:
- #
- # We're already up-to-date.
- #
- done = True
- else:
- expecting_SOA = True
- #
- # Process SOAs in the answer section (other than the initial
- # SOA in the first message).
- #
- for rrset in r.answer[answer_index:]:
- if done:
- raise dns.exception.FormError("answers after final SOA")
- if rrset.rdtype == dns.rdatatype.SOA and rrset.name == oname:
- if expecting_SOA:
- if rrset[0].serial != serial:
- raise dns.exception.FormError("IXFR base serial mismatch")
- expecting_SOA = False
- elif rdtype == dns.rdatatype.IXFR:
- delete_mode = not delete_mode
- #
- # If this SOA RRset is equal to the first we saw then we're
- # finished. If this is an IXFR we also check that we're
- # seeing the record in the expected part of the response.
- #
- if rrset == soa_rrset and (
- rdtype == dns.rdatatype.AXFR
- or (rdtype == dns.rdatatype.IXFR and delete_mode)
- ):
- done = True
- elif expecting_SOA:
- #
- # We made an IXFR request and are expecting another
- # SOA RR, but saw something else, so this must be an
- # AXFR response.
- #
- rdtype = dns.rdatatype.AXFR
- expecting_SOA = False
- if done and q.keyring and not r.had_tsig:
- raise dns.exception.FormError("missing TSIG")
- yield r
-
-
-class UDPMode(enum.IntEnum):
- """How should UDP be used in an IXFR from :py:func:`inbound_xfr()`?
-
- NEVER means "never use UDP; always use TCP"
- TRY_FIRST means "try to use UDP but fall back to TCP if needed"
- ONLY means "raise ``dns.xfr.UseTCP`` if trying UDP does not succeed"
- """
-
- NEVER = 0
- TRY_FIRST = 1
- ONLY = 2
-
-
-def inbound_xfr(
- where: str,
- txn_manager: dns.transaction.TransactionManager,
- query: Optional[dns.message.Message] = None,
- port: int = 53,
- timeout: Optional[float] = None,
- lifetime: Optional[float] = None,
- source: Optional[str] = None,
- source_port: int = 0,
- udp_mode: UDPMode = UDPMode.NEVER,
-) -> None:
- """Conduct an inbound transfer and apply it via a transaction from the
- txn_manager.
-
- *where*, a ``str`` containing an IPv4 or IPv6 address, where
- to send the message.
-
- *txn_manager*, a ``dns.transaction.TransactionManager``, the txn_manager
- for this transfer (typically a ``dns.zone.Zone``).
-
- *query*, the query to send. If not supplied, a default query is
- constructed using information from the *txn_manager*.
-
- *port*, an ``int``, the port send the message to. The default is 53.
-
- *timeout*, a ``float``, the number of seconds to wait for each
- response message. If None, the default, wait forever.
-
- *lifetime*, a ``float``, the total number of seconds to spend
- doing the transfer. If ``None``, the default, then there is no
- limit on the time the transfer may take.
-
- *source*, a ``str`` containing an IPv4 or IPv6 address, specifying
- the source address. The default is the wildcard address.
-
- *source_port*, an ``int``, the port from which to send the message.
- The default is 0.
-
- *udp_mode*, a ``dns.query.UDPMode``, determines how UDP is used
- for IXFRs. The default is ``dns.UDPMode.NEVER``, i.e. only use
- TCP. Other possibilities are ``dns.UDPMode.TRY_FIRST``, which
- means "try UDP but fallback to TCP if needed", and
- ``dns.UDPMode.ONLY``, which means "try UDP and raise
- ``dns.xfr.UseTCP`` if it does not succeed.
-
- Raises on errors.
- """
- if query is None:
- (query, serial) = dns.xfr.make_query(txn_manager)
- else:
- serial = dns.xfr.extract_serial_from_query(query)
- rdtype = query.question[0].rdtype
- is_ixfr = rdtype == dns.rdatatype.IXFR
- origin = txn_manager.from_wire_origin()
- wire = query.to_wire()
- (af, destination, source) = _destination_and_source(
- where, port, source, source_port
- )
- (_, expiration) = _compute_times(lifetime)
- retry = True
- while retry:
- retry = False
- if is_ixfr and udp_mode != UDPMode.NEVER:
- sock_type = socket.SOCK_DGRAM
- is_udp = True
- else:
- sock_type = socket.SOCK_STREAM
- is_udp = False
- with _make_socket(af, sock_type, source) as s:
- _connect(s, destination, expiration)
- if is_udp:
- _udp_send(s, wire, None, expiration)
- else:
- tcpmsg = struct.pack("!H", len(wire)) + wire
- _net_write(s, tcpmsg, expiration)
- with dns.xfr.Inbound(txn_manager, rdtype, serial, is_udp) as inbound:
- done = False
- tsig_ctx = None
- while not done:
- (_, mexpiration) = _compute_times(timeout)
- if mexpiration is None or (
- expiration is not None and mexpiration > expiration
- ):
- mexpiration = expiration
- if is_udp:
- (rwire, _) = _udp_recv(s, 65535, mexpiration)
- else:
- ldata = _net_read(s, 2, mexpiration)
- (l,) = struct.unpack("!H", ldata)
- rwire = _net_read(s, l, mexpiration)
- r = dns.message.from_wire(
- rwire,
- keyring=query.keyring,
- request_mac=query.mac,
- xfr=True,
- origin=origin,
- tsig_ctx=tsig_ctx,
- multi=(not is_udp),
- one_rr_per_rrset=is_ixfr,
- )
- try:
- done = inbound.process_message(r)
- except dns.xfr.UseTCP:
- assert is_udp # should not happen if we used TCP!
- if udp_mode == UDPMode.ONLY:
- raise
- done = True
- retry = True
- udp_mode = UDPMode.NEVER
- continue
- tsig_ctx = r.tsig_ctx
- if not retry and query.keyring and not r.had_tsig:
- raise dns.exception.FormError("missing TSIG")
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__init__.py b/.venv/lib/python3.12/site-packages/dns/quic/__init__.py
deleted file mode 100644
index 20aff34..0000000
--- a/.venv/lib/python3.12/site-packages/dns/quic/__init__.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import dns._features
-import dns.asyncbackend
-
-if dns._features.have("doq"):
- import aioquic.quic.configuration # type: ignore
-
- from dns._asyncbackend import NullContext
- from dns.quic._asyncio import (
- AsyncioQuicConnection,
- AsyncioQuicManager,
- AsyncioQuicStream,
- )
- from dns.quic._common import AsyncQuicConnection, AsyncQuicManager
- from dns.quic._sync import SyncQuicConnection, SyncQuicManager, SyncQuicStream
-
- have_quic = True
-
- def null_factory(
- *args, # pylint: disable=unused-argument
- **kwargs, # pylint: disable=unused-argument
- ):
- return NullContext(None)
-
- def _asyncio_manager_factory(
- context, *args, **kwargs # pylint: disable=unused-argument
- ):
- return AsyncioQuicManager(*args, **kwargs)
-
- # We have a context factory and a manager factory as for trio we need to have
- # a nursery.
-
- _async_factories = {"asyncio": (null_factory, _asyncio_manager_factory)}
-
- if dns._features.have("trio"):
- import trio
-
- from dns.quic._trio import ( # pylint: disable=ungrouped-imports
- TrioQuicConnection,
- TrioQuicManager,
- TrioQuicStream,
- )
-
- def _trio_context_factory():
- return trio.open_nursery()
-
- def _trio_manager_factory(context, *args, **kwargs):
- return TrioQuicManager(context, *args, **kwargs)
-
- _async_factories["trio"] = (_trio_context_factory, _trio_manager_factory)
-
- def factories_for_backend(backend=None):
- if backend is None:
- backend = dns.asyncbackend.get_default_backend()
- return _async_factories[backend.name()]
-
-else: # pragma: no cover
- have_quic = False
-
- from typing import Any
-
- class AsyncQuicStream: # type: ignore
- pass
-
- class AsyncQuicConnection: # type: ignore
- async def make_stream(self) -> Any:
- raise NotImplementedError
-
- class SyncQuicStream: # type: ignore
- pass
-
- class SyncQuicConnection: # type: ignore
- def make_stream(self) -> Any:
- raise NotImplementedError
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 0ba9486..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_asyncio.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_asyncio.cpython-312.pyc
deleted file mode 100644
index 9ef9d2e..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_asyncio.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_common.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_common.cpython-312.pyc
deleted file mode 100644
index 8586ca8..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_common.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_sync.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_sync.cpython-312.pyc
deleted file mode 100644
index c0d1694..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_sync.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_trio.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_trio.cpython-312.pyc
deleted file mode 100644
index 2b67e75..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/quic/__pycache__/_trio.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/_asyncio.py b/.venv/lib/python3.12/site-packages/dns/quic/_asyncio.py
deleted file mode 100644
index 0f44331..0000000
--- a/.venv/lib/python3.12/site-packages/dns/quic/_asyncio.py
+++ /dev/null
@@ -1,228 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import asyncio
-import socket
-import ssl
-import struct
-import time
-
-import aioquic.quic.configuration # type: ignore
-import aioquic.quic.connection # type: ignore
-import aioquic.quic.events # type: ignore
-
-import dns.asyncbackend
-import dns.exception
-import dns.inet
-from dns.quic._common import (
- QUIC_MAX_DATAGRAM,
- AsyncQuicConnection,
- AsyncQuicManager,
- BaseQuicStream,
- UnexpectedEOF,
-)
-
-
-class AsyncioQuicStream(BaseQuicStream):
- def __init__(self, connection, stream_id):
- super().__init__(connection, stream_id)
- self._wake_up = asyncio.Condition()
-
- async def _wait_for_wake_up(self):
- async with self._wake_up:
- await self._wake_up.wait()
-
- async def wait_for(self, amount, expiration):
- while True:
- timeout = self._timeout_from_expiration(expiration)
- if self._buffer.have(amount):
- return
- self._expecting = amount
- try:
- await asyncio.wait_for(self._wait_for_wake_up(), timeout)
- except TimeoutError:
- raise dns.exception.Timeout
- self._expecting = 0
-
- async def receive(self, timeout=None):
- expiration = self._expiration_from_timeout(timeout)
- await self.wait_for(2, expiration)
- (size,) = struct.unpack("!H", self._buffer.get(2))
- await self.wait_for(size, expiration)
- return self._buffer.get(size)
-
- async def send(self, datagram, is_end=False):
- data = self._encapsulate(datagram)
- await self._connection.write(self._stream_id, data, is_end)
-
- async def _add_input(self, data, is_end):
- if self._common_add_input(data, is_end):
- async with self._wake_up:
- self._wake_up.notify()
-
- async def close(self):
- self._close()
-
- # Streams are async context managers
-
- async def __aenter__(self):
- return self
-
- async def __aexit__(self, exc_type, exc_val, exc_tb):
- await self.close()
- async with self._wake_up:
- self._wake_up.notify()
- return False
-
-
-class AsyncioQuicConnection(AsyncQuicConnection):
- def __init__(self, connection, address, port, source, source_port, manager=None):
- super().__init__(connection, address, port, source, source_port, manager)
- self._socket = None
- self._handshake_complete = asyncio.Event()
- self._socket_created = asyncio.Event()
- self._wake_timer = asyncio.Condition()
- self._receiver_task = None
- self._sender_task = None
-
- async def _receiver(self):
- try:
- af = dns.inet.af_for_address(self._address)
- backend = dns.asyncbackend.get_backend("asyncio")
- # Note that peer is a low-level address tuple, but make_socket() wants
- # a high-level address tuple, so we convert.
- self._socket = await backend.make_socket(
- af, socket.SOCK_DGRAM, 0, self._source, (self._peer[0], self._peer[1])
- )
- self._socket_created.set()
- async with self._socket:
- while not self._done:
- (datagram, address) = await self._socket.recvfrom(
- QUIC_MAX_DATAGRAM, None
- )
- if address[0] != self._peer[0] or address[1] != self._peer[1]:
- continue
- self._connection.receive_datagram(datagram, address, time.time())
- # Wake up the timer in case the sender is sleeping, as there may be
- # stuff to send now.
- async with self._wake_timer:
- self._wake_timer.notify_all()
- except Exception:
- pass
- finally:
- self._done = True
- async with self._wake_timer:
- self._wake_timer.notify_all()
- self._handshake_complete.set()
-
- async def _wait_for_wake_timer(self):
- async with self._wake_timer:
- await self._wake_timer.wait()
-
- async def _sender(self):
- await self._socket_created.wait()
- while not self._done:
- datagrams = self._connection.datagrams_to_send(time.time())
- for datagram, address in datagrams:
- assert address == self._peer
- await self._socket.sendto(datagram, self._peer, None)
- (expiration, interval) = self._get_timer_values()
- try:
- await asyncio.wait_for(self._wait_for_wake_timer(), interval)
- except Exception:
- pass
- self._handle_timer(expiration)
- await self._handle_events()
-
- async def _handle_events(self):
- count = 0
- while True:
- event = self._connection.next_event()
- if event is None:
- return
- if isinstance(event, aioquic.quic.events.StreamDataReceived):
- stream = self._streams.get(event.stream_id)
- if stream:
- await stream._add_input(event.data, event.end_stream)
- elif isinstance(event, aioquic.quic.events.HandshakeCompleted):
- self._handshake_complete.set()
- elif isinstance(event, aioquic.quic.events.ConnectionTerminated):
- self._done = True
- self._receiver_task.cancel()
- elif isinstance(event, aioquic.quic.events.StreamReset):
- stream = self._streams.get(event.stream_id)
- if stream:
- await stream._add_input(b"", True)
-
- count += 1
- if count > 10:
- # yield
- count = 0
- await asyncio.sleep(0)
-
- async def write(self, stream, data, is_end=False):
- self._connection.send_stream_data(stream, data, is_end)
- async with self._wake_timer:
- self._wake_timer.notify_all()
-
- def run(self):
- if self._closed:
- return
- self._receiver_task = asyncio.Task(self._receiver())
- self._sender_task = asyncio.Task(self._sender())
-
- async def make_stream(self, timeout=None):
- try:
- await asyncio.wait_for(self._handshake_complete.wait(), timeout)
- except TimeoutError:
- raise dns.exception.Timeout
- if self._done:
- raise UnexpectedEOF
- stream_id = self._connection.get_next_available_stream_id(False)
- stream = AsyncioQuicStream(self, stream_id)
- self._streams[stream_id] = stream
- return stream
-
- async def close(self):
- if not self._closed:
- self._manager.closed(self._peer[0], self._peer[1])
- self._closed = True
- self._connection.close()
- # sender might be blocked on this, so set it
- self._socket_created.set()
- async with self._wake_timer:
- self._wake_timer.notify_all()
- try:
- await self._receiver_task
- except asyncio.CancelledError:
- pass
- try:
- await self._sender_task
- except asyncio.CancelledError:
- pass
- await self._socket.close()
-
-
-class AsyncioQuicManager(AsyncQuicManager):
- def __init__(self, conf=None, verify_mode=ssl.CERT_REQUIRED, server_name=None):
- super().__init__(conf, verify_mode, AsyncioQuicConnection, server_name)
-
- def connect(
- self, address, port=853, source=None, source_port=0, want_session_ticket=True
- ):
- (connection, start) = self._connect(
- address, port, source, source_port, want_session_ticket
- )
- if start:
- connection.run()
- return connection
-
- async def __aenter__(self):
- return self
-
- async def __aexit__(self, exc_type, exc_val, exc_tb):
- # Copy the iterator into a list as exiting things will mutate the connections
- # table.
- connections = list(self._connections.values())
- for connection in connections:
- await connection.close()
- return False
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/_common.py b/.venv/lib/python3.12/site-packages/dns/quic/_common.py
deleted file mode 100644
index 0eacc69..0000000
--- a/.venv/lib/python3.12/site-packages/dns/quic/_common.py
+++ /dev/null
@@ -1,224 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import copy
-import functools
-import socket
-import struct
-import time
-from typing import Any, Optional
-
-import aioquic.quic.configuration # type: ignore
-import aioquic.quic.connection # type: ignore
-
-import dns.inet
-
-QUIC_MAX_DATAGRAM = 2048
-MAX_SESSION_TICKETS = 8
-# If we hit the max sessions limit we will delete this many of the oldest connections.
-# The value must be a integer > 0 and <= MAX_SESSION_TICKETS.
-SESSIONS_TO_DELETE = MAX_SESSION_TICKETS // 4
-
-
-class UnexpectedEOF(Exception):
- pass
-
-
-class Buffer:
- def __init__(self):
- self._buffer = b""
- self._seen_end = False
-
- def put(self, data, is_end):
- if self._seen_end:
- return
- self._buffer += data
- if is_end:
- self._seen_end = True
-
- def have(self, amount):
- if len(self._buffer) >= amount:
- return True
- if self._seen_end:
- raise UnexpectedEOF
- return False
-
- def seen_end(self):
- return self._seen_end
-
- def get(self, amount):
- assert self.have(amount)
- data = self._buffer[:amount]
- self._buffer = self._buffer[amount:]
- return data
-
-
-class BaseQuicStream:
- def __init__(self, connection, stream_id):
- self._connection = connection
- self._stream_id = stream_id
- self._buffer = Buffer()
- self._expecting = 0
-
- def id(self):
- return self._stream_id
-
- def _expiration_from_timeout(self, timeout):
- if timeout is not None:
- expiration = time.time() + timeout
- else:
- expiration = None
- return expiration
-
- def _timeout_from_expiration(self, expiration):
- if expiration is not None:
- timeout = max(expiration - time.time(), 0.0)
- else:
- timeout = None
- return timeout
-
- # Subclass must implement receive() as sync / async and which returns a message
- # or raises UnexpectedEOF.
-
- def _encapsulate(self, datagram):
- l = len(datagram)
- return struct.pack("!H", l) + datagram
-
- def _common_add_input(self, data, is_end):
- self._buffer.put(data, is_end)
- try:
- return self._expecting > 0 and self._buffer.have(self._expecting)
- except UnexpectedEOF:
- return True
-
- def _close(self):
- self._connection.close_stream(self._stream_id)
- self._buffer.put(b"", True) # send EOF in case we haven't seen it.
-
-
-class BaseQuicConnection:
- def __init__(
- self, connection, address, port, source=None, source_port=0, manager=None
- ):
- self._done = False
- self._connection = connection
- self._address = address
- self._port = port
- self._closed = False
- self._manager = manager
- self._streams = {}
- self._af = dns.inet.af_for_address(address)
- self._peer = dns.inet.low_level_address_tuple((address, port))
- if source is None and source_port != 0:
- if self._af == socket.AF_INET:
- source = "0.0.0.0"
- elif self._af == socket.AF_INET6:
- source = "::"
- else:
- raise NotImplementedError
- if source:
- self._source = (source, source_port)
- else:
- self._source = None
-
- def close_stream(self, stream_id):
- del self._streams[stream_id]
-
- def _get_timer_values(self, closed_is_special=True):
- now = time.time()
- expiration = self._connection.get_timer()
- if expiration is None:
- expiration = now + 3600 # arbitrary "big" value
- interval = max(expiration - now, 0)
- if self._closed and closed_is_special:
- # lower sleep interval to avoid a race in the closing process
- # which can lead to higher latency closing due to sleeping when
- # we have events.
- interval = min(interval, 0.05)
- return (expiration, interval)
-
- def _handle_timer(self, expiration):
- now = time.time()
- if expiration <= now:
- self._connection.handle_timer(now)
-
-
-class AsyncQuicConnection(BaseQuicConnection):
- async def make_stream(self, timeout: Optional[float] = None) -> Any:
- pass
-
-
-class BaseQuicManager:
- def __init__(self, conf, verify_mode, connection_factory, server_name=None):
- self._connections = {}
- self._connection_factory = connection_factory
- self._session_tickets = {}
- if conf is None:
- verify_path = None
- if isinstance(verify_mode, str):
- verify_path = verify_mode
- verify_mode = True
- conf = aioquic.quic.configuration.QuicConfiguration(
- alpn_protocols=["doq", "doq-i03"],
- verify_mode=verify_mode,
- server_name=server_name,
- )
- if verify_path is not None:
- conf.load_verify_locations(verify_path)
- self._conf = conf
-
- def _connect(
- self, address, port=853, source=None, source_port=0, want_session_ticket=True
- ):
- connection = self._connections.get((address, port))
- if connection is not None:
- return (connection, False)
- conf = self._conf
- if want_session_ticket:
- try:
- session_ticket = self._session_tickets.pop((address, port))
- # We found a session ticket, so make a configuration that uses it.
- conf = copy.copy(conf)
- conf.session_ticket = session_ticket
- except KeyError:
- # No session ticket.
- pass
- # Whether or not we found a session ticket, we want a handler to save
- # one.
- session_ticket_handler = functools.partial(
- self.save_session_ticket, address, port
- )
- else:
- session_ticket_handler = None
- qconn = aioquic.quic.connection.QuicConnection(
- configuration=conf,
- session_ticket_handler=session_ticket_handler,
- )
- lladdress = dns.inet.low_level_address_tuple((address, port))
- qconn.connect(lladdress, time.time())
- connection = self._connection_factory(
- qconn, address, port, source, source_port, self
- )
- self._connections[(address, port)] = connection
- return (connection, True)
-
- def closed(self, address, port):
- try:
- del self._connections[(address, port)]
- except KeyError:
- pass
-
- def save_session_ticket(self, address, port, ticket):
- # We rely on dictionaries keys() being in insertion order here. We
- # can't just popitem() as that would be LIFO which is the opposite of
- # what we want.
- l = len(self._session_tickets)
- if l >= MAX_SESSION_TICKETS:
- keys_to_delete = list(self._session_tickets.keys())[0:SESSIONS_TO_DELETE]
- for key in keys_to_delete:
- del self._session_tickets[key]
- self._session_tickets[(address, port)] = ticket
-
-
-class AsyncQuicManager(BaseQuicManager):
- def connect(self, address, port=853, source=None, source_port=0):
- raise NotImplementedError
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/_sync.py b/.venv/lib/python3.12/site-packages/dns/quic/_sync.py
deleted file mode 100644
index 120cb5f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/quic/_sync.py
+++ /dev/null
@@ -1,238 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import selectors
-import socket
-import ssl
-import struct
-import threading
-import time
-
-import aioquic.quic.configuration # type: ignore
-import aioquic.quic.connection # type: ignore
-import aioquic.quic.events # type: ignore
-
-import dns.exception
-import dns.inet
-from dns.quic._common import (
- QUIC_MAX_DATAGRAM,
- BaseQuicConnection,
- BaseQuicManager,
- BaseQuicStream,
- UnexpectedEOF,
-)
-
-# Avoid circularity with dns.query
-if hasattr(selectors, "PollSelector"):
- _selector_class = selectors.PollSelector # type: ignore
-else:
- _selector_class = selectors.SelectSelector # type: ignore
-
-
-class SyncQuicStream(BaseQuicStream):
- def __init__(self, connection, stream_id):
- super().__init__(connection, stream_id)
- self._wake_up = threading.Condition()
- self._lock = threading.Lock()
-
- def wait_for(self, amount, expiration):
- while True:
- timeout = self._timeout_from_expiration(expiration)
- with self._lock:
- if self._buffer.have(amount):
- return
- self._expecting = amount
- with self._wake_up:
- if not self._wake_up.wait(timeout):
- raise dns.exception.Timeout
- self._expecting = 0
-
- def receive(self, timeout=None):
- expiration = self._expiration_from_timeout(timeout)
- self.wait_for(2, expiration)
- with self._lock:
- (size,) = struct.unpack("!H", self._buffer.get(2))
- self.wait_for(size, expiration)
- with self._lock:
- return self._buffer.get(size)
-
- def send(self, datagram, is_end=False):
- data = self._encapsulate(datagram)
- self._connection.write(self._stream_id, data, is_end)
-
- def _add_input(self, data, is_end):
- if self._common_add_input(data, is_end):
- with self._wake_up:
- self._wake_up.notify()
-
- def close(self):
- with self._lock:
- self._close()
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- self.close()
- with self._wake_up:
- self._wake_up.notify()
- return False
-
-
-class SyncQuicConnection(BaseQuicConnection):
- def __init__(self, connection, address, port, source, source_port, manager):
- super().__init__(connection, address, port, source, source_port, manager)
- self._socket = socket.socket(self._af, socket.SOCK_DGRAM, 0)
- if self._source is not None:
- try:
- self._socket.bind(
- dns.inet.low_level_address_tuple(self._source, self._af)
- )
- except Exception:
- self._socket.close()
- raise
- self._socket.connect(self._peer)
- (self._send_wakeup, self._receive_wakeup) = socket.socketpair()
- self._receive_wakeup.setblocking(False)
- self._socket.setblocking(False)
- self._handshake_complete = threading.Event()
- self._worker_thread = None
- self._lock = threading.Lock()
-
- def _read(self):
- count = 0
- while count < 10:
- count += 1
- try:
- datagram = self._socket.recv(QUIC_MAX_DATAGRAM)
- except BlockingIOError:
- return
- with self._lock:
- self._connection.receive_datagram(datagram, self._peer, time.time())
-
- def _drain_wakeup(self):
- while True:
- try:
- self._receive_wakeup.recv(32)
- except BlockingIOError:
- return
-
- def _worker(self):
- try:
- sel = _selector_class()
- sel.register(self._socket, selectors.EVENT_READ, self._read)
- sel.register(self._receive_wakeup, selectors.EVENT_READ, self._drain_wakeup)
- while not self._done:
- (expiration, interval) = self._get_timer_values(False)
- items = sel.select(interval)
- for key, _ in items:
- key.data()
- with self._lock:
- self._handle_timer(expiration)
- self._handle_events()
- with self._lock:
- datagrams = self._connection.datagrams_to_send(time.time())
- for datagram, _ in datagrams:
- try:
- self._socket.send(datagram)
- except BlockingIOError:
- # we let QUIC handle any lossage
- pass
- finally:
- with self._lock:
- self._done = True
- # Ensure anyone waiting for this gets woken up.
- self._handshake_complete.set()
-
- def _handle_events(self):
- while True:
- with self._lock:
- event = self._connection.next_event()
- if event is None:
- return
- if isinstance(event, aioquic.quic.events.StreamDataReceived):
- with self._lock:
- stream = self._streams.get(event.stream_id)
- if stream:
- stream._add_input(event.data, event.end_stream)
- elif isinstance(event, aioquic.quic.events.HandshakeCompleted):
- self._handshake_complete.set()
- elif isinstance(event, aioquic.quic.events.ConnectionTerminated):
- with self._lock:
- self._done = True
- elif isinstance(event, aioquic.quic.events.StreamReset):
- with self._lock:
- stream = self._streams.get(event.stream_id)
- if stream:
- stream._add_input(b"", True)
-
- def write(self, stream, data, is_end=False):
- with self._lock:
- self._connection.send_stream_data(stream, data, is_end)
- self._send_wakeup.send(b"\x01")
-
- def run(self):
- if self._closed:
- return
- self._worker_thread = threading.Thread(target=self._worker)
- self._worker_thread.start()
-
- def make_stream(self, timeout=None):
- if not self._handshake_complete.wait(timeout):
- raise dns.exception.Timeout
- with self._lock:
- if self._done:
- raise UnexpectedEOF
- stream_id = self._connection.get_next_available_stream_id(False)
- stream = SyncQuicStream(self, stream_id)
- self._streams[stream_id] = stream
- return stream
-
- def close_stream(self, stream_id):
- with self._lock:
- super().close_stream(stream_id)
-
- def close(self):
- with self._lock:
- if self._closed:
- return
- self._manager.closed(self._peer[0], self._peer[1])
- self._closed = True
- self._connection.close()
- self._send_wakeup.send(b"\x01")
- self._worker_thread.join()
-
-
-class SyncQuicManager(BaseQuicManager):
- def __init__(self, conf=None, verify_mode=ssl.CERT_REQUIRED, server_name=None):
- super().__init__(conf, verify_mode, SyncQuicConnection, server_name)
- self._lock = threading.Lock()
-
- def connect(
- self, address, port=853, source=None, source_port=0, want_session_ticket=True
- ):
- with self._lock:
- (connection, start) = self._connect(
- address, port, source, source_port, want_session_ticket
- )
- if start:
- connection.run()
- return connection
-
- def closed(self, address, port):
- with self._lock:
- super().closed(address, port)
-
- def save_session_ticket(self, address, port, ticket):
- with self._lock:
- super().save_session_ticket(address, port, ticket)
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- # Copy the iterator into a list as exiting things will mutate the connections
- # table.
- connections = list(self._connections.values())
- for connection in connections:
- connection.close()
- return False
diff --git a/.venv/lib/python3.12/site-packages/dns/quic/_trio.py b/.venv/lib/python3.12/site-packages/dns/quic/_trio.py
deleted file mode 100644
index 35e36b9..0000000
--- a/.venv/lib/python3.12/site-packages/dns/quic/_trio.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import socket
-import ssl
-import struct
-import time
-
-import aioquic.quic.configuration # type: ignore
-import aioquic.quic.connection # type: ignore
-import aioquic.quic.events # type: ignore
-import trio
-
-import dns.exception
-import dns.inet
-from dns._asyncbackend import NullContext
-from dns.quic._common import (
- QUIC_MAX_DATAGRAM,
- AsyncQuicConnection,
- AsyncQuicManager,
- BaseQuicStream,
- UnexpectedEOF,
-)
-
-
-class TrioQuicStream(BaseQuicStream):
- def __init__(self, connection, stream_id):
- super().__init__(connection, stream_id)
- self._wake_up = trio.Condition()
-
- async def wait_for(self, amount):
- while True:
- if self._buffer.have(amount):
- return
- self._expecting = amount
- async with self._wake_up:
- await self._wake_up.wait()
- self._expecting = 0
-
- async def receive(self, timeout=None):
- if timeout is None:
- context = NullContext(None)
- else:
- context = trio.move_on_after(timeout)
- with context:
- await self.wait_for(2)
- (size,) = struct.unpack("!H", self._buffer.get(2))
- await self.wait_for(size)
- return self._buffer.get(size)
- raise dns.exception.Timeout
-
- async def send(self, datagram, is_end=False):
- data = self._encapsulate(datagram)
- await self._connection.write(self._stream_id, data, is_end)
-
- async def _add_input(self, data, is_end):
- if self._common_add_input(data, is_end):
- async with self._wake_up:
- self._wake_up.notify()
-
- async def close(self):
- self._close()
-
- # Streams are async context managers
-
- async def __aenter__(self):
- return self
-
- async def __aexit__(self, exc_type, exc_val, exc_tb):
- await self.close()
- async with self._wake_up:
- self._wake_up.notify()
- return False
-
-
-class TrioQuicConnection(AsyncQuicConnection):
- def __init__(self, connection, address, port, source, source_port, manager=None):
- super().__init__(connection, address, port, source, source_port, manager)
- self._socket = trio.socket.socket(self._af, socket.SOCK_DGRAM, 0)
- self._handshake_complete = trio.Event()
- self._run_done = trio.Event()
- self._worker_scope = None
- self._send_pending = False
-
- async def _worker(self):
- try:
- if self._source:
- await self._socket.bind(
- dns.inet.low_level_address_tuple(self._source, self._af)
- )
- await self._socket.connect(self._peer)
- while not self._done:
- (expiration, interval) = self._get_timer_values(False)
- if self._send_pending:
- # Do not block forever if sends are pending. Even though we
- # have a wake-up mechanism if we've already started the blocking
- # read, the possibility of context switching in send means that
- # more writes can happen while we have no wake up context, so
- # we need self._send_pending to avoid (effectively) a "lost wakeup"
- # race.
- interval = 0.0
- with trio.CancelScope(
- deadline=trio.current_time() + interval
- ) as self._worker_scope:
- datagram = await self._socket.recv(QUIC_MAX_DATAGRAM)
- self._connection.receive_datagram(datagram, self._peer, time.time())
- self._worker_scope = None
- self._handle_timer(expiration)
- await self._handle_events()
- # We clear this now, before sending anything, as sending can cause
- # context switches that do more sends. We want to know if that
- # happens so we don't block a long time on the recv() above.
- self._send_pending = False
- datagrams = self._connection.datagrams_to_send(time.time())
- for datagram, _ in datagrams:
- await self._socket.send(datagram)
- finally:
- self._done = True
- self._handshake_complete.set()
-
- async def _handle_events(self):
- count = 0
- while True:
- event = self._connection.next_event()
- if event is None:
- return
- if isinstance(event, aioquic.quic.events.StreamDataReceived):
- stream = self._streams.get(event.stream_id)
- if stream:
- await stream._add_input(event.data, event.end_stream)
- elif isinstance(event, aioquic.quic.events.HandshakeCompleted):
- self._handshake_complete.set()
- elif isinstance(event, aioquic.quic.events.ConnectionTerminated):
- self._done = True
- self._socket.close()
- elif isinstance(event, aioquic.quic.events.StreamReset):
- stream = self._streams.get(event.stream_id)
- if stream:
- await stream._add_input(b"", True)
- count += 1
- if count > 10:
- # yield
- count = 0
- await trio.sleep(0)
-
- async def write(self, stream, data, is_end=False):
- self._connection.send_stream_data(stream, data, is_end)
- self._send_pending = True
- if self._worker_scope is not None:
- self._worker_scope.cancel()
-
- async def run(self):
- if self._closed:
- return
- async with trio.open_nursery() as nursery:
- nursery.start_soon(self._worker)
- self._run_done.set()
-
- async def make_stream(self, timeout=None):
- if timeout is None:
- context = NullContext(None)
- else:
- context = trio.move_on_after(timeout)
- with context:
- await self._handshake_complete.wait()
- if self._done:
- raise UnexpectedEOF
- stream_id = self._connection.get_next_available_stream_id(False)
- stream = TrioQuicStream(self, stream_id)
- self._streams[stream_id] = stream
- return stream
- raise dns.exception.Timeout
-
- async def close(self):
- if not self._closed:
- self._manager.closed(self._peer[0], self._peer[1])
- self._closed = True
- self._connection.close()
- self._send_pending = True
- if self._worker_scope is not None:
- self._worker_scope.cancel()
- await self._run_done.wait()
-
-
-class TrioQuicManager(AsyncQuicManager):
- def __init__(
- self, nursery, conf=None, verify_mode=ssl.CERT_REQUIRED, server_name=None
- ):
- super().__init__(conf, verify_mode, TrioQuicConnection, server_name)
- self._nursery = nursery
-
- def connect(
- self, address, port=853, source=None, source_port=0, want_session_ticket=True
- ):
- (connection, start) = self._connect(
- address, port, source, source_port, want_session_ticket
- )
- if start:
- self._nursery.start_soon(connection.run)
- return connection
-
- async def __aenter__(self):
- return self
-
- async def __aexit__(self, exc_type, exc_val, exc_tb):
- # Copy the iterator into a list as exiting things will mutate the connections
- # table.
- connections = list(self._connections.values())
- for connection in connections:
- await connection.close()
- return False
diff --git a/.venv/lib/python3.12/site-packages/dns/rcode.py b/.venv/lib/python3.12/site-packages/dns/rcode.py
deleted file mode 100644
index 8e6386f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rcode.py
+++ /dev/null
@@ -1,168 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Result Codes."""
-
-from typing import Tuple
-
-import dns.enum
-import dns.exception
-
-
-class Rcode(dns.enum.IntEnum):
- #: No error
- NOERROR = 0
- #: Format error
- FORMERR = 1
- #: Server failure
- SERVFAIL = 2
- #: Name does not exist ("Name Error" in RFC 1025 terminology).
- NXDOMAIN = 3
- #: Not implemented
- NOTIMP = 4
- #: Refused
- REFUSED = 5
- #: Name exists.
- YXDOMAIN = 6
- #: RRset exists.
- YXRRSET = 7
- #: RRset does not exist.
- NXRRSET = 8
- #: Not authoritative.
- NOTAUTH = 9
- #: Name not in zone.
- NOTZONE = 10
- #: DSO-TYPE Not Implemented
- DSOTYPENI = 11
- #: Bad EDNS version.
- BADVERS = 16
- #: TSIG Signature Failure
- BADSIG = 16
- #: Key not recognized.
- BADKEY = 17
- #: Signature out of time window.
- BADTIME = 18
- #: Bad TKEY Mode.
- BADMODE = 19
- #: Duplicate key name.
- BADNAME = 20
- #: Algorithm not supported.
- BADALG = 21
- #: Bad Truncation
- BADTRUNC = 22
- #: Bad/missing Server Cookie
- BADCOOKIE = 23
-
- @classmethod
- def _maximum(cls):
- return 4095
-
- @classmethod
- def _unknown_exception_class(cls):
- return UnknownRcode
-
-
-class UnknownRcode(dns.exception.DNSException):
- """A DNS rcode is unknown."""
-
-
-def from_text(text: str) -> Rcode:
- """Convert text into an rcode.
-
- *text*, a ``str``, the textual rcode or an integer in textual form.
-
- Raises ``dns.rcode.UnknownRcode`` if the rcode mnemonic is unknown.
-
- Returns a ``dns.rcode.Rcode``.
- """
-
- return Rcode.from_text(text)
-
-
-def from_flags(flags: int, ednsflags: int) -> Rcode:
- """Return the rcode value encoded by flags and ednsflags.
-
- *flags*, an ``int``, the DNS flags field.
-
- *ednsflags*, an ``int``, the EDNS flags field.
-
- Raises ``ValueError`` if rcode is < 0 or > 4095
-
- Returns a ``dns.rcode.Rcode``.
- """
-
- value = (flags & 0x000F) | ((ednsflags >> 20) & 0xFF0)
- return Rcode.make(value)
-
-
-def to_flags(value: Rcode) -> Tuple[int, int]:
- """Return a (flags, ednsflags) tuple which encodes the rcode.
-
- *value*, a ``dns.rcode.Rcode``, the rcode.
-
- Raises ``ValueError`` if rcode is < 0 or > 4095.
-
- Returns an ``(int, int)`` tuple.
- """
-
- if value < 0 or value > 4095:
- raise ValueError("rcode must be >= 0 and <= 4095")
- v = value & 0xF
- ev = (value & 0xFF0) << 20
- return (v, ev)
-
-
-def to_text(value: Rcode, tsig: bool = False) -> str:
- """Convert rcode into text.
-
- *value*, a ``dns.rcode.Rcode``, the rcode.
-
- Raises ``ValueError`` if rcode is < 0 or > 4095.
-
- Returns a ``str``.
- """
-
- if tsig and value == Rcode.BADVERS:
- return "BADSIG"
- return Rcode.to_text(value)
-
-
-### BEGIN generated Rcode constants
-
-NOERROR = Rcode.NOERROR
-FORMERR = Rcode.FORMERR
-SERVFAIL = Rcode.SERVFAIL
-NXDOMAIN = Rcode.NXDOMAIN
-NOTIMP = Rcode.NOTIMP
-REFUSED = Rcode.REFUSED
-YXDOMAIN = Rcode.YXDOMAIN
-YXRRSET = Rcode.YXRRSET
-NXRRSET = Rcode.NXRRSET
-NOTAUTH = Rcode.NOTAUTH
-NOTZONE = Rcode.NOTZONE
-DSOTYPENI = Rcode.DSOTYPENI
-BADVERS = Rcode.BADVERS
-BADSIG = Rcode.BADSIG
-BADKEY = Rcode.BADKEY
-BADTIME = Rcode.BADTIME
-BADMODE = Rcode.BADMODE
-BADNAME = Rcode.BADNAME
-BADALG = Rcode.BADALG
-BADTRUNC = Rcode.BADTRUNC
-BADCOOKIE = Rcode.BADCOOKIE
-
-### END generated Rcode constants
diff --git a/.venv/lib/python3.12/site-packages/dns/rdata.py b/.venv/lib/python3.12/site-packages/dns/rdata.py
deleted file mode 100644
index 024fd8f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdata.py
+++ /dev/null
@@ -1,884 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS rdata."""
-
-import base64
-import binascii
-import inspect
-import io
-import itertools
-import random
-from importlib import import_module
-from typing import Any, Dict, Optional, Tuple, Union
-
-import dns.exception
-import dns.immutable
-import dns.ipv4
-import dns.ipv6
-import dns.name
-import dns.rdataclass
-import dns.rdatatype
-import dns.tokenizer
-import dns.ttl
-import dns.wire
-
-_chunksize = 32
-
-# We currently allow comparisons for rdata with relative names for backwards
-# compatibility, but in the future we will not, as these kinds of comparisons
-# can lead to subtle bugs if code is not carefully written.
-#
-# This switch allows the future behavior to be turned on so code can be
-# tested with it.
-_allow_relative_comparisons = True
-
-
-class NoRelativeRdataOrdering(dns.exception.DNSException):
- """An attempt was made to do an ordered comparison of one or more
- rdata with relative names. The only reliable way of sorting rdata
- is to use non-relativized rdata.
-
- """
-
-
-def _wordbreak(data, chunksize=_chunksize, separator=b" "):
- """Break a binary string into chunks of chunksize characters separated by
- a space.
- """
-
- if not chunksize:
- return data.decode()
- return separator.join(
- [data[i : i + chunksize] for i in range(0, len(data), chunksize)]
- ).decode()
-
-
-# pylint: disable=unused-argument
-
-
-def _hexify(data, chunksize=_chunksize, separator=b" ", **kw):
- """Convert a binary string into its hex encoding, broken up into chunks
- of chunksize characters separated by a separator.
- """
-
- return _wordbreak(binascii.hexlify(data), chunksize, separator)
-
-
-def _base64ify(data, chunksize=_chunksize, separator=b" ", **kw):
- """Convert a binary string into its base64 encoding, broken up into chunks
- of chunksize characters separated by a separator.
- """
-
- return _wordbreak(base64.b64encode(data), chunksize, separator)
-
-
-# pylint: enable=unused-argument
-
-__escaped = b'"\\'
-
-
-def _escapify(qstring):
- """Escape the characters in a quoted string which need it."""
-
- if isinstance(qstring, str):
- qstring = qstring.encode()
- if not isinstance(qstring, bytearray):
- qstring = bytearray(qstring)
-
- text = ""
- for c in qstring:
- if c in __escaped:
- text += "\\" + chr(c)
- elif c >= 0x20 and c < 0x7F:
- text += chr(c)
- else:
- text += "\\%03d" % c
- return text
-
-
-def _truncate_bitmap(what):
- """Determine the index of greatest byte that isn't all zeros, and
- return the bitmap that contains all the bytes less than that index.
- """
-
- for i in range(len(what) - 1, -1, -1):
- if what[i] != 0:
- return what[0 : i + 1]
- return what[0:1]
-
-
-# So we don't have to edit all the rdata classes...
-_constify = dns.immutable.constify
-
-
-@dns.immutable.immutable
-class Rdata:
- """Base class for all DNS rdata types."""
-
- __slots__ = ["rdclass", "rdtype", "rdcomment"]
-
- def __init__(self, rdclass, rdtype):
- """Initialize an rdata.
-
- *rdclass*, an ``int`` is the rdataclass of the Rdata.
-
- *rdtype*, an ``int`` is the rdatatype of the Rdata.
- """
-
- self.rdclass = self._as_rdataclass(rdclass)
- self.rdtype = self._as_rdatatype(rdtype)
- self.rdcomment = None
-
- def _get_all_slots(self):
- return itertools.chain.from_iterable(
- getattr(cls, "__slots__", []) for cls in self.__class__.__mro__
- )
-
- def __getstate__(self):
- # We used to try to do a tuple of all slots here, but it
- # doesn't work as self._all_slots isn't available at
- # __setstate__() time. Before that we tried to store a tuple
- # of __slots__, but that didn't work as it didn't store the
- # slots defined by ancestors. This older way didn't fail
- # outright, but ended up with partially broken objects, e.g.
- # if you unpickled an A RR it wouldn't have rdclass and rdtype
- # attributes, and would compare badly.
- state = {}
- for slot in self._get_all_slots():
- state[slot] = getattr(self, slot)
- return state
-
- def __setstate__(self, state):
- for slot, val in state.items():
- object.__setattr__(self, slot, val)
- if not hasattr(self, "rdcomment"):
- # Pickled rdata from 2.0.x might not have a rdcomment, so add
- # it if needed.
- object.__setattr__(self, "rdcomment", None)
-
- def covers(self) -> dns.rdatatype.RdataType:
- """Return the type a Rdata covers.
-
- DNS SIG/RRSIG rdatas apply to a specific type; this type is
- returned by the covers() function. If the rdata type is not
- SIG or RRSIG, dns.rdatatype.NONE is returned. This is useful when
- creating rdatasets, allowing the rdataset to contain only RRSIGs
- of a particular type, e.g. RRSIG(NS).
-
- Returns a ``dns.rdatatype.RdataType``.
- """
-
- return dns.rdatatype.NONE
-
- def extended_rdatatype(self) -> int:
- """Return a 32-bit type value, the least significant 16 bits of
- which are the ordinary DNS type, and the upper 16 bits of which are
- the "covered" type, if any.
-
- Returns an ``int``.
- """
-
- return self.covers() << 16 | self.rdtype
-
- def to_text(
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- **kw: Dict[str, Any],
- ) -> str:
- """Convert an rdata to text format.
-
- Returns a ``str``.
- """
-
- raise NotImplementedError # pragma: no cover
-
- def _to_wire(
- self,
- file: Optional[Any],
- compress: Optional[dns.name.CompressType] = None,
- origin: Optional[dns.name.Name] = None,
- canonicalize: bool = False,
- ) -> bytes:
- raise NotImplementedError # pragma: no cover
-
- def to_wire(
- self,
- file: Optional[Any] = None,
- compress: Optional[dns.name.CompressType] = None,
- origin: Optional[dns.name.Name] = None,
- canonicalize: bool = False,
- ) -> bytes:
- """Convert an rdata to wire format.
-
- Returns a ``bytes`` or ``None``.
- """
-
- if file:
- return self._to_wire(file, compress, origin, canonicalize)
- else:
- f = io.BytesIO()
- self._to_wire(f, compress, origin, canonicalize)
- return f.getvalue()
-
- def to_generic(
- self, origin: Optional[dns.name.Name] = None
- ) -> "dns.rdata.GenericRdata":
- """Creates a dns.rdata.GenericRdata equivalent of this rdata.
-
- Returns a ``dns.rdata.GenericRdata``.
- """
- return dns.rdata.GenericRdata(
- self.rdclass, self.rdtype, self.to_wire(origin=origin)
- )
-
- def to_digestable(self, origin: Optional[dns.name.Name] = None) -> bytes:
- """Convert rdata to a format suitable for digesting in hashes. This
- is also the DNSSEC canonical form.
-
- Returns a ``bytes``.
- """
-
- return self.to_wire(origin=origin, canonicalize=True)
-
- def __repr__(self):
- covers = self.covers()
- if covers == dns.rdatatype.NONE:
- ctext = ""
- else:
- ctext = "(" + dns.rdatatype.to_text(covers) + ")"
- return (
- ""
- )
-
- def __str__(self):
- return self.to_text()
-
- def _cmp(self, other):
- """Compare an rdata with another rdata of the same rdtype and
- rdclass.
-
- For rdata with only absolute names:
- Return < 0 if self < other in the DNSSEC ordering, 0 if self
- == other, and > 0 if self > other.
- For rdata with at least one relative names:
- The rdata sorts before any rdata with only absolute names.
- When compared with another relative rdata, all names are
- made absolute as if they were relative to the root, as the
- proper origin is not available. While this creates a stable
- ordering, it is NOT guaranteed to be the DNSSEC ordering.
- In the future, all ordering comparisons for rdata with
- relative names will be disallowed.
- """
- try:
- our = self.to_digestable()
- our_relative = False
- except dns.name.NeedAbsoluteNameOrOrigin:
- if _allow_relative_comparisons:
- our = self.to_digestable(dns.name.root)
- our_relative = True
- try:
- their = other.to_digestable()
- their_relative = False
- except dns.name.NeedAbsoluteNameOrOrigin:
- if _allow_relative_comparisons:
- their = other.to_digestable(dns.name.root)
- their_relative = True
- if _allow_relative_comparisons:
- if our_relative != their_relative:
- # For the purpose of comparison, all rdata with at least one
- # relative name is less than an rdata with only absolute names.
- if our_relative:
- return -1
- else:
- return 1
- elif our_relative or their_relative:
- raise NoRelativeRdataOrdering
- if our == their:
- return 0
- elif our > their:
- return 1
- else:
- return -1
-
- def __eq__(self, other):
- if not isinstance(other, Rdata):
- return False
- if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
- return False
- our_relative = False
- their_relative = False
- try:
- our = self.to_digestable()
- except dns.name.NeedAbsoluteNameOrOrigin:
- our = self.to_digestable(dns.name.root)
- our_relative = True
- try:
- their = other.to_digestable()
- except dns.name.NeedAbsoluteNameOrOrigin:
- their = other.to_digestable(dns.name.root)
- their_relative = True
- if our_relative != their_relative:
- return False
- return our == their
-
- def __ne__(self, other):
- if not isinstance(other, Rdata):
- return True
- if self.rdclass != other.rdclass or self.rdtype != other.rdtype:
- return True
- return not self.__eq__(other)
-
- def __lt__(self, other):
- if (
- not isinstance(other, Rdata)
- or self.rdclass != other.rdclass
- or self.rdtype != other.rdtype
- ):
- return NotImplemented
- return self._cmp(other) < 0
-
- def __le__(self, other):
- if (
- not isinstance(other, Rdata)
- or self.rdclass != other.rdclass
- or self.rdtype != other.rdtype
- ):
- return NotImplemented
- return self._cmp(other) <= 0
-
- def __ge__(self, other):
- if (
- not isinstance(other, Rdata)
- or self.rdclass != other.rdclass
- or self.rdtype != other.rdtype
- ):
- return NotImplemented
- return self._cmp(other) >= 0
-
- def __gt__(self, other):
- if (
- not isinstance(other, Rdata)
- or self.rdclass != other.rdclass
- or self.rdtype != other.rdtype
- ):
- return NotImplemented
- return self._cmp(other) > 0
-
- def __hash__(self):
- return hash(self.to_digestable(dns.name.root))
-
- @classmethod
- def from_text(
- cls,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- tok: dns.tokenizer.Tokenizer,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
- ) -> "Rdata":
- raise NotImplementedError # pragma: no cover
-
- @classmethod
- def from_wire_parser(
- cls,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- parser: dns.wire.Parser,
- origin: Optional[dns.name.Name] = None,
- ) -> "Rdata":
- raise NotImplementedError # pragma: no cover
-
- def replace(self, **kwargs: Any) -> "Rdata":
- """
- Create a new Rdata instance based on the instance replace was
- invoked on. It is possible to pass different parameters to
- override the corresponding properties of the base Rdata.
-
- Any field specific to the Rdata type can be replaced, but the
- *rdtype* and *rdclass* fields cannot.
-
- Returns an instance of the same Rdata subclass as *self*.
- """
-
- # Get the constructor parameters.
- parameters = inspect.signature(self.__init__).parameters # type: ignore
-
- # Ensure that all of the arguments correspond to valid fields.
- # Don't allow rdclass or rdtype to be changed, though.
- for key in kwargs:
- if key == "rdcomment":
- continue
- if key not in parameters:
- raise AttributeError(
- "'{}' object has no attribute '{}'".format(
- self.__class__.__name__, key
- )
- )
- if key in ("rdclass", "rdtype"):
- raise AttributeError(
- "Cannot overwrite '{}' attribute '{}'".format(
- self.__class__.__name__, key
- )
- )
-
- # Construct the parameter list. For each field, use the value in
- # kwargs if present, and the current value otherwise.
- args = (kwargs.get(key, getattr(self, key)) for key in parameters)
-
- # Create, validate, and return the new object.
- rd = self.__class__(*args)
- # The comment is not set in the constructor, so give it special
- # handling.
- rdcomment = kwargs.get("rdcomment", self.rdcomment)
- if rdcomment is not None:
- object.__setattr__(rd, "rdcomment", rdcomment)
- return rd
-
- # Type checking and conversion helpers. These are class methods as
- # they don't touch object state and may be useful to others.
-
- @classmethod
- def _as_rdataclass(cls, value):
- return dns.rdataclass.RdataClass.make(value)
-
- @classmethod
- def _as_rdatatype(cls, value):
- return dns.rdatatype.RdataType.make(value)
-
- @classmethod
- def _as_bytes(
- cls,
- value: Any,
- encode: bool = False,
- max_length: Optional[int] = None,
- empty_ok: bool = True,
- ) -> bytes:
- if encode and isinstance(value, str):
- bvalue = value.encode()
- elif isinstance(value, bytearray):
- bvalue = bytes(value)
- elif isinstance(value, bytes):
- bvalue = value
- else:
- raise ValueError("not bytes")
- if max_length is not None and len(bvalue) > max_length:
- raise ValueError("too long")
- if not empty_ok and len(bvalue) == 0:
- raise ValueError("empty bytes not allowed")
- return bvalue
-
- @classmethod
- def _as_name(cls, value):
- # Note that proper name conversion (e.g. with origin and IDNA
- # awareness) is expected to be done via from_text. This is just
- # a simple thing for people invoking the constructor directly.
- if isinstance(value, str):
- return dns.name.from_text(value)
- elif not isinstance(value, dns.name.Name):
- raise ValueError("not a name")
- return value
-
- @classmethod
- def _as_uint8(cls, value):
- if not isinstance(value, int):
- raise ValueError("not an integer")
- if value < 0 or value > 255:
- raise ValueError("not a uint8")
- return value
-
- @classmethod
- def _as_uint16(cls, value):
- if not isinstance(value, int):
- raise ValueError("not an integer")
- if value < 0 or value > 65535:
- raise ValueError("not a uint16")
- return value
-
- @classmethod
- def _as_uint32(cls, value):
- if not isinstance(value, int):
- raise ValueError("not an integer")
- if value < 0 or value > 4294967295:
- raise ValueError("not a uint32")
- return value
-
- @classmethod
- def _as_uint48(cls, value):
- if not isinstance(value, int):
- raise ValueError("not an integer")
- if value < 0 or value > 281474976710655:
- raise ValueError("not a uint48")
- return value
-
- @classmethod
- def _as_int(cls, value, low=None, high=None):
- if not isinstance(value, int):
- raise ValueError("not an integer")
- if low is not None and value < low:
- raise ValueError("value too small")
- if high is not None and value > high:
- raise ValueError("value too large")
- return value
-
- @classmethod
- def _as_ipv4_address(cls, value):
- if isinstance(value, str):
- return dns.ipv4.canonicalize(value)
- elif isinstance(value, bytes):
- return dns.ipv4.inet_ntoa(value)
- else:
- raise ValueError("not an IPv4 address")
-
- @classmethod
- def _as_ipv6_address(cls, value):
- if isinstance(value, str):
- return dns.ipv6.canonicalize(value)
- elif isinstance(value, bytes):
- return dns.ipv6.inet_ntoa(value)
- else:
- raise ValueError("not an IPv6 address")
-
- @classmethod
- def _as_bool(cls, value):
- if isinstance(value, bool):
- return value
- else:
- raise ValueError("not a boolean")
-
- @classmethod
- def _as_ttl(cls, value):
- if isinstance(value, int):
- return cls._as_int(value, 0, dns.ttl.MAX_TTL)
- elif isinstance(value, str):
- return dns.ttl.from_text(value)
- else:
- raise ValueError("not a TTL")
-
- @classmethod
- def _as_tuple(cls, value, as_value):
- try:
- # For user convenience, if value is a singleton of the list
- # element type, wrap it in a tuple.
- return (as_value(value),)
- except Exception:
- # Otherwise, check each element of the iterable *value*
- # against *as_value*.
- return tuple(as_value(v) for v in value)
-
- # Processing order
-
- @classmethod
- def _processing_order(cls, iterable):
- items = list(iterable)
- random.shuffle(items)
- return items
-
-
-@dns.immutable.immutable
-class GenericRdata(Rdata):
- """Generic Rdata Class
-
- This class is used for rdata types for which we have no better
- implementation. It implements the DNS "unknown RRs" scheme.
- """
-
- __slots__ = ["data"]
-
- def __init__(self, rdclass, rdtype, data):
- super().__init__(rdclass, rdtype)
- self.data = data
-
- def to_text(
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- **kw: Dict[str, Any],
- ) -> str:
- return r"\# %d " % len(self.data) + _hexify(self.data, **kw)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- token = tok.get()
- if not token.is_identifier() or token.value != r"\#":
- raise dns.exception.SyntaxError(r"generic rdata does not start with \#")
- length = tok.get_int()
- hex = tok.concatenate_remaining_identifiers(True).encode()
- data = binascii.unhexlify(hex)
- if len(data) != length:
- raise dns.exception.SyntaxError("generic rdata hex data has wrong length")
- return cls(rdclass, rdtype, data)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(self.data)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- return cls(rdclass, rdtype, parser.get_remaining())
-
-
-_rdata_classes: Dict[Tuple[dns.rdataclass.RdataClass, dns.rdatatype.RdataType], Any] = (
- {}
-)
-_module_prefix = "dns.rdtypes"
-
-
-def get_rdata_class(rdclass, rdtype):
- cls = _rdata_classes.get((rdclass, rdtype))
- if not cls:
- cls = _rdata_classes.get((dns.rdatatype.ANY, rdtype))
- if not cls:
- rdclass_text = dns.rdataclass.to_text(rdclass)
- rdtype_text = dns.rdatatype.to_text(rdtype)
- rdtype_text = rdtype_text.replace("-", "_")
- try:
- mod = import_module(
- ".".join([_module_prefix, rdclass_text, rdtype_text])
- )
- cls = getattr(mod, rdtype_text)
- _rdata_classes[(rdclass, rdtype)] = cls
- except ImportError:
- try:
- mod = import_module(".".join([_module_prefix, "ANY", rdtype_text]))
- cls = getattr(mod, rdtype_text)
- _rdata_classes[(dns.rdataclass.ANY, rdtype)] = cls
- _rdata_classes[(rdclass, rdtype)] = cls
- except ImportError:
- pass
- if not cls:
- cls = GenericRdata
- _rdata_classes[(rdclass, rdtype)] = cls
- return cls
-
-
-def from_text(
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- tok: Union[dns.tokenizer.Tokenizer, str],
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
- idna_codec: Optional[dns.name.IDNACodec] = None,
-) -> Rdata:
- """Build an rdata object from text format.
-
- This function attempts to dynamically load a class which
- implements the specified rdata class and type. If there is no
- class-and-type-specific implementation, the GenericRdata class
- is used.
-
- Once a class is chosen, its from_text() class method is called
- with the parameters to this function.
-
- If *tok* is a ``str``, then a tokenizer is created and the string
- is used as its input.
-
- *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype.
-
- *tok*, a ``dns.tokenizer.Tokenizer`` or a ``str``.
-
- *origin*, a ``dns.name.Name`` (or ``None``), the
- origin to use for relative names.
-
- *relativize*, a ``bool``. If true, name will be relativized.
-
- *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
- when relativizing names. If not set, the *origin* value will be used.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder to use if a tokenizer needs to be created. If
- ``None``, the default IDNA 2003 encoder/decoder is used. If a
- tokenizer is not created, then the codec associated with the tokenizer
- is the one that is used.
-
- Returns an instance of the chosen Rdata subclass.
-
- """
- if isinstance(tok, str):
- tok = dns.tokenizer.Tokenizer(tok, idna_codec=idna_codec)
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- cls = get_rdata_class(rdclass, rdtype)
- with dns.exception.ExceptionWrapper(dns.exception.SyntaxError):
- rdata = None
- if cls != GenericRdata:
- # peek at first token
- token = tok.get()
- tok.unget(token)
- if token.is_identifier() and token.value == r"\#":
- #
- # Known type using the generic syntax. Extract the
- # wire form from the generic syntax, and then run
- # from_wire on it.
- #
- grdata = GenericRdata.from_text(
- rdclass, rdtype, tok, origin, relativize, relativize_to
- )
- rdata = from_wire(
- rdclass, rdtype, grdata.data, 0, len(grdata.data), origin
- )
- #
- # If this comparison isn't equal, then there must have been
- # compressed names in the wire format, which is an error,
- # there being no reasonable context to decompress with.
- #
- rwire = rdata.to_wire()
- if rwire != grdata.data:
- raise dns.exception.SyntaxError(
- "compressed data in "
- "generic syntax form "
- "of known rdatatype"
- )
- if rdata is None:
- rdata = cls.from_text(
- rdclass, rdtype, tok, origin, relativize, relativize_to
- )
- token = tok.get_eol_as_token()
- if token.comment is not None:
- object.__setattr__(rdata, "rdcomment", token.comment)
- return rdata
-
-
-def from_wire_parser(
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- parser: dns.wire.Parser,
- origin: Optional[dns.name.Name] = None,
-) -> Rdata:
- """Build an rdata object from wire format
-
- This function attempts to dynamically load a class which
- implements the specified rdata class and type. If there is no
- class-and-type-specific implementation, the GenericRdata class
- is used.
-
- Once a class is chosen, its from_wire() class method is called
- with the parameters to this function.
-
- *rdclass*, a ``dns.rdataclass.RdataClass`` or ``str``, the rdataclass.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdatatype.
-
- *parser*, a ``dns.wire.Parser``, the parser, which should be
- restricted to the rdata length.
-
- *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``,
- then names will be relativized to this origin.
-
- Returns an instance of the chosen Rdata subclass.
- """
-
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- cls = get_rdata_class(rdclass, rdtype)
- with dns.exception.ExceptionWrapper(dns.exception.FormError):
- return cls.from_wire_parser(rdclass, rdtype, parser, origin)
-
-
-def from_wire(
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- wire: bytes,
- current: int,
- rdlen: int,
- origin: Optional[dns.name.Name] = None,
-) -> Rdata:
- """Build an rdata object from wire format
-
- This function attempts to dynamically load a class which
- implements the specified rdata class and type. If there is no
- class-and-type-specific implementation, the GenericRdata class
- is used.
-
- Once a class is chosen, its from_wire() class method is called
- with the parameters to this function.
-
- *rdclass*, an ``int``, the rdataclass.
-
- *rdtype*, an ``int``, the rdatatype.
-
- *wire*, a ``bytes``, the wire-format message.
-
- *current*, an ``int``, the offset in wire of the beginning of
- the rdata.
-
- *rdlen*, an ``int``, the length of the wire-format rdata
-
- *origin*, a ``dns.name.Name`` (or ``None``). If not ``None``,
- then names will be relativized to this origin.
-
- Returns an instance of the chosen Rdata subclass.
- """
- parser = dns.wire.Parser(wire, current)
- with parser.restrict_to(rdlen):
- return from_wire_parser(rdclass, rdtype, parser, origin)
-
-
-class RdatatypeExists(dns.exception.DNSException):
- """DNS rdatatype already exists."""
-
- supp_kwargs = {"rdclass", "rdtype"}
- fmt = (
- "The rdata type with class {rdclass:d} and rdtype {rdtype:d} "
- + "already exists."
- )
-
-
-def register_type(
- implementation: Any,
- rdtype: int,
- rdtype_text: str,
- is_singleton: bool = False,
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
-) -> None:
- """Dynamically register a module to handle an rdatatype.
-
- *implementation*, a module implementing the type in the usual dnspython
- way.
-
- *rdtype*, an ``int``, the rdatatype to register.
-
- *rdtype_text*, a ``str``, the textual form of the rdatatype.
-
- *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
- RRsets of the type can have only one member.)
-
- *rdclass*, the rdataclass of the type, or ``dns.rdataclass.ANY`` if
- it applies to all classes.
- """
-
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- existing_cls = get_rdata_class(rdclass, rdtype)
- if existing_cls != GenericRdata or dns.rdatatype.is_metatype(rdtype):
- raise RdatatypeExists(rdclass=rdclass, rdtype=rdtype)
- _rdata_classes[(rdclass, rdtype)] = getattr(
- implementation, rdtype_text.replace("-", "_")
- )
- dns.rdatatype.register_type(rdtype, rdtype_text, is_singleton)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdataclass.py b/.venv/lib/python3.12/site-packages/dns/rdataclass.py
deleted file mode 100644
index 89b85a7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdataclass.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Rdata Classes."""
-
-import dns.enum
-import dns.exception
-
-
-class RdataClass(dns.enum.IntEnum):
- """DNS Rdata Class"""
-
- RESERVED0 = 0
- IN = 1
- INTERNET = IN
- CH = 3
- CHAOS = CH
- HS = 4
- HESIOD = HS
- NONE = 254
- ANY = 255
-
- @classmethod
- def _maximum(cls):
- return 65535
-
- @classmethod
- def _short_name(cls):
- return "class"
-
- @classmethod
- def _prefix(cls):
- return "CLASS"
-
- @classmethod
- def _unknown_exception_class(cls):
- return UnknownRdataclass
-
-
-_metaclasses = {RdataClass.NONE, RdataClass.ANY}
-
-
-class UnknownRdataclass(dns.exception.DNSException):
- """A DNS class is unknown."""
-
-
-def from_text(text: str) -> RdataClass:
- """Convert text into a DNS rdata class value.
-
- The input text can be a defined DNS RR class mnemonic or
- instance of the DNS generic class syntax.
-
- For example, "IN" and "CLASS1" will both result in a value of 1.
-
- Raises ``dns.rdatatype.UnknownRdataclass`` if the class is unknown.
-
- Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535.
-
- Returns a ``dns.rdataclass.RdataClass``.
- """
-
- return RdataClass.from_text(text)
-
-
-def to_text(value: RdataClass) -> str:
- """Convert a DNS rdata class value to text.
-
- If the value has a known mnemonic, it will be used, otherwise the
- DNS generic class syntax will be used.
-
- Raises ``ValueError`` if the rdata class value is not >= 0 and <= 65535.
-
- Returns a ``str``.
- """
-
- return RdataClass.to_text(value)
-
-
-def is_metaclass(rdclass: RdataClass) -> bool:
- """True if the specified class is a metaclass.
-
- The currently defined metaclasses are ANY and NONE.
-
- *rdclass* is a ``dns.rdataclass.RdataClass``.
- """
-
- if rdclass in _metaclasses:
- return True
- return False
-
-
-### BEGIN generated RdataClass constants
-
-RESERVED0 = RdataClass.RESERVED0
-IN = RdataClass.IN
-INTERNET = RdataClass.INTERNET
-CH = RdataClass.CH
-CHAOS = RdataClass.CHAOS
-HS = RdataClass.HS
-HESIOD = RdataClass.HESIOD
-NONE = RdataClass.NONE
-ANY = RdataClass.ANY
-
-### END generated RdataClass constants
diff --git a/.venv/lib/python3.12/site-packages/dns/rdataset.py b/.venv/lib/python3.12/site-packages/dns/rdataset.py
deleted file mode 100644
index 8bff58d..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdataset.py
+++ /dev/null
@@ -1,516 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS rdatasets (an rdataset is a set of rdatas of a given type and class)"""
-
-import io
-import random
-import struct
-from typing import Any, Collection, Dict, List, Optional, Union, cast
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdataclass
-import dns.rdatatype
-import dns.renderer
-import dns.set
-import dns.ttl
-
-# define SimpleSet here for backwards compatibility
-SimpleSet = dns.set.Set
-
-
-class DifferingCovers(dns.exception.DNSException):
- """An attempt was made to add a DNS SIG/RRSIG whose covered type
- is not the same as that of the other rdatas in the rdataset."""
-
-
-class IncompatibleTypes(dns.exception.DNSException):
- """An attempt was made to add DNS RR data of an incompatible type."""
-
-
-class Rdataset(dns.set.Set):
- """A DNS rdataset."""
-
- __slots__ = ["rdclass", "rdtype", "covers", "ttl"]
-
- def __init__(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- ttl: int = 0,
- ):
- """Create a new rdataset of the specified class and type.
-
- *rdclass*, a ``dns.rdataclass.RdataClass``, the rdataclass.
-
- *rdtype*, an ``dns.rdatatype.RdataType``, the rdatatype.
-
- *covers*, an ``dns.rdatatype.RdataType``, the covered rdatatype.
-
- *ttl*, an ``int``, the TTL.
- """
-
- super().__init__()
- self.rdclass = rdclass
- self.rdtype: dns.rdatatype.RdataType = rdtype
- self.covers: dns.rdatatype.RdataType = covers
- self.ttl = ttl
-
- def _clone(self):
- obj = super()._clone()
- obj.rdclass = self.rdclass
- obj.rdtype = self.rdtype
- obj.covers = self.covers
- obj.ttl = self.ttl
- return obj
-
- def update_ttl(self, ttl: int) -> None:
- """Perform TTL minimization.
-
- Set the TTL of the rdataset to be the lesser of the set's current
- TTL or the specified TTL. If the set contains no rdatas, set the TTL
- to the specified TTL.
-
- *ttl*, an ``int`` or ``str``.
- """
- ttl = dns.ttl.make(ttl)
- if len(self) == 0:
- self.ttl = ttl
- elif ttl < self.ttl:
- self.ttl = ttl
-
- def add( # pylint: disable=arguments-differ,arguments-renamed
- self, rd: dns.rdata.Rdata, ttl: Optional[int] = None
- ) -> None:
- """Add the specified rdata to the rdataset.
-
- If the optional *ttl* parameter is supplied, then
- ``self.update_ttl(ttl)`` will be called prior to adding the rdata.
-
- *rd*, a ``dns.rdata.Rdata``, the rdata
-
- *ttl*, an ``int``, the TTL.
-
- Raises ``dns.rdataset.IncompatibleTypes`` if the type and class
- do not match the type and class of the rdataset.
-
- Raises ``dns.rdataset.DifferingCovers`` if the type is a signature
- type and the covered type does not match that of the rdataset.
- """
-
- #
- # If we're adding a signature, do some special handling to
- # check that the signature covers the same type as the
- # other rdatas in this rdataset. If this is the first rdata
- # in the set, initialize the covers field.
- #
- if self.rdclass != rd.rdclass or self.rdtype != rd.rdtype:
- raise IncompatibleTypes
- if ttl is not None:
- self.update_ttl(ttl)
- if self.rdtype == dns.rdatatype.RRSIG or self.rdtype == dns.rdatatype.SIG:
- covers = rd.covers()
- if len(self) == 0 and self.covers == dns.rdatatype.NONE:
- self.covers = covers
- elif self.covers != covers:
- raise DifferingCovers
- if dns.rdatatype.is_singleton(rd.rdtype) and len(self) > 0:
- self.clear()
- super().add(rd)
-
- def union_update(self, other):
- self.update_ttl(other.ttl)
- super().union_update(other)
-
- def intersection_update(self, other):
- self.update_ttl(other.ttl)
- super().intersection_update(other)
-
- def update(self, other):
- """Add all rdatas in other to self.
-
- *other*, a ``dns.rdataset.Rdataset``, the rdataset from which
- to update.
- """
-
- self.update_ttl(other.ttl)
- super().update(other)
-
- def _rdata_repr(self):
- def maybe_truncate(s):
- if len(s) > 100:
- return s[:100] + "..."
- return s
-
- return "[%s]" % ", ".join("<%s>" % maybe_truncate(str(rr)) for rr in self)
-
- def __repr__(self):
- if self.covers == 0:
- ctext = ""
- else:
- ctext = "(" + dns.rdatatype.to_text(self.covers) + ")"
- return (
- ""
- )
-
- def __str__(self):
- return self.to_text()
-
- def __eq__(self, other):
- if not isinstance(other, Rdataset):
- return False
- if (
- self.rdclass != other.rdclass
- or self.rdtype != other.rdtype
- or self.covers != other.covers
- ):
- return False
- return super().__eq__(other)
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def to_text(
- self,
- name: Optional[dns.name.Name] = None,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- override_rdclass: Optional[dns.rdataclass.RdataClass] = None,
- want_comments: bool = False,
- **kw: Dict[str, Any],
- ) -> str:
- """Convert the rdataset into DNS zone file format.
-
- See ``dns.name.Name.choose_relativity`` for more information
- on how *origin* and *relativize* determine the way names
- are emitted.
-
- Any additional keyword arguments are passed on to the rdata
- ``to_text()`` method.
-
- *name*, a ``dns.name.Name``. If name is not ``None``, emit RRs with
- *name* as the owner name.
-
- *origin*, a ``dns.name.Name`` or ``None``, the origin for relative
- names.
-
- *relativize*, a ``bool``. If ``True``, names will be relativized
- to *origin*.
-
- *override_rdclass*, a ``dns.rdataclass.RdataClass`` or ``None``.
- If not ``None``, use this class instead of the Rdataset's class.
-
- *want_comments*, a ``bool``. If ``True``, emit comments for rdata
- which have them. The default is ``False``.
- """
-
- if name is not None:
- name = name.choose_relativity(origin, relativize)
- ntext = str(name)
- pad = " "
- else:
- ntext = ""
- pad = ""
- s = io.StringIO()
- if override_rdclass is not None:
- rdclass = override_rdclass
- else:
- rdclass = self.rdclass
- if len(self) == 0:
- #
- # Empty rdatasets are used for the question section, and in
- # some dynamic updates, so we don't need to print out the TTL
- # (which is meaningless anyway).
- #
- s.write(
- "{}{}{} {}\n".format(
- ntext,
- pad,
- dns.rdataclass.to_text(rdclass),
- dns.rdatatype.to_text(self.rdtype),
- )
- )
- else:
- for rd in self:
- extra = ""
- if want_comments:
- if rd.rdcomment:
- extra = f" ;{rd.rdcomment}"
- s.write(
- "%s%s%d %s %s %s%s\n"
- % (
- ntext,
- pad,
- self.ttl,
- dns.rdataclass.to_text(rdclass),
- dns.rdatatype.to_text(self.rdtype),
- rd.to_text(origin=origin, relativize=relativize, **kw),
- extra,
- )
- )
- #
- # We strip off the final \n for the caller's convenience in printing
- #
- return s.getvalue()[:-1]
-
- def to_wire(
- self,
- name: dns.name.Name,
- file: Any,
- compress: Optional[dns.name.CompressType] = None,
- origin: Optional[dns.name.Name] = None,
- override_rdclass: Optional[dns.rdataclass.RdataClass] = None,
- want_shuffle: bool = True,
- ) -> int:
- """Convert the rdataset to wire format.
-
- *name*, a ``dns.name.Name`` is the owner name to use.
-
- *file* is the file where the name is emitted (typically a
- BytesIO file).
-
- *compress*, a ``dict``, is the compression table to use. If
- ``None`` (the default), names will not be compressed.
-
- *origin* is a ``dns.name.Name`` or ``None``. If the name is
- relative and origin is not ``None``, then *origin* will be appended
- to it.
-
- *override_rdclass*, an ``int``, is used as the class instead of the
- class of the rdataset. This is useful when rendering rdatasets
- associated with dynamic updates.
-
- *want_shuffle*, a ``bool``. If ``True``, then the order of the
- Rdatas within the Rdataset will be shuffled before rendering.
-
- Returns an ``int``, the number of records emitted.
- """
-
- if override_rdclass is not None:
- rdclass = override_rdclass
- want_shuffle = False
- else:
- rdclass = self.rdclass
- if len(self) == 0:
- name.to_wire(file, compress, origin)
- file.write(struct.pack("!HHIH", self.rdtype, rdclass, 0, 0))
- return 1
- else:
- l: Union[Rdataset, List[dns.rdata.Rdata]]
- if want_shuffle:
- l = list(self)
- random.shuffle(l)
- else:
- l = self
- for rd in l:
- name.to_wire(file, compress, origin)
- file.write(struct.pack("!HHI", self.rdtype, rdclass, self.ttl))
- with dns.renderer.prefixed_length(file, 2):
- rd.to_wire(file, compress, origin)
- return len(self)
-
- def match(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType,
- ) -> bool:
- """Returns ``True`` if this rdataset matches the specified class,
- type, and covers.
- """
- if self.rdclass == rdclass and self.rdtype == rdtype and self.covers == covers:
- return True
- return False
-
- def processing_order(self) -> List[dns.rdata.Rdata]:
- """Return rdatas in a valid processing order according to the type's
- specification. For example, MX records are in preference order from
- lowest to highest preferences, with items of the same preference
- shuffled.
-
- For types that do not define a processing order, the rdatas are
- simply shuffled.
- """
- if len(self) == 0:
- return []
- else:
- return self[0]._processing_order(iter(self))
-
-
-@dns.immutable.immutable
-class ImmutableRdataset(Rdataset): # lgtm[py/missing-equals]
- """An immutable DNS rdataset."""
-
- _clone_class = Rdataset
-
- def __init__(self, rdataset: Rdataset):
- """Create an immutable rdataset from the specified rdataset."""
-
- super().__init__(
- rdataset.rdclass, rdataset.rdtype, rdataset.covers, rdataset.ttl
- )
- self.items = dns.immutable.Dict(rdataset.items)
-
- def update_ttl(self, ttl):
- raise TypeError("immutable")
-
- def add(self, rd, ttl=None):
- raise TypeError("immutable")
-
- def union_update(self, other):
- raise TypeError("immutable")
-
- def intersection_update(self, other):
- raise TypeError("immutable")
-
- def update(self, other):
- raise TypeError("immutable")
-
- def __delitem__(self, i):
- raise TypeError("immutable")
-
- # lgtm complains about these not raising ArithmeticError, but there is
- # precedent for overrides of these methods in other classes to raise
- # TypeError, and it seems like the better exception.
-
- def __ior__(self, other): # lgtm[py/unexpected-raise-in-special-method]
- raise TypeError("immutable")
-
- def __iand__(self, other): # lgtm[py/unexpected-raise-in-special-method]
- raise TypeError("immutable")
-
- def __iadd__(self, other): # lgtm[py/unexpected-raise-in-special-method]
- raise TypeError("immutable")
-
- def __isub__(self, other): # lgtm[py/unexpected-raise-in-special-method]
- raise TypeError("immutable")
-
- def clear(self):
- raise TypeError("immutable")
-
- def __copy__(self):
- return ImmutableRdataset(super().copy())
-
- def copy(self):
- return ImmutableRdataset(super().copy())
-
- def union(self, other):
- return ImmutableRdataset(super().union(other))
-
- def intersection(self, other):
- return ImmutableRdataset(super().intersection(other))
-
- def difference(self, other):
- return ImmutableRdataset(super().difference(other))
-
- def symmetric_difference(self, other):
- return ImmutableRdataset(super().symmetric_difference(other))
-
-
-def from_text_list(
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- ttl: int,
- text_rdatas: Collection[str],
- idna_codec: Optional[dns.name.IDNACodec] = None,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
-) -> Rdataset:
- """Create an rdataset with the specified class, type, and TTL, and with
- the specified list of rdatas in text format.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder to use; if ``None``, the default IDNA 2003
- encoder/decoder is used.
-
- *origin*, a ``dns.name.Name`` (or ``None``), the
- origin to use for relative names.
-
- *relativize*, a ``bool``. If true, name will be relativized.
-
- *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
- when relativizing names. If not set, the *origin* value will be used.
-
- Returns a ``dns.rdataset.Rdataset`` object.
- """
-
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- r = Rdataset(rdclass, rdtype)
- r.update_ttl(ttl)
- for t in text_rdatas:
- rd = dns.rdata.from_text(
- r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec
- )
- r.add(rd)
- return r
-
-
-def from_text(
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- ttl: int,
- *text_rdatas: Any,
-) -> Rdataset:
- """Create an rdataset with the specified class, type, and TTL, and with
- the specified rdatas in text format.
-
- Returns a ``dns.rdataset.Rdataset`` object.
- """
-
- return from_text_list(rdclass, rdtype, ttl, cast(Collection[str], text_rdatas))
-
-
-def from_rdata_list(ttl: int, rdatas: Collection[dns.rdata.Rdata]) -> Rdataset:
- """Create an rdataset with the specified TTL, and with
- the specified list of rdata objects.
-
- Returns a ``dns.rdataset.Rdataset`` object.
- """
-
- if len(rdatas) == 0:
- raise ValueError("rdata list must not be empty")
- r = None
- for rd in rdatas:
- if r is None:
- r = Rdataset(rd.rdclass, rd.rdtype)
- r.update_ttl(ttl)
- r.add(rd)
- assert r is not None
- return r
-
-
-def from_rdata(ttl: int, *rdatas: Any) -> Rdataset:
- """Create an rdataset with the specified TTL, and with
- the specified rdata objects.
-
- Returns a ``dns.rdataset.Rdataset`` object.
- """
-
- return from_rdata_list(ttl, cast(Collection[dns.rdata.Rdata], rdatas))
diff --git a/.venv/lib/python3.12/site-packages/dns/rdatatype.py b/.venv/lib/python3.12/site-packages/dns/rdatatype.py
deleted file mode 100644
index e6c5818..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdatatype.py
+++ /dev/null
@@ -1,332 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Rdata Types."""
-
-from typing import Dict
-
-import dns.enum
-import dns.exception
-
-
-class RdataType(dns.enum.IntEnum):
- """DNS Rdata Type"""
-
- TYPE0 = 0
- NONE = 0
- A = 1
- NS = 2
- MD = 3
- MF = 4
- CNAME = 5
- SOA = 6
- MB = 7
- MG = 8
- MR = 9
- NULL = 10
- WKS = 11
- PTR = 12
- HINFO = 13
- MINFO = 14
- MX = 15
- TXT = 16
- RP = 17
- AFSDB = 18
- X25 = 19
- ISDN = 20
- RT = 21
- NSAP = 22
- NSAP_PTR = 23
- SIG = 24
- KEY = 25
- PX = 26
- GPOS = 27
- AAAA = 28
- LOC = 29
- NXT = 30
- SRV = 33
- NAPTR = 35
- KX = 36
- CERT = 37
- A6 = 38
- DNAME = 39
- OPT = 41
- APL = 42
- DS = 43
- SSHFP = 44
- IPSECKEY = 45
- RRSIG = 46
- NSEC = 47
- DNSKEY = 48
- DHCID = 49
- NSEC3 = 50
- NSEC3PARAM = 51
- TLSA = 52
- SMIMEA = 53
- HIP = 55
- NINFO = 56
- CDS = 59
- CDNSKEY = 60
- OPENPGPKEY = 61
- CSYNC = 62
- ZONEMD = 63
- SVCB = 64
- HTTPS = 65
- SPF = 99
- UNSPEC = 103
- NID = 104
- L32 = 105
- L64 = 106
- LP = 107
- EUI48 = 108
- EUI64 = 109
- TKEY = 249
- TSIG = 250
- IXFR = 251
- AXFR = 252
- MAILB = 253
- MAILA = 254
- ANY = 255
- URI = 256
- CAA = 257
- AVC = 258
- AMTRELAY = 260
- TA = 32768
- DLV = 32769
-
- @classmethod
- def _maximum(cls):
- return 65535
-
- @classmethod
- def _short_name(cls):
- return "type"
-
- @classmethod
- def _prefix(cls):
- return "TYPE"
-
- @classmethod
- def _extra_from_text(cls, text):
- if text.find("-") >= 0:
- try:
- return cls[text.replace("-", "_")]
- except KeyError:
- pass
- return _registered_by_text.get(text)
-
- @classmethod
- def _extra_to_text(cls, value, current_text):
- if current_text is None:
- return _registered_by_value.get(value)
- if current_text.find("_") >= 0:
- return current_text.replace("_", "-")
- return current_text
-
- @classmethod
- def _unknown_exception_class(cls):
- return UnknownRdatatype
-
-
-_registered_by_text: Dict[str, RdataType] = {}
-_registered_by_value: Dict[RdataType, str] = {}
-
-_metatypes = {RdataType.OPT}
-
-_singletons = {
- RdataType.SOA,
- RdataType.NXT,
- RdataType.DNAME,
- RdataType.NSEC,
- RdataType.CNAME,
-}
-
-
-class UnknownRdatatype(dns.exception.DNSException):
- """DNS resource record type is unknown."""
-
-
-def from_text(text: str) -> RdataType:
- """Convert text into a DNS rdata type value.
-
- The input text can be a defined DNS RR type mnemonic or
- instance of the DNS generic type syntax.
-
- For example, "NS" and "TYPE2" will both result in a value of 2.
-
- Raises ``dns.rdatatype.UnknownRdatatype`` if the type is unknown.
-
- Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535.
-
- Returns a ``dns.rdatatype.RdataType``.
- """
-
- return RdataType.from_text(text)
-
-
-def to_text(value: RdataType) -> str:
- """Convert a DNS rdata type value to text.
-
- If the value has a known mnemonic, it will be used, otherwise the
- DNS generic type syntax will be used.
-
- Raises ``ValueError`` if the rdata type value is not >= 0 and <= 65535.
-
- Returns a ``str``.
- """
-
- return RdataType.to_text(value)
-
-
-def is_metatype(rdtype: RdataType) -> bool:
- """True if the specified type is a metatype.
-
- *rdtype* is a ``dns.rdatatype.RdataType``.
-
- The currently defined metatypes are TKEY, TSIG, IXFR, AXFR, MAILA,
- MAILB, ANY, and OPT.
-
- Returns a ``bool``.
- """
-
- return (256 > rdtype >= 128) or rdtype in _metatypes
-
-
-def is_singleton(rdtype: RdataType) -> bool:
- """Is the specified type a singleton type?
-
- Singleton types can only have a single rdata in an rdataset, or a single
- RR in an RRset.
-
- The currently defined singleton types are CNAME, DNAME, NSEC, NXT, and
- SOA.
-
- *rdtype* is an ``int``.
-
- Returns a ``bool``.
- """
-
- if rdtype in _singletons:
- return True
- return False
-
-
-# pylint: disable=redefined-outer-name
-def register_type(
- rdtype: RdataType, rdtype_text: str, is_singleton: bool = False
-) -> None:
- """Dynamically register an rdatatype.
-
- *rdtype*, a ``dns.rdatatype.RdataType``, the rdatatype to register.
-
- *rdtype_text*, a ``str``, the textual form of the rdatatype.
-
- *is_singleton*, a ``bool``, indicating if the type is a singleton (i.e.
- RRsets of the type can have only one member.)
- """
-
- _registered_by_text[rdtype_text] = rdtype
- _registered_by_value[rdtype] = rdtype_text
- if is_singleton:
- _singletons.add(rdtype)
-
-
-### BEGIN generated RdataType constants
-
-TYPE0 = RdataType.TYPE0
-NONE = RdataType.NONE
-A = RdataType.A
-NS = RdataType.NS
-MD = RdataType.MD
-MF = RdataType.MF
-CNAME = RdataType.CNAME
-SOA = RdataType.SOA
-MB = RdataType.MB
-MG = RdataType.MG
-MR = RdataType.MR
-NULL = RdataType.NULL
-WKS = RdataType.WKS
-PTR = RdataType.PTR
-HINFO = RdataType.HINFO
-MINFO = RdataType.MINFO
-MX = RdataType.MX
-TXT = RdataType.TXT
-RP = RdataType.RP
-AFSDB = RdataType.AFSDB
-X25 = RdataType.X25
-ISDN = RdataType.ISDN
-RT = RdataType.RT
-NSAP = RdataType.NSAP
-NSAP_PTR = RdataType.NSAP_PTR
-SIG = RdataType.SIG
-KEY = RdataType.KEY
-PX = RdataType.PX
-GPOS = RdataType.GPOS
-AAAA = RdataType.AAAA
-LOC = RdataType.LOC
-NXT = RdataType.NXT
-SRV = RdataType.SRV
-NAPTR = RdataType.NAPTR
-KX = RdataType.KX
-CERT = RdataType.CERT
-A6 = RdataType.A6
-DNAME = RdataType.DNAME
-OPT = RdataType.OPT
-APL = RdataType.APL
-DS = RdataType.DS
-SSHFP = RdataType.SSHFP
-IPSECKEY = RdataType.IPSECKEY
-RRSIG = RdataType.RRSIG
-NSEC = RdataType.NSEC
-DNSKEY = RdataType.DNSKEY
-DHCID = RdataType.DHCID
-NSEC3 = RdataType.NSEC3
-NSEC3PARAM = RdataType.NSEC3PARAM
-TLSA = RdataType.TLSA
-SMIMEA = RdataType.SMIMEA
-HIP = RdataType.HIP
-NINFO = RdataType.NINFO
-CDS = RdataType.CDS
-CDNSKEY = RdataType.CDNSKEY
-OPENPGPKEY = RdataType.OPENPGPKEY
-CSYNC = RdataType.CSYNC
-ZONEMD = RdataType.ZONEMD
-SVCB = RdataType.SVCB
-HTTPS = RdataType.HTTPS
-SPF = RdataType.SPF
-UNSPEC = RdataType.UNSPEC
-NID = RdataType.NID
-L32 = RdataType.L32
-L64 = RdataType.L64
-LP = RdataType.LP
-EUI48 = RdataType.EUI48
-EUI64 = RdataType.EUI64
-TKEY = RdataType.TKEY
-TSIG = RdataType.TSIG
-IXFR = RdataType.IXFR
-AXFR = RdataType.AXFR
-MAILB = RdataType.MAILB
-MAILA = RdataType.MAILA
-ANY = RdataType.ANY
-URI = RdataType.URI
-CAA = RdataType.CAA
-AVC = RdataType.AVC
-AMTRELAY = RdataType.AMTRELAY
-TA = RdataType.TA
-DLV = RdataType.DLV
-
-### END generated RdataType constants
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AFSDB.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AFSDB.py
deleted file mode 100644
index 06a3b97..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AFSDB.py
+++ /dev/null
@@ -1,45 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.mxbase
-
-
-@dns.immutable.immutable
-class AFSDB(dns.rdtypes.mxbase.UncompressedDowncasingMX):
- """AFSDB record"""
-
- # Use the property mechanism to make "subtype" an alias for the
- # "preference" attribute, and "hostname" an alias for the "exchange"
- # attribute.
- #
- # This lets us inherit the UncompressedMX implementation but lets
- # the caller use appropriate attribute names for the rdata type.
- #
- # We probably lose some performance vs. a cut-and-paste
- # implementation, but this way we don't copy code, and that's
- # good.
-
- @property
- def subtype(self):
- "the AFSDB subtype"
- return self.preference
-
- @property
- def hostname(self):
- "the AFSDB hostname"
- return self.exchange
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AMTRELAY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AMTRELAY.py
deleted file mode 100644
index ed2b072..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AMTRELAY.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdtypes.util
-
-
-class Relay(dns.rdtypes.util.Gateway):
- name = "AMTRELAY relay"
-
- @property
- def relay(self):
- return self.gateway
-
-
-@dns.immutable.immutable
-class AMTRELAY(dns.rdata.Rdata):
- """AMTRELAY record"""
-
- # see: RFC 8777
-
- __slots__ = ["precedence", "discovery_optional", "relay_type", "relay"]
-
- def __init__(
- self, rdclass, rdtype, precedence, discovery_optional, relay_type, relay
- ):
- super().__init__(rdclass, rdtype)
- relay = Relay(relay_type, relay)
- self.precedence = self._as_uint8(precedence)
- self.discovery_optional = self._as_bool(discovery_optional)
- self.relay_type = relay.type
- self.relay = relay.relay
-
- def to_text(self, origin=None, relativize=True, **kw):
- relay = Relay(self.relay_type, self.relay).to_text(origin, relativize)
- return "%d %d %d %s" % (
- self.precedence,
- self.discovery_optional,
- self.relay_type,
- relay,
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- precedence = tok.get_uint8()
- discovery_optional = tok.get_uint8()
- if discovery_optional > 1:
- raise dns.exception.SyntaxError("expecting 0 or 1")
- discovery_optional = bool(discovery_optional)
- relay_type = tok.get_uint8()
- if relay_type > 0x7F:
- raise dns.exception.SyntaxError("expecting an integer <= 127")
- relay = Relay.from_text(relay_type, tok, origin, relativize, relativize_to)
- return cls(
- rdclass, rdtype, precedence, discovery_optional, relay_type, relay.relay
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- relay_type = self.relay_type | (self.discovery_optional << 7)
- header = struct.pack("!BB", self.precedence, relay_type)
- file.write(header)
- Relay(self.relay_type, self.relay).to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (precedence, relay_type) = parser.get_struct("!BB")
- discovery_optional = bool(relay_type >> 7)
- relay_type &= 0x7F
- relay = Relay.from_wire_parser(relay_type, parser, origin)
- return cls(
- rdclass, rdtype, precedence, discovery_optional, relay_type, relay.relay
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AVC.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AVC.py
deleted file mode 100644
index a27ae2d..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/AVC.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2016 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.txtbase
-
-
-@dns.immutable.immutable
-class AVC(dns.rdtypes.txtbase.TXTBase):
- """AVC record"""
-
- # See: IANA dns parameters for AVC
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CAA.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CAA.py
deleted file mode 100644
index 2e6a7e7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CAA.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class CAA(dns.rdata.Rdata):
- """CAA (Certification Authority Authorization) record"""
-
- # see: RFC 6844
-
- __slots__ = ["flags", "tag", "value"]
-
- def __init__(self, rdclass, rdtype, flags, tag, value):
- super().__init__(rdclass, rdtype)
- self.flags = self._as_uint8(flags)
- self.tag = self._as_bytes(tag, True, 255)
- if not tag.isalnum():
- raise ValueError("tag is not alphanumeric")
- self.value = self._as_bytes(value)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return '%u %s "%s"' % (
- self.flags,
- dns.rdata._escapify(self.tag),
- dns.rdata._escapify(self.value),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- flags = tok.get_uint8()
- tag = tok.get_string().encode()
- value = tok.get_string().encode()
- return cls(rdclass, rdtype, flags, tag, value)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!B", self.flags))
- l = len(self.tag)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.tag)
- file.write(self.value)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- flags = parser.get_uint8()
- tag = parser.get_counted_bytes()
- value = parser.get_remaining()
- return cls(rdclass, rdtype, flags, tag, value)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDNSKEY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDNSKEY.py
deleted file mode 100644
index b613409..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDNSKEY.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.dnskeybase # lgtm[py/import-and-import-from]
-
-# pylint: disable=unused-import
-from dns.rdtypes.dnskeybase import ( # noqa: F401 lgtm[py/unused-import]
- REVOKE,
- SEP,
- ZONE,
-)
-
-# pylint: enable=unused-import
-
-
-@dns.immutable.immutable
-class CDNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase):
- """CDNSKEY record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDS.py
deleted file mode 100644
index 8312b97..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CDS.py
+++ /dev/null
@@ -1,29 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.dsbase
-
-
-@dns.immutable.immutable
-class CDS(dns.rdtypes.dsbase.DSBase):
- """CDS record"""
-
- _digest_length_by_type = {
- **dns.rdtypes.dsbase.DSBase._digest_length_by_type,
- 0: 1, # delete, RFC 8078 Sec. 4 (including Errata ID 5049)
- }
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CERT.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CERT.py
deleted file mode 100644
index f369cc8..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CERT.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import struct
-
-import dns.dnssectypes
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-_ctype_by_value = {
- 1: "PKIX",
- 2: "SPKI",
- 3: "PGP",
- 4: "IPKIX",
- 5: "ISPKI",
- 6: "IPGP",
- 7: "ACPKIX",
- 8: "IACPKIX",
- 253: "URI",
- 254: "OID",
-}
-
-_ctype_by_name = {
- "PKIX": 1,
- "SPKI": 2,
- "PGP": 3,
- "IPKIX": 4,
- "ISPKI": 5,
- "IPGP": 6,
- "ACPKIX": 7,
- "IACPKIX": 8,
- "URI": 253,
- "OID": 254,
-}
-
-
-def _ctype_from_text(what):
- v = _ctype_by_name.get(what)
- if v is not None:
- return v
- return int(what)
-
-
-def _ctype_to_text(what):
- v = _ctype_by_value.get(what)
- if v is not None:
- return v
- return str(what)
-
-
-@dns.immutable.immutable
-class CERT(dns.rdata.Rdata):
- """CERT record"""
-
- # see RFC 4398
-
- __slots__ = ["certificate_type", "key_tag", "algorithm", "certificate"]
-
- def __init__(
- self, rdclass, rdtype, certificate_type, key_tag, algorithm, certificate
- ):
- super().__init__(rdclass, rdtype)
- self.certificate_type = self._as_uint16(certificate_type)
- self.key_tag = self._as_uint16(key_tag)
- self.algorithm = self._as_uint8(algorithm)
- self.certificate = self._as_bytes(certificate)
-
- def to_text(self, origin=None, relativize=True, **kw):
- certificate_type = _ctype_to_text(self.certificate_type)
- return "%s %d %s %s" % (
- certificate_type,
- self.key_tag,
- dns.dnssectypes.Algorithm.to_text(self.algorithm),
- dns.rdata._base64ify(self.certificate, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- certificate_type = _ctype_from_text(tok.get_string())
- key_tag = tok.get_uint16()
- algorithm = dns.dnssectypes.Algorithm.from_text(tok.get_string())
- b64 = tok.concatenate_remaining_identifiers().encode()
- certificate = base64.b64decode(b64)
- return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- prefix = struct.pack(
- "!HHB", self.certificate_type, self.key_tag, self.algorithm
- )
- file.write(prefix)
- file.write(self.certificate)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (certificate_type, key_tag, algorithm) = parser.get_struct("!HHB")
- certificate = parser.get_remaining()
- return cls(rdclass, rdtype, certificate_type, key_tag, algorithm, certificate)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CNAME.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CNAME.py
deleted file mode 100644
index 665e407..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CNAME.py
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.nsbase
-
-
-@dns.immutable.immutable
-class CNAME(dns.rdtypes.nsbase.NSBase):
- """CNAME record
-
- Note: although CNAME is officially a singleton type, dnspython allows
- non-singleton CNAME rdatasets because such sets have been commonly
- used by BIND and other nameservers for load balancing."""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CSYNC.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CSYNC.py
deleted file mode 100644
index 2f972f6..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/CSYNC.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011, 2016 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdatatype
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class Bitmap(dns.rdtypes.util.Bitmap):
- type_name = "CSYNC"
-
-
-@dns.immutable.immutable
-class CSYNC(dns.rdata.Rdata):
- """CSYNC record"""
-
- __slots__ = ["serial", "flags", "windows"]
-
- def __init__(self, rdclass, rdtype, serial, flags, windows):
- super().__init__(rdclass, rdtype)
- self.serial = self._as_uint32(serial)
- self.flags = self._as_uint16(flags)
- if not isinstance(windows, Bitmap):
- windows = Bitmap(windows)
- self.windows = tuple(windows.windows)
-
- def to_text(self, origin=None, relativize=True, **kw):
- text = Bitmap(self.windows).to_text()
- return "%d %d%s" % (self.serial, self.flags, text)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- serial = tok.get_uint32()
- flags = tok.get_uint16()
- bitmap = Bitmap.from_text(tok)
- return cls(rdclass, rdtype, serial, flags, bitmap)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!IH", self.serial, self.flags))
- Bitmap(self.windows).to_wire(file)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (serial, flags) = parser.get_struct("!IH")
- bitmap = Bitmap.from_wire_parser(parser)
- return cls(rdclass, rdtype, serial, flags, bitmap)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DLV.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DLV.py
deleted file mode 100644
index 6c134f1..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DLV.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.dsbase
-
-
-@dns.immutable.immutable
-class DLV(dns.rdtypes.dsbase.DSBase):
- """DLV record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNAME.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNAME.py
deleted file mode 100644
index bbf9186..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNAME.py
+++ /dev/null
@@ -1,27 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.nsbase
-
-
-@dns.immutable.immutable
-class DNAME(dns.rdtypes.nsbase.UncompressedNS):
- """DNAME record"""
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.target.to_wire(file, None, origin, canonicalize)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNSKEY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNSKEY.py
deleted file mode 100644
index 6d961a9..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DNSKEY.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.dnskeybase # lgtm[py/import-and-import-from]
-
-# pylint: disable=unused-import
-from dns.rdtypes.dnskeybase import ( # noqa: F401 lgtm[py/unused-import]
- REVOKE,
- SEP,
- ZONE,
-)
-
-# pylint: enable=unused-import
-
-
-@dns.immutable.immutable
-class DNSKEY(dns.rdtypes.dnskeybase.DNSKEYBase):
- """DNSKEY record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DS.py
deleted file mode 100644
index 58b3108..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/DS.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.dsbase
-
-
-@dns.immutable.immutable
-class DS(dns.rdtypes.dsbase.DSBase):
- """DS record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI48.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI48.py
deleted file mode 100644
index c843be5..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI48.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2015 Red Hat, Inc.
-# Author: Petr Spacek
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.euibase
-
-
-@dns.immutable.immutable
-class EUI48(dns.rdtypes.euibase.EUIBase):
- """EUI48 record"""
-
- # see: rfc7043.txt
-
- byte_len = 6 # 0123456789ab (in hex)
- text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI64.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI64.py
deleted file mode 100644
index f6d7e25..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/EUI64.py
+++ /dev/null
@@ -1,30 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2015 Red Hat, Inc.
-# Author: Petr Spacek
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.euibase
-
-
-@dns.immutable.immutable
-class EUI64(dns.rdtypes.euibase.EUIBase):
- """EUI64 record"""
-
- # see: rfc7043.txt
-
- byte_len = 8 # 0123456789abcdef (in hex)
- text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab-cd-ef
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/GPOS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/GPOS.py
deleted file mode 100644
index 312338f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/GPOS.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-def _validate_float_string(what):
- if len(what) == 0:
- raise dns.exception.FormError
- if what[0] == b"-"[0] or what[0] == b"+"[0]:
- what = what[1:]
- if what.isdigit():
- return
- try:
- (left, right) = what.split(b".")
- except ValueError:
- raise dns.exception.FormError
- if left == b"" and right == b"":
- raise dns.exception.FormError
- if not left == b"" and not left.decode().isdigit():
- raise dns.exception.FormError
- if not right == b"" and not right.decode().isdigit():
- raise dns.exception.FormError
-
-
-@dns.immutable.immutable
-class GPOS(dns.rdata.Rdata):
- """GPOS record"""
-
- # see: RFC 1712
-
- __slots__ = ["latitude", "longitude", "altitude"]
-
- def __init__(self, rdclass, rdtype, latitude, longitude, altitude):
- super().__init__(rdclass, rdtype)
- if isinstance(latitude, float) or isinstance(latitude, int):
- latitude = str(latitude)
- if isinstance(longitude, float) or isinstance(longitude, int):
- longitude = str(longitude)
- if isinstance(altitude, float) or isinstance(altitude, int):
- altitude = str(altitude)
- latitude = self._as_bytes(latitude, True, 255)
- longitude = self._as_bytes(longitude, True, 255)
- altitude = self._as_bytes(altitude, True, 255)
- _validate_float_string(latitude)
- _validate_float_string(longitude)
- _validate_float_string(altitude)
- self.latitude = latitude
- self.longitude = longitude
- self.altitude = altitude
- flat = self.float_latitude
- if flat < -90.0 or flat > 90.0:
- raise dns.exception.FormError("bad latitude")
- flong = self.float_longitude
- if flong < -180.0 or flong > 180.0:
- raise dns.exception.FormError("bad longitude")
-
- def to_text(self, origin=None, relativize=True, **kw):
- return "{} {} {}".format(
- self.latitude.decode(), self.longitude.decode(), self.altitude.decode()
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- latitude = tok.get_string()
- longitude = tok.get_string()
- altitude = tok.get_string()
- return cls(rdclass, rdtype, latitude, longitude, altitude)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.latitude)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.latitude)
- l = len(self.longitude)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.longitude)
- l = len(self.altitude)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.altitude)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- latitude = parser.get_counted_bytes()
- longitude = parser.get_counted_bytes()
- altitude = parser.get_counted_bytes()
- return cls(rdclass, rdtype, latitude, longitude, altitude)
-
- @property
- def float_latitude(self):
- "latitude as a floating point value"
- return float(self.latitude)
-
- @property
- def float_longitude(self):
- "longitude as a floating point value"
- return float(self.longitude)
-
- @property
- def float_altitude(self):
- "altitude as a floating point value"
- return float(self.altitude)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HINFO.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HINFO.py
deleted file mode 100644
index c2c45de..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HINFO.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class HINFO(dns.rdata.Rdata):
- """HINFO record"""
-
- # see: RFC 1035
-
- __slots__ = ["cpu", "os"]
-
- def __init__(self, rdclass, rdtype, cpu, os):
- super().__init__(rdclass, rdtype)
- self.cpu = self._as_bytes(cpu, True, 255)
- self.os = self._as_bytes(os, True, 255)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return '"{}" "{}"'.format(
- dns.rdata._escapify(self.cpu), dns.rdata._escapify(self.os)
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- cpu = tok.get_string(max_length=255)
- os = tok.get_string(max_length=255)
- return cls(rdclass, rdtype, cpu, os)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.cpu)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.cpu)
- l = len(self.os)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.os)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- cpu = parser.get_counted_bytes()
- os = parser.get_counted_bytes()
- return cls(rdclass, rdtype, cpu, os)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HIP.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HIP.py
deleted file mode 100644
index 9166913..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/HIP.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2010, 2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import binascii
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-
-
-@dns.immutable.immutable
-class HIP(dns.rdata.Rdata):
- """HIP record"""
-
- # see: RFC 5205
-
- __slots__ = ["hit", "algorithm", "key", "servers"]
-
- def __init__(self, rdclass, rdtype, hit, algorithm, key, servers):
- super().__init__(rdclass, rdtype)
- self.hit = self._as_bytes(hit, True, 255)
- self.algorithm = self._as_uint8(algorithm)
- self.key = self._as_bytes(key, True)
- self.servers = self._as_tuple(servers, self._as_name)
-
- def to_text(self, origin=None, relativize=True, **kw):
- hit = binascii.hexlify(self.hit).decode()
- key = base64.b64encode(self.key).replace(b"\n", b"").decode()
- text = ""
- servers = []
- for server in self.servers:
- servers.append(server.choose_relativity(origin, relativize))
- if len(servers) > 0:
- text += " " + " ".join((x.to_unicode() for x in servers))
- return "%u %s %s%s" % (self.algorithm, hit, key, text)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_uint8()
- hit = binascii.unhexlify(tok.get_string().encode())
- key = base64.b64decode(tok.get_string().encode())
- servers = []
- for token in tok.get_remaining():
- server = tok.as_name(token, origin, relativize, relativize_to)
- servers.append(server)
- return cls(rdclass, rdtype, hit, algorithm, key, servers)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- lh = len(self.hit)
- lk = len(self.key)
- file.write(struct.pack("!BBH", lh, self.algorithm, lk))
- file.write(self.hit)
- file.write(self.key)
- for server in self.servers:
- server.to_wire(file, None, origin, False)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (lh, algorithm, lk) = parser.get_struct("!BBH")
- hit = parser.get_bytes(lh)
- key = parser.get_bytes(lk)
- servers = []
- while parser.remaining() > 0:
- server = parser.get_name(origin)
- servers.append(server)
- return cls(rdclass, rdtype, hit, algorithm, key, servers)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ISDN.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ISDN.py
deleted file mode 100644
index fb01eab..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ISDN.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class ISDN(dns.rdata.Rdata):
- """ISDN record"""
-
- # see: RFC 1183
-
- __slots__ = ["address", "subaddress"]
-
- def __init__(self, rdclass, rdtype, address, subaddress):
- super().__init__(rdclass, rdtype)
- self.address = self._as_bytes(address, True, 255)
- self.subaddress = self._as_bytes(subaddress, True, 255)
-
- def to_text(self, origin=None, relativize=True, **kw):
- if self.subaddress:
- return '"{}" "{}"'.format(
- dns.rdata._escapify(self.address), dns.rdata._escapify(self.subaddress)
- )
- else:
- return '"%s"' % dns.rdata._escapify(self.address)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_string()
- tokens = tok.get_remaining(max_tokens=1)
- if len(tokens) >= 1:
- subaddress = tokens[0].unescape().value
- else:
- subaddress = ""
- return cls(rdclass, rdtype, address, subaddress)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.address)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.address)
- l = len(self.subaddress)
- if l > 0:
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.subaddress)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_counted_bytes()
- if parser.remaining() > 0:
- subaddress = parser.get_counted_bytes()
- else:
- subaddress = b""
- return cls(rdclass, rdtype, address, subaddress)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L32.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L32.py
deleted file mode 100644
index 09804c2..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L32.py
+++ /dev/null
@@ -1,41 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import struct
-
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class L32(dns.rdata.Rdata):
- """L32 record"""
-
- # see: rfc6742.txt
-
- __slots__ = ["preference", "locator32"]
-
- def __init__(self, rdclass, rdtype, preference, locator32):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- self.locator32 = self._as_ipv4_address(locator32)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return f"{self.preference} {self.locator32}"
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- nodeid = tok.get_identifier()
- return cls(rdclass, rdtype, preference, nodeid)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!H", self.preference))
- file.write(dns.ipv4.inet_aton(self.locator32))
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- locator32 = parser.get_remaining()
- return cls(rdclass, rdtype, preference, locator32)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L64.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L64.py
deleted file mode 100644
index fb76808..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/L64.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import struct
-
-import dns.immutable
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class L64(dns.rdata.Rdata):
- """L64 record"""
-
- # see: rfc6742.txt
-
- __slots__ = ["preference", "locator64"]
-
- def __init__(self, rdclass, rdtype, preference, locator64):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- if isinstance(locator64, bytes):
- if len(locator64) != 8:
- raise ValueError("invalid locator64")
- self.locator64 = dns.rdata._hexify(locator64, 4, b":")
- else:
- dns.rdtypes.util.parse_formatted_hex(locator64, 4, 4, ":")
- self.locator64 = locator64
-
- def to_text(self, origin=None, relativize=True, **kw):
- return f"{self.preference} {self.locator64}"
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- locator64 = tok.get_identifier()
- return cls(rdclass, rdtype, preference, locator64)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!H", self.preference))
- file.write(dns.rdtypes.util.parse_formatted_hex(self.locator64, 4, 4, ":"))
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- locator64 = parser.get_remaining()
- return cls(rdclass, rdtype, preference, locator64)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LOC.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LOC.py
deleted file mode 100644
index a36a2c1..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LOC.py
+++ /dev/null
@@ -1,354 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-_pows = tuple(10**i for i in range(0, 11))
-
-# default values are in centimeters
-_default_size = 100.0
-_default_hprec = 1000000.0
-_default_vprec = 1000.0
-
-# for use by from_wire()
-_MAX_LATITUDE = 0x80000000 + 90 * 3600000
-_MIN_LATITUDE = 0x80000000 - 90 * 3600000
-_MAX_LONGITUDE = 0x80000000 + 180 * 3600000
-_MIN_LONGITUDE = 0x80000000 - 180 * 3600000
-
-
-def _exponent_of(what, desc):
- if what == 0:
- return 0
- exp = None
- for i, pow in enumerate(_pows):
- if what < pow:
- exp = i - 1
- break
- if exp is None or exp < 0:
- raise dns.exception.SyntaxError("%s value out of bounds" % desc)
- return exp
-
-
-def _float_to_tuple(what):
- if what < 0:
- sign = -1
- what *= -1
- else:
- sign = 1
- what = round(what * 3600000)
- degrees = int(what // 3600000)
- what -= degrees * 3600000
- minutes = int(what // 60000)
- what -= minutes * 60000
- seconds = int(what // 1000)
- what -= int(seconds * 1000)
- what = int(what)
- return (degrees, minutes, seconds, what, sign)
-
-
-def _tuple_to_float(what):
- value = float(what[0])
- value += float(what[1]) / 60.0
- value += float(what[2]) / 3600.0
- value += float(what[3]) / 3600000.0
- return float(what[4]) * value
-
-
-def _encode_size(what, desc):
- what = int(what)
- exponent = _exponent_of(what, desc) & 0xF
- base = what // pow(10, exponent) & 0xF
- return base * 16 + exponent
-
-
-def _decode_size(what, desc):
- exponent = what & 0x0F
- if exponent > 9:
- raise dns.exception.FormError("bad %s exponent" % desc)
- base = (what & 0xF0) >> 4
- if base > 9:
- raise dns.exception.FormError("bad %s base" % desc)
- return base * pow(10, exponent)
-
-
-def _check_coordinate_list(value, low, high):
- if value[0] < low or value[0] > high:
- raise ValueError(f"not in range [{low}, {high}]")
- if value[1] < 0 or value[1] > 59:
- raise ValueError("bad minutes value")
- if value[2] < 0 or value[2] > 59:
- raise ValueError("bad seconds value")
- if value[3] < 0 or value[3] > 999:
- raise ValueError("bad milliseconds value")
- if value[4] != 1 and value[4] != -1:
- raise ValueError("bad hemisphere value")
-
-
-@dns.immutable.immutable
-class LOC(dns.rdata.Rdata):
- """LOC record"""
-
- # see: RFC 1876
-
- __slots__ = [
- "latitude",
- "longitude",
- "altitude",
- "size",
- "horizontal_precision",
- "vertical_precision",
- ]
-
- def __init__(
- self,
- rdclass,
- rdtype,
- latitude,
- longitude,
- altitude,
- size=_default_size,
- hprec=_default_hprec,
- vprec=_default_vprec,
- ):
- """Initialize a LOC record instance.
-
- The parameters I{latitude} and I{longitude} may be either a 4-tuple
- of integers specifying (degrees, minutes, seconds, milliseconds),
- or they may be floating point values specifying the number of
- degrees. The other parameters are floats. Size, horizontal precision,
- and vertical precision are specified in centimeters."""
-
- super().__init__(rdclass, rdtype)
- if isinstance(latitude, int):
- latitude = float(latitude)
- if isinstance(latitude, float):
- latitude = _float_to_tuple(latitude)
- _check_coordinate_list(latitude, -90, 90)
- self.latitude = tuple(latitude)
- if isinstance(longitude, int):
- longitude = float(longitude)
- if isinstance(longitude, float):
- longitude = _float_to_tuple(longitude)
- _check_coordinate_list(longitude, -180, 180)
- self.longitude = tuple(longitude)
- self.altitude = float(altitude)
- self.size = float(size)
- self.horizontal_precision = float(hprec)
- self.vertical_precision = float(vprec)
-
- def to_text(self, origin=None, relativize=True, **kw):
- if self.latitude[4] > 0:
- lat_hemisphere = "N"
- else:
- lat_hemisphere = "S"
- if self.longitude[4] > 0:
- long_hemisphere = "E"
- else:
- long_hemisphere = "W"
- text = "%d %d %d.%03d %s %d %d %d.%03d %s %0.2fm" % (
- self.latitude[0],
- self.latitude[1],
- self.latitude[2],
- self.latitude[3],
- lat_hemisphere,
- self.longitude[0],
- self.longitude[1],
- self.longitude[2],
- self.longitude[3],
- long_hemisphere,
- self.altitude / 100.0,
- )
-
- # do not print default values
- if (
- self.size != _default_size
- or self.horizontal_precision != _default_hprec
- or self.vertical_precision != _default_vprec
- ):
- text += " {:0.2f}m {:0.2f}m {:0.2f}m".format(
- self.size / 100.0,
- self.horizontal_precision / 100.0,
- self.vertical_precision / 100.0,
- )
- return text
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- latitude = [0, 0, 0, 0, 1]
- longitude = [0, 0, 0, 0, 1]
- size = _default_size
- hprec = _default_hprec
- vprec = _default_vprec
-
- latitude[0] = tok.get_int()
- t = tok.get_string()
- if t.isdigit():
- latitude[1] = int(t)
- t = tok.get_string()
- if "." in t:
- (seconds, milliseconds) = t.split(".")
- if not seconds.isdigit():
- raise dns.exception.SyntaxError("bad latitude seconds value")
- latitude[2] = int(seconds)
- l = len(milliseconds)
- if l == 0 or l > 3 or not milliseconds.isdigit():
- raise dns.exception.SyntaxError("bad latitude milliseconds value")
- if l == 1:
- m = 100
- elif l == 2:
- m = 10
- else:
- m = 1
- latitude[3] = m * int(milliseconds)
- t = tok.get_string()
- elif t.isdigit():
- latitude[2] = int(t)
- t = tok.get_string()
- if t == "S":
- latitude[4] = -1
- elif t != "N":
- raise dns.exception.SyntaxError("bad latitude hemisphere value")
-
- longitude[0] = tok.get_int()
- t = tok.get_string()
- if t.isdigit():
- longitude[1] = int(t)
- t = tok.get_string()
- if "." in t:
- (seconds, milliseconds) = t.split(".")
- if not seconds.isdigit():
- raise dns.exception.SyntaxError("bad longitude seconds value")
- longitude[2] = int(seconds)
- l = len(milliseconds)
- if l == 0 or l > 3 or not milliseconds.isdigit():
- raise dns.exception.SyntaxError("bad longitude milliseconds value")
- if l == 1:
- m = 100
- elif l == 2:
- m = 10
- else:
- m = 1
- longitude[3] = m * int(milliseconds)
- t = tok.get_string()
- elif t.isdigit():
- longitude[2] = int(t)
- t = tok.get_string()
- if t == "W":
- longitude[4] = -1
- elif t != "E":
- raise dns.exception.SyntaxError("bad longitude hemisphere value")
-
- t = tok.get_string()
- if t[-1] == "m":
- t = t[0:-1]
- altitude = float(t) * 100.0 # m -> cm
-
- tokens = tok.get_remaining(max_tokens=3)
- if len(tokens) >= 1:
- value = tokens[0].unescape().value
- if value[-1] == "m":
- value = value[0:-1]
- size = float(value) * 100.0 # m -> cm
- if len(tokens) >= 2:
- value = tokens[1].unescape().value
- if value[-1] == "m":
- value = value[0:-1]
- hprec = float(value) * 100.0 # m -> cm
- if len(tokens) >= 3:
- value = tokens[2].unescape().value
- if value[-1] == "m":
- value = value[0:-1]
- vprec = float(value) * 100.0 # m -> cm
-
- # Try encoding these now so we raise if they are bad
- _encode_size(size, "size")
- _encode_size(hprec, "horizontal precision")
- _encode_size(vprec, "vertical precision")
-
- return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- milliseconds = (
- self.latitude[0] * 3600000
- + self.latitude[1] * 60000
- + self.latitude[2] * 1000
- + self.latitude[3]
- ) * self.latitude[4]
- latitude = 0x80000000 + milliseconds
- milliseconds = (
- self.longitude[0] * 3600000
- + self.longitude[1] * 60000
- + self.longitude[2] * 1000
- + self.longitude[3]
- ) * self.longitude[4]
- longitude = 0x80000000 + milliseconds
- altitude = int(self.altitude) + 10000000
- size = _encode_size(self.size, "size")
- hprec = _encode_size(self.horizontal_precision, "horizontal precision")
- vprec = _encode_size(self.vertical_precision, "vertical precision")
- wire = struct.pack(
- "!BBBBIII", 0, size, hprec, vprec, latitude, longitude, altitude
- )
- file.write(wire)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (
- version,
- size,
- hprec,
- vprec,
- latitude,
- longitude,
- altitude,
- ) = parser.get_struct("!BBBBIII")
- if version != 0:
- raise dns.exception.FormError("LOC version not zero")
- if latitude < _MIN_LATITUDE or latitude > _MAX_LATITUDE:
- raise dns.exception.FormError("bad latitude")
- if latitude > 0x80000000:
- latitude = (latitude - 0x80000000) / 3600000
- else:
- latitude = -1 * (0x80000000 - latitude) / 3600000
- if longitude < _MIN_LONGITUDE or longitude > _MAX_LONGITUDE:
- raise dns.exception.FormError("bad longitude")
- if longitude > 0x80000000:
- longitude = (longitude - 0x80000000) / 3600000
- else:
- longitude = -1 * (0x80000000 - longitude) / 3600000
- altitude = float(altitude) - 10000000.0
- size = _decode_size(size, "size")
- hprec = _decode_size(hprec, "horizontal precision")
- vprec = _decode_size(vprec, "vertical precision")
- return cls(rdclass, rdtype, latitude, longitude, altitude, size, hprec, vprec)
-
- @property
- def float_latitude(self):
- "latitude as a floating point value"
- return _tuple_to_float(self.latitude)
-
- @property
- def float_longitude(self):
- "longitude as a floating point value"
- return _tuple_to_float(self.longitude)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LP.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LP.py
deleted file mode 100644
index 312663f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/LP.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import struct
-
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class LP(dns.rdata.Rdata):
- """LP record"""
-
- # see: rfc6742.txt
-
- __slots__ = ["preference", "fqdn"]
-
- def __init__(self, rdclass, rdtype, preference, fqdn):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- self.fqdn = self._as_name(fqdn)
-
- def to_text(self, origin=None, relativize=True, **kw):
- fqdn = self.fqdn.choose_relativity(origin, relativize)
- return "%d %s" % (self.preference, fqdn)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- fqdn = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, preference, fqdn)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!H", self.preference))
- self.fqdn.to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- fqdn = parser.get_name(origin)
- return cls(rdclass, rdtype, preference, fqdn)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/MX.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/MX.py
deleted file mode 100644
index 0c300c5..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/MX.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.mxbase
-
-
-@dns.immutable.immutable
-class MX(dns.rdtypes.mxbase.MXBase):
- """MX record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NID.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NID.py
deleted file mode 100644
index 2f64917..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NID.py
+++ /dev/null
@@ -1,47 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import struct
-
-import dns.immutable
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class NID(dns.rdata.Rdata):
- """NID record"""
-
- # see: rfc6742.txt
-
- __slots__ = ["preference", "nodeid"]
-
- def __init__(self, rdclass, rdtype, preference, nodeid):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- if isinstance(nodeid, bytes):
- if len(nodeid) != 8:
- raise ValueError("invalid nodeid")
- self.nodeid = dns.rdata._hexify(nodeid, 4, b":")
- else:
- dns.rdtypes.util.parse_formatted_hex(nodeid, 4, 4, ":")
- self.nodeid = nodeid
-
- def to_text(self, origin=None, relativize=True, **kw):
- return f"{self.preference} {self.nodeid}"
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- nodeid = tok.get_identifier()
- return cls(rdclass, rdtype, preference, nodeid)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!H", self.preference))
- file.write(dns.rdtypes.util.parse_formatted_hex(self.nodeid, 4, 4, ":"))
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- nodeid = parser.get_remaining()
- return cls(rdclass, rdtype, preference, nodeid)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NINFO.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NINFO.py
deleted file mode 100644
index b177bdd..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NINFO.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.txtbase
-
-
-@dns.immutable.immutable
-class NINFO(dns.rdtypes.txtbase.TXTBase):
- """NINFO record"""
-
- # see: draft-reid-dnsext-zs-01
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NS.py
deleted file mode 100644
index c3f34ce..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NS.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.nsbase
-
-
-@dns.immutable.immutable
-class NS(dns.rdtypes.nsbase.NSBase):
- """NS record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC.py
deleted file mode 100644
index 340525a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC.py
+++ /dev/null
@@ -1,67 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdatatype
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class Bitmap(dns.rdtypes.util.Bitmap):
- type_name = "NSEC"
-
-
-@dns.immutable.immutable
-class NSEC(dns.rdata.Rdata):
- """NSEC record"""
-
- __slots__ = ["next", "windows"]
-
- def __init__(self, rdclass, rdtype, next, windows):
- super().__init__(rdclass, rdtype)
- self.next = self._as_name(next)
- if not isinstance(windows, Bitmap):
- windows = Bitmap(windows)
- self.windows = tuple(windows.windows)
-
- def to_text(self, origin=None, relativize=True, **kw):
- next = self.next.choose_relativity(origin, relativize)
- text = Bitmap(self.windows).to_text()
- return "{}{}".format(next, text)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- next = tok.get_name(origin, relativize, relativize_to)
- windows = Bitmap.from_text(tok)
- return cls(rdclass, rdtype, next, windows)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- # Note that NSEC downcasing, originally mandated by RFC 4034
- # section 6.2 was removed by RFC 6840 section 5.1.
- self.next.to_wire(file, None, origin, False)
- Bitmap(self.windows).to_wire(file)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- next = parser.get_name(origin)
- bitmap = Bitmap.from_wire_parser(parser)
- return cls(rdclass, rdtype, next, bitmap)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3.py
deleted file mode 100644
index d71302b..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3.py
+++ /dev/null
@@ -1,126 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import binascii
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-import dns.rdtypes.util
-
-b32_hex_to_normal = bytes.maketrans(
- b"0123456789ABCDEFGHIJKLMNOPQRSTUV", b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"
-)
-b32_normal_to_hex = bytes.maketrans(
- b"ABCDEFGHIJKLMNOPQRSTUVWXYZ234567", b"0123456789ABCDEFGHIJKLMNOPQRSTUV"
-)
-
-# hash algorithm constants
-SHA1 = 1
-
-# flag constants
-OPTOUT = 1
-
-
-@dns.immutable.immutable
-class Bitmap(dns.rdtypes.util.Bitmap):
- type_name = "NSEC3"
-
-
-@dns.immutable.immutable
-class NSEC3(dns.rdata.Rdata):
- """NSEC3 record"""
-
- __slots__ = ["algorithm", "flags", "iterations", "salt", "next", "windows"]
-
- def __init__(
- self, rdclass, rdtype, algorithm, flags, iterations, salt, next, windows
- ):
- super().__init__(rdclass, rdtype)
- self.algorithm = self._as_uint8(algorithm)
- self.flags = self._as_uint8(flags)
- self.iterations = self._as_uint16(iterations)
- self.salt = self._as_bytes(salt, True, 255)
- self.next = self._as_bytes(next, True, 255)
- if not isinstance(windows, Bitmap):
- windows = Bitmap(windows)
- self.windows = tuple(windows.windows)
-
- def _next_text(self):
- next = base64.b32encode(self.next).translate(b32_normal_to_hex).lower().decode()
- next = next.rstrip("=")
- return next
-
- def to_text(self, origin=None, relativize=True, **kw):
- next = self._next_text()
- if self.salt == b"":
- salt = "-"
- else:
- salt = binascii.hexlify(self.salt).decode()
- text = Bitmap(self.windows).to_text()
- return "%u %u %u %s %s%s" % (
- self.algorithm,
- self.flags,
- self.iterations,
- salt,
- next,
- text,
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_uint8()
- flags = tok.get_uint8()
- iterations = tok.get_uint16()
- salt = tok.get_string()
- if salt == "-":
- salt = b""
- else:
- salt = binascii.unhexlify(salt.encode("ascii"))
- next = tok.get_string().encode("ascii").upper().translate(b32_hex_to_normal)
- if next.endswith(b"="):
- raise binascii.Error("Incorrect padding")
- if len(next) % 8 != 0:
- next += b"=" * (8 - len(next) % 8)
- next = base64.b32decode(next)
- bitmap = Bitmap.from_text(tok)
- return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, bitmap)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.salt)
- file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l))
- file.write(self.salt)
- l = len(self.next)
- file.write(struct.pack("!B", l))
- file.write(self.next)
- Bitmap(self.windows).to_wire(file)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (algorithm, flags, iterations) = parser.get_struct("!BBH")
- salt = parser.get_counted_bytes()
- next = parser.get_counted_bytes()
- bitmap = Bitmap.from_wire_parser(parser)
- return cls(rdclass, rdtype, algorithm, flags, iterations, salt, next, bitmap)
-
- def next_name(self, origin=None):
- return dns.name.from_text(self._next_text(), origin)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py
deleted file mode 100644
index d1e62eb..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/NSEC3PARAM.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class NSEC3PARAM(dns.rdata.Rdata):
- """NSEC3PARAM record"""
-
- __slots__ = ["algorithm", "flags", "iterations", "salt"]
-
- def __init__(self, rdclass, rdtype, algorithm, flags, iterations, salt):
- super().__init__(rdclass, rdtype)
- self.algorithm = self._as_uint8(algorithm)
- self.flags = self._as_uint8(flags)
- self.iterations = self._as_uint16(iterations)
- self.salt = self._as_bytes(salt, True, 255)
-
- def to_text(self, origin=None, relativize=True, **kw):
- if self.salt == b"":
- salt = "-"
- else:
- salt = binascii.hexlify(self.salt).decode()
- return "%u %u %u %s" % (self.algorithm, self.flags, self.iterations, salt)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_uint8()
- flags = tok.get_uint8()
- iterations = tok.get_uint16()
- salt = tok.get_string()
- if salt == "-":
- salt = ""
- else:
- salt = binascii.unhexlify(salt.encode())
- return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.salt)
- file.write(struct.pack("!BBHB", self.algorithm, self.flags, self.iterations, l))
- file.write(self.salt)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (algorithm, flags, iterations) = parser.get_struct("!BBH")
- salt = parser.get_counted_bytes()
- return cls(rdclass, rdtype, algorithm, flags, iterations, salt)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py
deleted file mode 100644
index 4d7a4b6..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPENPGPKEY.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2016 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class OPENPGPKEY(dns.rdata.Rdata):
- """OPENPGPKEY record"""
-
- # see: RFC 7929
-
- def __init__(self, rdclass, rdtype, key):
- super().__init__(rdclass, rdtype)
- self.key = self._as_bytes(key)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return dns.rdata._base64ify(self.key, chunksize=None, **kw)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- b64 = tok.concatenate_remaining_identifiers().encode()
- key = base64.b64decode(b64)
- return cls(rdclass, rdtype, key)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(self.key)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- key = parser.get_remaining()
- return cls(rdclass, rdtype, key)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPT.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPT.py
deleted file mode 100644
index d343dfa..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/OPT.py
+++ /dev/null
@@ -1,77 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.edns
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-# We don't implement from_text, and that's ok.
-# pylint: disable=abstract-method
-
-
-@dns.immutable.immutable
-class OPT(dns.rdata.Rdata):
- """OPT record"""
-
- __slots__ = ["options"]
-
- def __init__(self, rdclass, rdtype, options):
- """Initialize an OPT rdata.
-
- *rdclass*, an ``int`` is the rdataclass of the Rdata,
- which is also the payload size.
-
- *rdtype*, an ``int`` is the rdatatype of the Rdata.
-
- *options*, a tuple of ``bytes``
- """
-
- super().__init__(rdclass, rdtype)
-
- def as_option(option):
- if not isinstance(option, dns.edns.Option):
- raise ValueError("option is not a dns.edns.option")
- return option
-
- self.options = self._as_tuple(options, as_option)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- for opt in self.options:
- owire = opt.to_wire()
- file.write(struct.pack("!HH", opt.otype, len(owire)))
- file.write(owire)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return " ".join(opt.to_text() for opt in self.options)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- options = []
- while parser.remaining() > 0:
- (otype, olen) = parser.get_struct("!HH")
- with parser.restrict_to(olen):
- opt = dns.edns.option_from_wire_parser(otype, parser)
- options.append(opt)
- return cls(rdclass, rdtype, options)
-
- @property
- def payload(self):
- "payload size"
- return self.rdclass
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/PTR.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/PTR.py
deleted file mode 100644
index 98c3616..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/PTR.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.nsbase
-
-
-@dns.immutable.immutable
-class PTR(dns.rdtypes.nsbase.NSBase):
- """PTR record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RP.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RP.py
deleted file mode 100644
index 9b74549..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RP.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-
-
-@dns.immutable.immutable
-class RP(dns.rdata.Rdata):
- """RP record"""
-
- # see: RFC 1183
-
- __slots__ = ["mbox", "txt"]
-
- def __init__(self, rdclass, rdtype, mbox, txt):
- super().__init__(rdclass, rdtype)
- self.mbox = self._as_name(mbox)
- self.txt = self._as_name(txt)
-
- def to_text(self, origin=None, relativize=True, **kw):
- mbox = self.mbox.choose_relativity(origin, relativize)
- txt = self.txt.choose_relativity(origin, relativize)
- return "{} {}".format(str(mbox), str(txt))
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- mbox = tok.get_name(origin, relativize, relativize_to)
- txt = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, mbox, txt)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.mbox.to_wire(file, None, origin, canonicalize)
- self.txt.to_wire(file, None, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- mbox = parser.get_name(origin)
- txt = parser.get_name(origin)
- return cls(rdclass, rdtype, mbox, txt)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RRSIG.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RRSIG.py
deleted file mode 100644
index 8beb423..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RRSIG.py
+++ /dev/null
@@ -1,157 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import calendar
-import struct
-import time
-
-import dns.dnssectypes
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-
-
-class BadSigTime(dns.exception.DNSException):
- """Time in DNS SIG or RRSIG resource record cannot be parsed."""
-
-
-def sigtime_to_posixtime(what):
- if len(what) <= 10 and what.isdigit():
- return int(what)
- if len(what) != 14:
- raise BadSigTime
- year = int(what[0:4])
- month = int(what[4:6])
- day = int(what[6:8])
- hour = int(what[8:10])
- minute = int(what[10:12])
- second = int(what[12:14])
- return calendar.timegm((year, month, day, hour, minute, second, 0, 0, 0))
-
-
-def posixtime_to_sigtime(what):
- return time.strftime("%Y%m%d%H%M%S", time.gmtime(what))
-
-
-@dns.immutable.immutable
-class RRSIG(dns.rdata.Rdata):
- """RRSIG record"""
-
- __slots__ = [
- "type_covered",
- "algorithm",
- "labels",
- "original_ttl",
- "expiration",
- "inception",
- "key_tag",
- "signer",
- "signature",
- ]
-
- def __init__(
- self,
- rdclass,
- rdtype,
- type_covered,
- algorithm,
- labels,
- original_ttl,
- expiration,
- inception,
- key_tag,
- signer,
- signature,
- ):
- super().__init__(rdclass, rdtype)
- self.type_covered = self._as_rdatatype(type_covered)
- self.algorithm = dns.dnssectypes.Algorithm.make(algorithm)
- self.labels = self._as_uint8(labels)
- self.original_ttl = self._as_ttl(original_ttl)
- self.expiration = self._as_uint32(expiration)
- self.inception = self._as_uint32(inception)
- self.key_tag = self._as_uint16(key_tag)
- self.signer = self._as_name(signer)
- self.signature = self._as_bytes(signature)
-
- def covers(self):
- return self.type_covered
-
- def to_text(self, origin=None, relativize=True, **kw):
- return "%s %d %d %d %s %s %d %s %s" % (
- dns.rdatatype.to_text(self.type_covered),
- self.algorithm,
- self.labels,
- self.original_ttl,
- posixtime_to_sigtime(self.expiration),
- posixtime_to_sigtime(self.inception),
- self.key_tag,
- self.signer.choose_relativity(origin, relativize),
- dns.rdata._base64ify(self.signature, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- type_covered = dns.rdatatype.from_text(tok.get_string())
- algorithm = dns.dnssectypes.Algorithm.from_text(tok.get_string())
- labels = tok.get_int()
- original_ttl = tok.get_ttl()
- expiration = sigtime_to_posixtime(tok.get_string())
- inception = sigtime_to_posixtime(tok.get_string())
- key_tag = tok.get_int()
- signer = tok.get_name(origin, relativize, relativize_to)
- b64 = tok.concatenate_remaining_identifiers().encode()
- signature = base64.b64decode(b64)
- return cls(
- rdclass,
- rdtype,
- type_covered,
- algorithm,
- labels,
- original_ttl,
- expiration,
- inception,
- key_tag,
- signer,
- signature,
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack(
- "!HBBIIIH",
- self.type_covered,
- self.algorithm,
- self.labels,
- self.original_ttl,
- self.expiration,
- self.inception,
- self.key_tag,
- )
- file.write(header)
- self.signer.to_wire(file, None, origin, canonicalize)
- file.write(self.signature)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("!HBBIIIH")
- signer = parser.get_name(origin)
- signature = parser.get_remaining()
- return cls(rdclass, rdtype, *header, signer, signature)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RT.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RT.py
deleted file mode 100644
index 5a4d45c..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/RT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.mxbase
-
-
-@dns.immutable.immutable
-class RT(dns.rdtypes.mxbase.UncompressedDowncasingMX):
- """RT record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SMIMEA.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SMIMEA.py
deleted file mode 100644
index 55d87bf..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SMIMEA.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import dns.immutable
-import dns.rdtypes.tlsabase
-
-
-@dns.immutable.immutable
-class SMIMEA(dns.rdtypes.tlsabase.TLSABase):
- """SMIMEA record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SOA.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SOA.py
deleted file mode 100644
index 09aa832..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SOA.py
+++ /dev/null
@@ -1,86 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-
-
-@dns.immutable.immutable
-class SOA(dns.rdata.Rdata):
- """SOA record"""
-
- # see: RFC 1035
-
- __slots__ = ["mname", "rname", "serial", "refresh", "retry", "expire", "minimum"]
-
- def __init__(
- self, rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum
- ):
- super().__init__(rdclass, rdtype)
- self.mname = self._as_name(mname)
- self.rname = self._as_name(rname)
- self.serial = self._as_uint32(serial)
- self.refresh = self._as_ttl(refresh)
- self.retry = self._as_ttl(retry)
- self.expire = self._as_ttl(expire)
- self.minimum = self._as_ttl(minimum)
-
- def to_text(self, origin=None, relativize=True, **kw):
- mname = self.mname.choose_relativity(origin, relativize)
- rname = self.rname.choose_relativity(origin, relativize)
- return "%s %s %d %d %d %d %d" % (
- mname,
- rname,
- self.serial,
- self.refresh,
- self.retry,
- self.expire,
- self.minimum,
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- mname = tok.get_name(origin, relativize, relativize_to)
- rname = tok.get_name(origin, relativize, relativize_to)
- serial = tok.get_uint32()
- refresh = tok.get_ttl()
- retry = tok.get_ttl()
- expire = tok.get_ttl()
- minimum = tok.get_ttl()
- return cls(
- rdclass, rdtype, mname, rname, serial, refresh, retry, expire, minimum
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.mname.to_wire(file, compress, origin, canonicalize)
- self.rname.to_wire(file, compress, origin, canonicalize)
- five_ints = struct.pack(
- "!IIIII", self.serial, self.refresh, self.retry, self.expire, self.minimum
- )
- file.write(five_ints)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- mname = parser.get_name(origin)
- rname = parser.get_name(origin)
- return cls(rdclass, rdtype, mname, rname, *parser.get_struct("!IIIII"))
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SPF.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SPF.py
deleted file mode 100644
index 1df3b70..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SPF.py
+++ /dev/null
@@ -1,26 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.txtbase
-
-
-@dns.immutable.immutable
-class SPF(dns.rdtypes.txtbase.TXTBase):
- """SPF record"""
-
- # see: RFC 4408
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SSHFP.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SSHFP.py
deleted file mode 100644
index d2c4b07..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/SSHFP.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-import struct
-
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-
-
-@dns.immutable.immutable
-class SSHFP(dns.rdata.Rdata):
- """SSHFP record"""
-
- # See RFC 4255
-
- __slots__ = ["algorithm", "fp_type", "fingerprint"]
-
- def __init__(self, rdclass, rdtype, algorithm, fp_type, fingerprint):
- super().__init__(rdclass, rdtype)
- self.algorithm = self._as_uint8(algorithm)
- self.fp_type = self._as_uint8(fp_type)
- self.fingerprint = self._as_bytes(fingerprint, True)
-
- def to_text(self, origin=None, relativize=True, **kw):
- kw = kw.copy()
- chunksize = kw.pop("chunksize", 128)
- return "%d %d %s" % (
- self.algorithm,
- self.fp_type,
- dns.rdata._hexify(self.fingerprint, chunksize=chunksize, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_uint8()
- fp_type = tok.get_uint8()
- fingerprint = tok.concatenate_remaining_identifiers().encode()
- fingerprint = binascii.unhexlify(fingerprint)
- return cls(rdclass, rdtype, algorithm, fp_type, fingerprint)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!BB", self.algorithm, self.fp_type)
- file.write(header)
- file.write(self.fingerprint)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("BB")
- fingerprint = parser.get_remaining()
- return cls(rdclass, rdtype, header[0], header[1], fingerprint)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TKEY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TKEY.py
deleted file mode 100644
index 5b490b8..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TKEY.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class TKEY(dns.rdata.Rdata):
- """TKEY Record"""
-
- __slots__ = [
- "algorithm",
- "inception",
- "expiration",
- "mode",
- "error",
- "key",
- "other",
- ]
-
- def __init__(
- self,
- rdclass,
- rdtype,
- algorithm,
- inception,
- expiration,
- mode,
- error,
- key,
- other=b"",
- ):
- super().__init__(rdclass, rdtype)
- self.algorithm = self._as_name(algorithm)
- self.inception = self._as_uint32(inception)
- self.expiration = self._as_uint32(expiration)
- self.mode = self._as_uint16(mode)
- self.error = self._as_uint16(error)
- self.key = self._as_bytes(key)
- self.other = self._as_bytes(other)
-
- def to_text(self, origin=None, relativize=True, **kw):
- _algorithm = self.algorithm.choose_relativity(origin, relativize)
- text = "%s %u %u %u %u %s" % (
- str(_algorithm),
- self.inception,
- self.expiration,
- self.mode,
- self.error,
- dns.rdata._base64ify(self.key, 0),
- )
- if len(self.other) > 0:
- text += " %s" % (dns.rdata._base64ify(self.other, 0))
-
- return text
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_name(relativize=False)
- inception = tok.get_uint32()
- expiration = tok.get_uint32()
- mode = tok.get_uint16()
- error = tok.get_uint16()
- key_b64 = tok.get_string().encode()
- key = base64.b64decode(key_b64)
- other_b64 = tok.concatenate_remaining_identifiers(True).encode()
- other = base64.b64decode(other_b64)
-
- return cls(
- rdclass, rdtype, algorithm, inception, expiration, mode, error, key, other
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.algorithm.to_wire(file, compress, origin)
- file.write(
- struct.pack("!IIHH", self.inception, self.expiration, self.mode, self.error)
- )
- file.write(struct.pack("!H", len(self.key)))
- file.write(self.key)
- file.write(struct.pack("!H", len(self.other)))
- if len(self.other) > 0:
- file.write(self.other)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- algorithm = parser.get_name(origin)
- inception, expiration, mode, error = parser.get_struct("!IIHH")
- key = parser.get_counted_bytes(2)
- other = parser.get_counted_bytes(2)
-
- return cls(
- rdclass, rdtype, algorithm, inception, expiration, mode, error, key, other
- )
-
- # Constants for the mode field - from RFC 2930:
- # 2.5 The Mode Field
- #
- # The mode field specifies the general scheme for key agreement or
- # the purpose of the TKEY DNS message. Servers and resolvers
- # supporting this specification MUST implement the Diffie-Hellman key
- # agreement mode and the key deletion mode for queries. All other
- # modes are OPTIONAL. A server supporting TKEY that receives a TKEY
- # request with a mode it does not support returns the BADMODE error.
- # The following values of the Mode octet are defined, available, or
- # reserved:
- #
- # Value Description
- # ----- -----------
- # 0 - reserved, see section 7
- # 1 server assignment
- # 2 Diffie-Hellman exchange
- # 3 GSS-API negotiation
- # 4 resolver assignment
- # 5 key deletion
- # 6-65534 - available, see section 7
- # 65535 - reserved, see section 7
- SERVER_ASSIGNMENT = 1
- DIFFIE_HELLMAN_EXCHANGE = 2
- GSSAPI_NEGOTIATION = 3
- RESOLVER_ASSIGNMENT = 4
- KEY_DELETION = 5
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TLSA.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TLSA.py
deleted file mode 100644
index 4dffc55..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TLSA.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import dns.immutable
-import dns.rdtypes.tlsabase
-
-
-@dns.immutable.immutable
-class TLSA(dns.rdtypes.tlsabase.TLSABase):
- """TLSA record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TSIG.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TSIG.py
deleted file mode 100644
index 7942382..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TSIG.py
+++ /dev/null
@@ -1,160 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rcode
-import dns.rdata
-
-
-@dns.immutable.immutable
-class TSIG(dns.rdata.Rdata):
- """TSIG record"""
-
- __slots__ = [
- "algorithm",
- "time_signed",
- "fudge",
- "mac",
- "original_id",
- "error",
- "other",
- ]
-
- def __init__(
- self,
- rdclass,
- rdtype,
- algorithm,
- time_signed,
- fudge,
- mac,
- original_id,
- error,
- other,
- ):
- """Initialize a TSIG rdata.
-
- *rdclass*, an ``int`` is the rdataclass of the Rdata.
-
- *rdtype*, an ``int`` is the rdatatype of the Rdata.
-
- *algorithm*, a ``dns.name.Name``.
-
- *time_signed*, an ``int``.
-
- *fudge*, an ``int`.
-
- *mac*, a ``bytes``
-
- *original_id*, an ``int``
-
- *error*, an ``int``
-
- *other*, a ``bytes``
- """
-
- super().__init__(rdclass, rdtype)
- self.algorithm = self._as_name(algorithm)
- self.time_signed = self._as_uint48(time_signed)
- self.fudge = self._as_uint16(fudge)
- self.mac = self._as_bytes(mac)
- self.original_id = self._as_uint16(original_id)
- self.error = dns.rcode.Rcode.make(error)
- self.other = self._as_bytes(other)
-
- def to_text(self, origin=None, relativize=True, **kw):
- algorithm = self.algorithm.choose_relativity(origin, relativize)
- error = dns.rcode.to_text(self.error, True)
- text = (
- f"{algorithm} {self.time_signed} {self.fudge} "
- + f"{len(self.mac)} {dns.rdata._base64ify(self.mac, 0)} "
- + f"{self.original_id} {error} {len(self.other)}"
- )
- if self.other:
- text += f" {dns.rdata._base64ify(self.other, 0)}"
- return text
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- algorithm = tok.get_name(relativize=False)
- time_signed = tok.get_uint48()
- fudge = tok.get_uint16()
- mac_len = tok.get_uint16()
- mac = base64.b64decode(tok.get_string())
- if len(mac) != mac_len:
- raise SyntaxError("invalid MAC")
- original_id = tok.get_uint16()
- error = dns.rcode.from_text(tok.get_string())
- other_len = tok.get_uint16()
- if other_len > 0:
- other = base64.b64decode(tok.get_string())
- if len(other) != other_len:
- raise SyntaxError("invalid other data")
- else:
- other = b""
- return cls(
- rdclass,
- rdtype,
- algorithm,
- time_signed,
- fudge,
- mac,
- original_id,
- error,
- other,
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.algorithm.to_wire(file, None, origin, False)
- file.write(
- struct.pack(
- "!HIHH",
- (self.time_signed >> 32) & 0xFFFF,
- self.time_signed & 0xFFFFFFFF,
- self.fudge,
- len(self.mac),
- )
- )
- file.write(self.mac)
- file.write(struct.pack("!HHH", self.original_id, self.error, len(self.other)))
- file.write(self.other)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- algorithm = parser.get_name()
- time_signed = parser.get_uint48()
- fudge = parser.get_uint16()
- mac = parser.get_counted_bytes(2)
- (original_id, error) = parser.get_struct("!HH")
- other = parser.get_counted_bytes(2)
- return cls(
- rdclass,
- rdtype,
- algorithm,
- time_signed,
- fudge,
- mac,
- original_id,
- error,
- other,
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TXT.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TXT.py
deleted file mode 100644
index 6d4dae2..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/TXT.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.txtbase
-
-
-@dns.immutable.immutable
-class TXT(dns.rdtypes.txtbase.TXTBase):
- """TXT record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/URI.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/URI.py
deleted file mode 100644
index 2efbb30..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/URI.py
+++ /dev/null
@@ -1,79 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-# Copyright (C) 2015 Red Hat, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class URI(dns.rdata.Rdata):
- """URI record"""
-
- # see RFC 7553
-
- __slots__ = ["priority", "weight", "target"]
-
- def __init__(self, rdclass, rdtype, priority, weight, target):
- super().__init__(rdclass, rdtype)
- self.priority = self._as_uint16(priority)
- self.weight = self._as_uint16(weight)
- self.target = self._as_bytes(target, True)
- if len(self.target) == 0:
- raise dns.exception.SyntaxError("URI target cannot be empty")
-
- def to_text(self, origin=None, relativize=True, **kw):
- return '%d %d "%s"' % (self.priority, self.weight, self.target.decode())
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- priority = tok.get_uint16()
- weight = tok.get_uint16()
- target = tok.get().unescape()
- if not (target.is_quoted_string() or target.is_identifier()):
- raise dns.exception.SyntaxError("URI target must be a string")
- return cls(rdclass, rdtype, priority, weight, target.value)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- two_ints = struct.pack("!HH", self.priority, self.weight)
- file.write(two_ints)
- file.write(self.target)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (priority, weight) = parser.get_struct("!HH")
- target = parser.get_remaining()
- if len(target) == 0:
- raise dns.exception.FormError("URI target may not be empty")
- return cls(rdclass, rdtype, priority, weight, target)
-
- def _processing_priority(self):
- return self.priority
-
- def _processing_weight(self):
- return self.weight
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.weighted_processing_order(iterable)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/X25.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/X25.py
deleted file mode 100644
index 8375611..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/X25.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class X25(dns.rdata.Rdata):
- """X25 record"""
-
- # see RFC 1183
-
- __slots__ = ["address"]
-
- def __init__(self, rdclass, rdtype, address):
- super().__init__(rdclass, rdtype)
- self.address = self._as_bytes(address, True, 255)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return '"%s"' % dns.rdata._escapify(self.address)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_string()
- return cls(rdclass, rdtype, address)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- l = len(self.address)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(self.address)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_counted_bytes()
- return cls(rdclass, rdtype, address)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ZONEMD.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ZONEMD.py
deleted file mode 100644
index c90e3ee..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/ZONEMD.py
+++ /dev/null
@@ -1,66 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import binascii
-import struct
-
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-import dns.zonetypes
-
-
-@dns.immutable.immutable
-class ZONEMD(dns.rdata.Rdata):
- """ZONEMD record"""
-
- # See RFC 8976
-
- __slots__ = ["serial", "scheme", "hash_algorithm", "digest"]
-
- def __init__(self, rdclass, rdtype, serial, scheme, hash_algorithm, digest):
- super().__init__(rdclass, rdtype)
- self.serial = self._as_uint32(serial)
- self.scheme = dns.zonetypes.DigestScheme.make(scheme)
- self.hash_algorithm = dns.zonetypes.DigestHashAlgorithm.make(hash_algorithm)
- self.digest = self._as_bytes(digest)
-
- if self.scheme == 0: # reserved, RFC 8976 Sec. 5.2
- raise ValueError("scheme 0 is reserved")
- if self.hash_algorithm == 0: # reserved, RFC 8976 Sec. 5.3
- raise ValueError("hash_algorithm 0 is reserved")
-
- hasher = dns.zonetypes._digest_hashers.get(self.hash_algorithm)
- if hasher and hasher().digest_size != len(self.digest):
- raise ValueError("digest length inconsistent with hash algorithm")
-
- def to_text(self, origin=None, relativize=True, **kw):
- kw = kw.copy()
- chunksize = kw.pop("chunksize", 128)
- return "%d %d %d %s" % (
- self.serial,
- self.scheme,
- self.hash_algorithm,
- dns.rdata._hexify(self.digest, chunksize=chunksize, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- serial = tok.get_uint32()
- scheme = tok.get_uint8()
- hash_algorithm = tok.get_uint8()
- digest = tok.concatenate_remaining_identifiers().encode()
- digest = binascii.unhexlify(digest)
- return cls(rdclass, rdtype, serial, scheme, hash_algorithm, digest)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!IBB", self.serial, self.scheme, self.hash_algorithm)
- file.write(header)
- file.write(self.digest)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("!IBB")
- digest = parser.get_remaining()
- return cls(rdclass, rdtype, header[0], header[1], header[2], digest)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__init__.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__init__.py
deleted file mode 100644
index 3824a0a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__init__.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Class ANY (generic) rdata type classes."""
-
-__all__ = [
- "AFSDB",
- "AMTRELAY",
- "AVC",
- "CAA",
- "CDNSKEY",
- "CDS",
- "CERT",
- "CNAME",
- "CSYNC",
- "DLV",
- "DNAME",
- "DNSKEY",
- "DS",
- "EUI48",
- "EUI64",
- "GPOS",
- "HINFO",
- "HIP",
- "ISDN",
- "L32",
- "L64",
- "LOC",
- "LP",
- "MX",
- "NID",
- "NINFO",
- "NS",
- "NSEC",
- "NSEC3",
- "NSEC3PARAM",
- "OPENPGPKEY",
- "OPT",
- "PTR",
- "RP",
- "RRSIG",
- "RT",
- "SMIMEA",
- "SOA",
- "SPF",
- "SSHFP",
- "TKEY",
- "TLSA",
- "TSIG",
- "TXT",
- "URI",
- "X25",
- "ZONEMD",
-]
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AFSDB.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AFSDB.cpython-312.pyc
deleted file mode 100644
index 79beeef..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AFSDB.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AMTRELAY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AMTRELAY.cpython-312.pyc
deleted file mode 100644
index 5ae7b10..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AMTRELAY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AVC.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AVC.cpython-312.pyc
deleted file mode 100644
index efe1635..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/AVC.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CAA.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CAA.cpython-312.pyc
deleted file mode 100644
index 7857b5e..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CAA.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDNSKEY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDNSKEY.cpython-312.pyc
deleted file mode 100644
index 373c9de..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDNSKEY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDS.cpython-312.pyc
deleted file mode 100644
index 6ec3ab3..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CDS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CERT.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CERT.cpython-312.pyc
deleted file mode 100644
index 471424a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CERT.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CNAME.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CNAME.cpython-312.pyc
deleted file mode 100644
index 71bc66f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CNAME.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CSYNC.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CSYNC.cpython-312.pyc
deleted file mode 100644
index 2e687a0..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/CSYNC.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DLV.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DLV.cpython-312.pyc
deleted file mode 100644
index a86c239..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DLV.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNAME.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNAME.cpython-312.pyc
deleted file mode 100644
index c766215..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNAME.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNSKEY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNSKEY.cpython-312.pyc
deleted file mode 100644
index 311aaf9..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DNSKEY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DS.cpython-312.pyc
deleted file mode 100644
index ee69788..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/DS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI48.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI48.cpython-312.pyc
deleted file mode 100644
index a651c82..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI48.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI64.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI64.cpython-312.pyc
deleted file mode 100644
index 0e7ec31..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/EUI64.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/GPOS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/GPOS.cpython-312.pyc
deleted file mode 100644
index 70d4e88..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/GPOS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HINFO.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HINFO.cpython-312.pyc
deleted file mode 100644
index 1fc418d..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HINFO.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HIP.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HIP.cpython-312.pyc
deleted file mode 100644
index e1b9853..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/HIP.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ISDN.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ISDN.cpython-312.pyc
deleted file mode 100644
index 380f1bf..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ISDN.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L32.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L32.cpython-312.pyc
deleted file mode 100644
index 80a0f8f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L32.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L64.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L64.cpython-312.pyc
deleted file mode 100644
index b8db103..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/L64.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LOC.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LOC.cpython-312.pyc
deleted file mode 100644
index 2755491..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LOC.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LP.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LP.cpython-312.pyc
deleted file mode 100644
index 9c4ab45..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/LP.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/MX.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/MX.cpython-312.pyc
deleted file mode 100644
index b04fd41..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/MX.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NID.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NID.cpython-312.pyc
deleted file mode 100644
index 77a7d00..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NID.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NINFO.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NINFO.cpython-312.pyc
deleted file mode 100644
index 6205b07..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NINFO.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NS.cpython-312.pyc
deleted file mode 100644
index 88558a1..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC.cpython-312.pyc
deleted file mode 100644
index b291a8a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3.cpython-312.pyc
deleted file mode 100644
index 10e60df..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3PARAM.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3PARAM.cpython-312.pyc
deleted file mode 100644
index 1dec1ae..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/NSEC3PARAM.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPENPGPKEY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPENPGPKEY.cpython-312.pyc
deleted file mode 100644
index 5a30d62..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPENPGPKEY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPT.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPT.cpython-312.pyc
deleted file mode 100644
index 05e7b1c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/OPT.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/PTR.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/PTR.cpython-312.pyc
deleted file mode 100644
index f2e3826..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/PTR.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RP.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RP.cpython-312.pyc
deleted file mode 100644
index b1eb282..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RP.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RRSIG.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RRSIG.cpython-312.pyc
deleted file mode 100644
index 8526334..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RRSIG.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RT.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RT.cpython-312.pyc
deleted file mode 100644
index 1f33203..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/RT.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SMIMEA.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SMIMEA.cpython-312.pyc
deleted file mode 100644
index 374314f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SMIMEA.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SOA.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SOA.cpython-312.pyc
deleted file mode 100644
index 5de147f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SOA.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SPF.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SPF.cpython-312.pyc
deleted file mode 100644
index cdcf69a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SPF.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SSHFP.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SSHFP.cpython-312.pyc
deleted file mode 100644
index 84ad610..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/SSHFP.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TKEY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TKEY.cpython-312.pyc
deleted file mode 100644
index 0c93167..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TKEY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TLSA.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TLSA.cpython-312.pyc
deleted file mode 100644
index 1eb3a5f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TLSA.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TSIG.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TSIG.cpython-312.pyc
deleted file mode 100644
index 1ea7d47..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TSIG.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TXT.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TXT.cpython-312.pyc
deleted file mode 100644
index ada5d7a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/TXT.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/URI.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/URI.cpython-312.pyc
deleted file mode 100644
index 132981b..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/URI.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/X25.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/X25.cpython-312.pyc
deleted file mode 100644
index 8abf323..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/X25.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ZONEMD.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ZONEMD.cpython-312.pyc
deleted file mode 100644
index c7f97a8..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/ZONEMD.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 1f339c2..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/ANY/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/A.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/A.py
deleted file mode 100644
index 583a88a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/A.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.immutable
-import dns.rdtypes.mxbase
-
-
-@dns.immutable.immutable
-class A(dns.rdata.Rdata):
- """A record for Chaosnet"""
-
- # domain: the domain of the address
- # address: the 16-bit address
-
- __slots__ = ["domain", "address"]
-
- def __init__(self, rdclass, rdtype, domain, address):
- super().__init__(rdclass, rdtype)
- self.domain = self._as_name(domain)
- self.address = self._as_uint16(address)
-
- def to_text(self, origin=None, relativize=True, **kw):
- domain = self.domain.choose_relativity(origin, relativize)
- return "%s %o" % (domain, self.address)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- domain = tok.get_name(origin, relativize, relativize_to)
- address = tok.get_uint16(base=8)
- return cls(rdclass, rdtype, domain, address)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.domain.to_wire(file, compress, origin, canonicalize)
- pref = struct.pack("!H", self.address)
- file.write(pref)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- domain = parser.get_name(origin)
- address = parser.get_uint16()
- return cls(rdclass, rdtype, domain, address)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__init__.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__init__.py
deleted file mode 100644
index 0760c26..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__init__.py
+++ /dev/null
@@ -1,22 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Class CH rdata type classes."""
-
-__all__ = [
- "A",
-]
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/A.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/A.cpython-312.pyc
deleted file mode 100644
index 61f92ed..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/A.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index dd9f2b2..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/CH/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/A.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/A.py
deleted file mode 100644
index e09d611..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/A.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.exception
-import dns.immutable
-import dns.ipv4
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class A(dns.rdata.Rdata):
- """A record."""
-
- __slots__ = ["address"]
-
- def __init__(self, rdclass, rdtype, address):
- super().__init__(rdclass, rdtype)
- self.address = self._as_ipv4_address(address)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return self.address
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_identifier()
- return cls(rdclass, rdtype, address)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(dns.ipv4.inet_aton(self.address))
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_remaining()
- return cls(rdclass, rdtype, address)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/AAAA.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/AAAA.py
deleted file mode 100644
index 0cd139e..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/AAAA.py
+++ /dev/null
@@ -1,51 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.exception
-import dns.immutable
-import dns.ipv6
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class AAAA(dns.rdata.Rdata):
- """AAAA record."""
-
- __slots__ = ["address"]
-
- def __init__(self, rdclass, rdtype, address):
- super().__init__(rdclass, rdtype)
- self.address = self._as_ipv6_address(address)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return self.address
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_identifier()
- return cls(rdclass, rdtype, address)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(dns.ipv6.inet_aton(self.address))
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_remaining()
- return cls(rdclass, rdtype, address)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/APL.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/APL.py
deleted file mode 100644
index 44cb3fe..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/APL.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-import codecs
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.ipv4
-import dns.ipv6
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class APLItem:
- """An APL list item."""
-
- __slots__ = ["family", "negation", "address", "prefix"]
-
- def __init__(self, family, negation, address, prefix):
- self.family = dns.rdata.Rdata._as_uint16(family)
- self.negation = dns.rdata.Rdata._as_bool(negation)
- if self.family == 1:
- self.address = dns.rdata.Rdata._as_ipv4_address(address)
- self.prefix = dns.rdata.Rdata._as_int(prefix, 0, 32)
- elif self.family == 2:
- self.address = dns.rdata.Rdata._as_ipv6_address(address)
- self.prefix = dns.rdata.Rdata._as_int(prefix, 0, 128)
- else:
- self.address = dns.rdata.Rdata._as_bytes(address, max_length=127)
- self.prefix = dns.rdata.Rdata._as_uint8(prefix)
-
- def __str__(self):
- if self.negation:
- return "!%d:%s/%s" % (self.family, self.address, self.prefix)
- else:
- return "%d:%s/%s" % (self.family, self.address, self.prefix)
-
- def to_wire(self, file):
- if self.family == 1:
- address = dns.ipv4.inet_aton(self.address)
- elif self.family == 2:
- address = dns.ipv6.inet_aton(self.address)
- else:
- address = binascii.unhexlify(self.address)
- #
- # Truncate least significant zero bytes.
- #
- last = 0
- for i in range(len(address) - 1, -1, -1):
- if address[i] != 0:
- last = i + 1
- break
- address = address[0:last]
- l = len(address)
- assert l < 128
- if self.negation:
- l |= 0x80
- header = struct.pack("!HBB", self.family, self.prefix, l)
- file.write(header)
- file.write(address)
-
-
-@dns.immutable.immutable
-class APL(dns.rdata.Rdata):
- """APL record."""
-
- # see: RFC 3123
-
- __slots__ = ["items"]
-
- def __init__(self, rdclass, rdtype, items):
- super().__init__(rdclass, rdtype)
- for item in items:
- if not isinstance(item, APLItem):
- raise ValueError("item not an APLItem")
- self.items = tuple(items)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return " ".join(map(str, self.items))
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- items = []
- for token in tok.get_remaining():
- item = token.unescape().value
- if item[0] == "!":
- negation = True
- item = item[1:]
- else:
- negation = False
- (family, rest) = item.split(":", 1)
- family = int(family)
- (address, prefix) = rest.split("/", 1)
- prefix = int(prefix)
- item = APLItem(family, negation, address, prefix)
- items.append(item)
-
- return cls(rdclass, rdtype, items)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- for item in self.items:
- item.to_wire(file)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- items = []
- while parser.remaining() > 0:
- header = parser.get_struct("!HBB")
- afdlen = header[2]
- if afdlen > 127:
- negation = True
- afdlen -= 128
- else:
- negation = False
- address = parser.get_bytes(afdlen)
- l = len(address)
- if header[0] == 1:
- if l < 4:
- address += b"\x00" * (4 - l)
- elif header[0] == 2:
- if l < 16:
- address += b"\x00" * (16 - l)
- else:
- #
- # This isn't really right according to the RFC, but it
- # seems better than throwing an exception
- #
- address = codecs.encode(address, "hex_codec")
- item = APLItem(header[0], negation, address, header[1])
- items.append(item)
- return cls(rdclass, rdtype, items)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/DHCID.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/DHCID.py
deleted file mode 100644
index 723492f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/DHCID.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class DHCID(dns.rdata.Rdata):
- """DHCID record"""
-
- # see: RFC 4701
-
- __slots__ = ["data"]
-
- def __init__(self, rdclass, rdtype, data):
- super().__init__(rdclass, rdtype)
- self.data = self._as_bytes(data)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return dns.rdata._base64ify(self.data, **kw)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- b64 = tok.concatenate_remaining_identifiers().encode()
- data = base64.b64decode(b64)
- return cls(rdclass, rdtype, data)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(self.data)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- data = parser.get_remaining()
- return cls(rdclass, rdtype, data)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/HTTPS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/HTTPS.py
deleted file mode 100644
index 15464cb..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/HTTPS.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import dns.immutable
-import dns.rdtypes.svcbbase
-
-
-@dns.immutable.immutable
-class HTTPS(dns.rdtypes.svcbbase.SVCBBase):
- """HTTPS record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/IPSECKEY.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/IPSECKEY.py
deleted file mode 100644
index e3a6615..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/IPSECKEY.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.rdtypes.util
-
-
-class Gateway(dns.rdtypes.util.Gateway):
- name = "IPSECKEY gateway"
-
-
-@dns.immutable.immutable
-class IPSECKEY(dns.rdata.Rdata):
- """IPSECKEY record"""
-
- # see: RFC 4025
-
- __slots__ = ["precedence", "gateway_type", "algorithm", "gateway", "key"]
-
- def __init__(
- self, rdclass, rdtype, precedence, gateway_type, algorithm, gateway, key
- ):
- super().__init__(rdclass, rdtype)
- gateway = Gateway(gateway_type, gateway)
- self.precedence = self._as_uint8(precedence)
- self.gateway_type = gateway.type
- self.algorithm = self._as_uint8(algorithm)
- self.gateway = gateway.gateway
- self.key = self._as_bytes(key)
-
- def to_text(self, origin=None, relativize=True, **kw):
- gateway = Gateway(self.gateway_type, self.gateway).to_text(origin, relativize)
- return "%d %d %d %s %s" % (
- self.precedence,
- self.gateway_type,
- self.algorithm,
- gateway,
- dns.rdata._base64ify(self.key, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- precedence = tok.get_uint8()
- gateway_type = tok.get_uint8()
- algorithm = tok.get_uint8()
- gateway = Gateway.from_text(
- gateway_type, tok, origin, relativize, relativize_to
- )
- b64 = tok.concatenate_remaining_identifiers().encode()
- key = base64.b64decode(b64)
- return cls(
- rdclass, rdtype, precedence, gateway_type, algorithm, gateway.gateway, key
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!BBB", self.precedence, self.gateway_type, self.algorithm)
- file.write(header)
- Gateway(self.gateway_type, self.gateway).to_wire(
- file, compress, origin, canonicalize
- )
- file.write(self.key)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("!BBB")
- gateway_type = header[1]
- gateway = Gateway.from_wire_parser(gateway_type, parser, origin)
- key = parser.get_remaining()
- return cls(
- rdclass, rdtype, header[0], gateway_type, header[2], gateway.gateway, key
- )
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/KX.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/KX.py
deleted file mode 100644
index 6073df4..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/KX.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.mxbase
-
-
-@dns.immutable.immutable
-class KX(dns.rdtypes.mxbase.UncompressedDowncasingMX):
- """KX record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NAPTR.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NAPTR.py
deleted file mode 100644
index 195d1cb..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NAPTR.py
+++ /dev/null
@@ -1,110 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-
-
-def _write_string(file, s):
- l = len(s)
- assert l < 256
- file.write(struct.pack("!B", l))
- file.write(s)
-
-
-@dns.immutable.immutable
-class NAPTR(dns.rdata.Rdata):
- """NAPTR record"""
-
- # see: RFC 3403
-
- __slots__ = ["order", "preference", "flags", "service", "regexp", "replacement"]
-
- def __init__(
- self, rdclass, rdtype, order, preference, flags, service, regexp, replacement
- ):
- super().__init__(rdclass, rdtype)
- self.flags = self._as_bytes(flags, True, 255)
- self.service = self._as_bytes(service, True, 255)
- self.regexp = self._as_bytes(regexp, True, 255)
- self.order = self._as_uint16(order)
- self.preference = self._as_uint16(preference)
- self.replacement = self._as_name(replacement)
-
- def to_text(self, origin=None, relativize=True, **kw):
- replacement = self.replacement.choose_relativity(origin, relativize)
- return '%d %d "%s" "%s" "%s" %s' % (
- self.order,
- self.preference,
- dns.rdata._escapify(self.flags),
- dns.rdata._escapify(self.service),
- dns.rdata._escapify(self.regexp),
- replacement,
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- order = tok.get_uint16()
- preference = tok.get_uint16()
- flags = tok.get_string()
- service = tok.get_string()
- regexp = tok.get_string()
- replacement = tok.get_name(origin, relativize, relativize_to)
- return cls(
- rdclass, rdtype, order, preference, flags, service, regexp, replacement
- )
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- two_ints = struct.pack("!HH", self.order, self.preference)
- file.write(two_ints)
- _write_string(file, self.flags)
- _write_string(file, self.service)
- _write_string(file, self.regexp)
- self.replacement.to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (order, preference) = parser.get_struct("!HH")
- strings = []
- for _ in range(3):
- s = parser.get_counted_bytes()
- strings.append(s)
- replacement = parser.get_name(origin)
- return cls(
- rdclass,
- rdtype,
- order,
- preference,
- strings[0],
- strings[1],
- strings[2],
- replacement,
- )
-
- def _processing_priority(self):
- return (self.order, self.preference)
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.priority_processing_order(iterable)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP.py
deleted file mode 100644
index a4854b3..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class NSAP(dns.rdata.Rdata):
- """NSAP record."""
-
- # see: RFC 1706
-
- __slots__ = ["address"]
-
- def __init__(self, rdclass, rdtype, address):
- super().__init__(rdclass, rdtype)
- self.address = self._as_bytes(address)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return "0x%s" % binascii.hexlify(self.address).decode()
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_string()
- if address[0:2] != "0x":
- raise dns.exception.SyntaxError("string does not start with 0x")
- address = address[2:].replace(".", "")
- if len(address) % 2 != 0:
- raise dns.exception.SyntaxError("hexstring has odd length")
- address = binascii.unhexlify(address.encode())
- return cls(rdclass, rdtype, address)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(self.address)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_remaining()
- return cls(rdclass, rdtype, address)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP_PTR.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP_PTR.py
deleted file mode 100644
index ce1c663..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/NSAP_PTR.py
+++ /dev/null
@@ -1,24 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import dns.immutable
-import dns.rdtypes.nsbase
-
-
-@dns.immutable.immutable
-class NSAP_PTR(dns.rdtypes.nsbase.UncompressedNS):
- """NSAP-PTR record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/PX.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/PX.py
deleted file mode 100644
index cdca153..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/PX.py
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class PX(dns.rdata.Rdata):
- """PX record."""
-
- # see: RFC 2163
-
- __slots__ = ["preference", "map822", "mapx400"]
-
- def __init__(self, rdclass, rdtype, preference, map822, mapx400):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- self.map822 = self._as_name(map822)
- self.mapx400 = self._as_name(mapx400)
-
- def to_text(self, origin=None, relativize=True, **kw):
- map822 = self.map822.choose_relativity(origin, relativize)
- mapx400 = self.mapx400.choose_relativity(origin, relativize)
- return "%d %s %s" % (self.preference, map822, mapx400)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- map822 = tok.get_name(origin, relativize, relativize_to)
- mapx400 = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, preference, map822, mapx400)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- pref = struct.pack("!H", self.preference)
- file.write(pref)
- self.map822.to_wire(file, None, origin, canonicalize)
- self.mapx400.to_wire(file, None, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- map822 = parser.get_name(origin)
- mapx400 = parser.get_name(origin)
- return cls(rdclass, rdtype, preference, map822, mapx400)
-
- def _processing_priority(self):
- return self.preference
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.priority_processing_order(iterable)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SRV.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SRV.py
deleted file mode 100644
index 5adef98..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SRV.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class SRV(dns.rdata.Rdata):
- """SRV record"""
-
- # see: RFC 2782
-
- __slots__ = ["priority", "weight", "port", "target"]
-
- def __init__(self, rdclass, rdtype, priority, weight, port, target):
- super().__init__(rdclass, rdtype)
- self.priority = self._as_uint16(priority)
- self.weight = self._as_uint16(weight)
- self.port = self._as_uint16(port)
- self.target = self._as_name(target)
-
- def to_text(self, origin=None, relativize=True, **kw):
- target = self.target.choose_relativity(origin, relativize)
- return "%d %d %d %s" % (self.priority, self.weight, self.port, target)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- priority = tok.get_uint16()
- weight = tok.get_uint16()
- port = tok.get_uint16()
- target = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, priority, weight, port, target)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- three_ints = struct.pack("!HHH", self.priority, self.weight, self.port)
- file.write(three_ints)
- self.target.to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- (priority, weight, port) = parser.get_struct("!HHH")
- target = parser.get_name(origin)
- return cls(rdclass, rdtype, priority, weight, port, target)
-
- def _processing_priority(self):
- return self.priority
-
- def _processing_weight(self):
- return self.weight
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.weighted_processing_order(iterable)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SVCB.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SVCB.py
deleted file mode 100644
index ff3e932..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/SVCB.py
+++ /dev/null
@@ -1,9 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import dns.immutable
-import dns.rdtypes.svcbbase
-
-
-@dns.immutable.immutable
-class SVCB(dns.rdtypes.svcbbase.SVCBBase):
- """SVCB record"""
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/WKS.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/WKS.py
deleted file mode 100644
index 881a784..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/WKS.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import socket
-import struct
-
-import dns.immutable
-import dns.ipv4
-import dns.rdata
-
-try:
- _proto_tcp = socket.getprotobyname("tcp")
- _proto_udp = socket.getprotobyname("udp")
-except OSError:
- # Fall back to defaults in case /etc/protocols is unavailable.
- _proto_tcp = 6
- _proto_udp = 17
-
-
-@dns.immutable.immutable
-class WKS(dns.rdata.Rdata):
- """WKS record"""
-
- # see: RFC 1035
-
- __slots__ = ["address", "protocol", "bitmap"]
-
- def __init__(self, rdclass, rdtype, address, protocol, bitmap):
- super().__init__(rdclass, rdtype)
- self.address = self._as_ipv4_address(address)
- self.protocol = self._as_uint8(protocol)
- self.bitmap = self._as_bytes(bitmap)
-
- def to_text(self, origin=None, relativize=True, **kw):
- bits = []
- for i, byte in enumerate(self.bitmap):
- for j in range(0, 8):
- if byte & (0x80 >> j):
- bits.append(str(i * 8 + j))
- text = " ".join(bits)
- return "%s %d %s" % (self.address, self.protocol, text)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- address = tok.get_string()
- protocol = tok.get_string()
- if protocol.isdigit():
- protocol = int(protocol)
- else:
- protocol = socket.getprotobyname(protocol)
- bitmap = bytearray()
- for token in tok.get_remaining():
- value = token.unescape().value
- if value.isdigit():
- serv = int(value)
- else:
- if protocol != _proto_udp and protocol != _proto_tcp:
- raise NotImplementedError("protocol must be TCP or UDP")
- if protocol == _proto_udp:
- protocol_text = "udp"
- else:
- protocol_text = "tcp"
- serv = socket.getservbyname(value, protocol_text)
- i = serv // 8
- l = len(bitmap)
- if l < i + 1:
- for _ in range(l, i + 1):
- bitmap.append(0)
- bitmap[i] = bitmap[i] | (0x80 >> (serv % 8))
- bitmap = dns.rdata._truncate_bitmap(bitmap)
- return cls(rdclass, rdtype, address, protocol, bitmap)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(dns.ipv4.inet_aton(self.address))
- protocol = struct.pack("!B", self.protocol)
- file.write(protocol)
- file.write(self.bitmap)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- address = parser.get_bytes(4)
- protocol = parser.get_uint8()
- bitmap = parser.get_remaining()
- return cls(rdclass, rdtype, address, protocol, bitmap)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__init__.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__init__.py
deleted file mode 100644
index dcec4dd..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__init__.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Class IN rdata type classes."""
-
-__all__ = [
- "A",
- "AAAA",
- "APL",
- "DHCID",
- "HTTPS",
- "IPSECKEY",
- "KX",
- "NAPTR",
- "NSAP",
- "NSAP_PTR",
- "PX",
- "SRV",
- "SVCB",
- "WKS",
-]
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/A.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/A.cpython-312.pyc
deleted file mode 100644
index 939d842..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/A.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/AAAA.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/AAAA.cpython-312.pyc
deleted file mode 100644
index 2d60edd..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/AAAA.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/APL.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/APL.cpython-312.pyc
deleted file mode 100644
index 731259c..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/APL.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/DHCID.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/DHCID.cpython-312.pyc
deleted file mode 100644
index 4e054de..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/DHCID.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/HTTPS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/HTTPS.cpython-312.pyc
deleted file mode 100644
index cce3ffe..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/HTTPS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/IPSECKEY.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/IPSECKEY.cpython-312.pyc
deleted file mode 100644
index 9e90265..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/IPSECKEY.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/KX.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/KX.cpython-312.pyc
deleted file mode 100644
index 459a745..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/KX.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NAPTR.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NAPTR.cpython-312.pyc
deleted file mode 100644
index 9f29bfc..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NAPTR.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP.cpython-312.pyc
deleted file mode 100644
index e03d675..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP_PTR.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP_PTR.cpython-312.pyc
deleted file mode 100644
index 92eb626..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/NSAP_PTR.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/PX.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/PX.cpython-312.pyc
deleted file mode 100644
index dec701f..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/PX.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SRV.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SRV.cpython-312.pyc
deleted file mode 100644
index f084420..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SRV.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SVCB.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SVCB.cpython-312.pyc
deleted file mode 100644
index 9ce4ca1..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/SVCB.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/WKS.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/WKS.cpython-312.pyc
deleted file mode 100644
index 50b7f79..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/WKS.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 8468c78..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/IN/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__init__.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/__init__.py
deleted file mode 100644
index 3997f84..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS rdata type classes"""
-
-__all__ = [
- "ANY",
- "IN",
- "CH",
- "dnskeybase",
- "dsbase",
- "euibase",
- "mxbase",
- "nsbase",
- "svcbbase",
- "tlsabase",
- "txtbase",
- "util",
-]
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index d4fd5a1..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dnskeybase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dnskeybase.cpython-312.pyc
deleted file mode 100644
index 0f162fa..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dnskeybase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dsbase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dsbase.cpython-312.pyc
deleted file mode 100644
index 8f45bd4..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/dsbase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/euibase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/euibase.cpython-312.pyc
deleted file mode 100644
index ad19cf7..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/euibase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/mxbase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/mxbase.cpython-312.pyc
deleted file mode 100644
index 682bfae..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/mxbase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/nsbase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/nsbase.cpython-312.pyc
deleted file mode 100644
index d4851f7..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/nsbase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/svcbbase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/svcbbase.cpython-312.pyc
deleted file mode 100644
index bc9f325..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/svcbbase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/tlsabase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/tlsabase.cpython-312.pyc
deleted file mode 100644
index 59e9f40..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/tlsabase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/txtbase.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/txtbase.cpython-312.pyc
deleted file mode 100644
index 91c884b..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/txtbase.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/util.cpython-312.pyc
deleted file mode 100644
index 29b293a..0000000
Binary files a/.venv/lib/python3.12/site-packages/dns/rdtypes/__pycache__/util.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/dnskeybase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/dnskeybase.py
deleted file mode 100644
index db300f8..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/dnskeybase.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2004-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import base64
-import enum
-import struct
-
-import dns.dnssectypes
-import dns.exception
-import dns.immutable
-import dns.rdata
-
-# wildcard import
-__all__ = ["SEP", "REVOKE", "ZONE"] # noqa: F822
-
-
-class Flag(enum.IntFlag):
- SEP = 0x0001
- REVOKE = 0x0080
- ZONE = 0x0100
-
-
-@dns.immutable.immutable
-class DNSKEYBase(dns.rdata.Rdata):
- """Base class for rdata that is like a DNSKEY record"""
-
- __slots__ = ["flags", "protocol", "algorithm", "key"]
-
- def __init__(self, rdclass, rdtype, flags, protocol, algorithm, key):
- super().__init__(rdclass, rdtype)
- self.flags = Flag(self._as_uint16(flags))
- self.protocol = self._as_uint8(protocol)
- self.algorithm = dns.dnssectypes.Algorithm.make(algorithm)
- self.key = self._as_bytes(key)
-
- def to_text(self, origin=None, relativize=True, **kw):
- return "%d %d %d %s" % (
- self.flags,
- self.protocol,
- self.algorithm,
- dns.rdata._base64ify(self.key, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- flags = tok.get_uint16()
- protocol = tok.get_uint8()
- algorithm = tok.get_string()
- b64 = tok.concatenate_remaining_identifiers().encode()
- key = base64.b64decode(b64)
- return cls(rdclass, rdtype, flags, protocol, algorithm, key)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!HBB", self.flags, self.protocol, self.algorithm)
- file.write(header)
- file.write(self.key)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("!HBB")
- key = parser.get_remaining()
- return cls(rdclass, rdtype, header[0], header[1], header[2], key)
-
-
-### BEGIN generated Flag constants
-
-SEP = Flag.SEP
-REVOKE = Flag.REVOKE
-ZONE = Flag.ZONE
-
-### END generated Flag constants
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/dsbase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/dsbase.py
deleted file mode 100644
index cd21f02..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/dsbase.py
+++ /dev/null
@@ -1,85 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2010, 2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-import struct
-
-import dns.dnssectypes
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-
-
-@dns.immutable.immutable
-class DSBase(dns.rdata.Rdata):
- """Base class for rdata that is like a DS record"""
-
- __slots__ = ["key_tag", "algorithm", "digest_type", "digest"]
-
- # Digest types registry:
- # https://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml
- _digest_length_by_type = {
- 1: 20, # SHA-1, RFC 3658 Sec. 2.4
- 2: 32, # SHA-256, RFC 4509 Sec. 2.2
- 3: 32, # GOST R 34.11-94, RFC 5933 Sec. 4 in conjunction with RFC 4490 Sec. 2.1
- 4: 48, # SHA-384, RFC 6605 Sec. 2
- }
-
- def __init__(self, rdclass, rdtype, key_tag, algorithm, digest_type, digest):
- super().__init__(rdclass, rdtype)
- self.key_tag = self._as_uint16(key_tag)
- self.algorithm = dns.dnssectypes.Algorithm.make(algorithm)
- self.digest_type = dns.dnssectypes.DSDigest.make(self._as_uint8(digest_type))
- self.digest = self._as_bytes(digest)
- try:
- if len(self.digest) != self._digest_length_by_type[self.digest_type]:
- raise ValueError("digest length inconsistent with digest type")
- except KeyError:
- if self.digest_type == 0: # reserved, RFC 3658 Sec. 2.4
- raise ValueError("digest type 0 is reserved")
-
- def to_text(self, origin=None, relativize=True, **kw):
- kw = kw.copy()
- chunksize = kw.pop("chunksize", 128)
- return "%d %d %d %s" % (
- self.key_tag,
- self.algorithm,
- self.digest_type,
- dns.rdata._hexify(self.digest, chunksize=chunksize, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- key_tag = tok.get_uint16()
- algorithm = tok.get_string()
- digest_type = tok.get_uint8()
- digest = tok.concatenate_remaining_identifiers().encode()
- digest = binascii.unhexlify(digest)
- return cls(rdclass, rdtype, key_tag, algorithm, digest_type, digest)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!HBB", self.key_tag, self.algorithm, self.digest_type)
- file.write(header)
- file.write(self.digest)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("!HBB")
- digest = parser.get_remaining()
- return cls(rdclass, rdtype, header[0], header[1], header[2], digest)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/euibase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/euibase.py
deleted file mode 100644
index 751087b..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/euibase.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (C) 2015 Red Hat, Inc.
-# Author: Petr Spacek
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED 'AS IS' AND RED HAT DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-
-import dns.immutable
-import dns.rdata
-
-
-@dns.immutable.immutable
-class EUIBase(dns.rdata.Rdata):
- """EUIxx record"""
-
- # see: rfc7043.txt
-
- __slots__ = ["eui"]
- # define these in subclasses
- # byte_len = 6 # 0123456789ab (in hex)
- # text_len = byte_len * 3 - 1 # 01-23-45-67-89-ab
-
- def __init__(self, rdclass, rdtype, eui):
- super().__init__(rdclass, rdtype)
- self.eui = self._as_bytes(eui)
- if len(self.eui) != self.byte_len:
- raise dns.exception.FormError(
- "EUI%s rdata has to have %s bytes" % (self.byte_len * 8, self.byte_len)
- )
-
- def to_text(self, origin=None, relativize=True, **kw):
- return dns.rdata._hexify(self.eui, chunksize=2, separator=b"-", **kw)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- text = tok.get_string()
- if len(text) != cls.text_len:
- raise dns.exception.SyntaxError(
- "Input text must have %s characters" % cls.text_len
- )
- for i in range(2, cls.byte_len * 3 - 1, 3):
- if text[i] != "-":
- raise dns.exception.SyntaxError("Dash expected at position %s" % i)
- text = text.replace("-", "")
- try:
- data = binascii.unhexlify(text.encode())
- except (ValueError, TypeError) as ex:
- raise dns.exception.SyntaxError("Hex decoding error: %s" % str(ex))
- return cls(rdclass, rdtype, data)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(self.eui)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- eui = parser.get_bytes(cls.byte_len)
- return cls(rdclass, rdtype, eui)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/mxbase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/mxbase.py
deleted file mode 100644
index 6d5e3d8..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/mxbase.py
+++ /dev/null
@@ -1,87 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""MX-like base classes."""
-
-import struct
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-
-
-@dns.immutable.immutable
-class MXBase(dns.rdata.Rdata):
- """Base class for rdata that is like an MX record."""
-
- __slots__ = ["preference", "exchange"]
-
- def __init__(self, rdclass, rdtype, preference, exchange):
- super().__init__(rdclass, rdtype)
- self.preference = self._as_uint16(preference)
- self.exchange = self._as_name(exchange)
-
- def to_text(self, origin=None, relativize=True, **kw):
- exchange = self.exchange.choose_relativity(origin, relativize)
- return "%d %s" % (self.preference, exchange)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- preference = tok.get_uint16()
- exchange = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, preference, exchange)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- pref = struct.pack("!H", self.preference)
- file.write(pref)
- self.exchange.to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- preference = parser.get_uint16()
- exchange = parser.get_name(origin)
- return cls(rdclass, rdtype, preference, exchange)
-
- def _processing_priority(self):
- return self.preference
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.priority_processing_order(iterable)
-
-
-@dns.immutable.immutable
-class UncompressedMX(MXBase):
- """Base class for rdata that is like an MX record, but whose name
- is not compressed when converted to DNS wire format, and whose
- digestable form is not downcased."""
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- super()._to_wire(file, None, origin, False)
-
-
-@dns.immutable.immutable
-class UncompressedDowncasingMX(MXBase):
- """Base class for rdata that is like an MX record, but whose name
- is not compressed when convert to DNS wire format."""
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- super()._to_wire(file, None, origin, canonicalize)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/nsbase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/nsbase.py
deleted file mode 100644
index 904224f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/nsbase.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""NS-like base classes."""
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.rdata
-
-
-@dns.immutable.immutable
-class NSBase(dns.rdata.Rdata):
- """Base class for rdata that is like an NS record."""
-
- __slots__ = ["target"]
-
- def __init__(self, rdclass, rdtype, target):
- super().__init__(rdclass, rdtype)
- self.target = self._as_name(target)
-
- def to_text(self, origin=None, relativize=True, **kw):
- target = self.target.choose_relativity(origin, relativize)
- return str(target)
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- target = tok.get_name(origin, relativize, relativize_to)
- return cls(rdclass, rdtype, target)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.target.to_wire(file, compress, origin, canonicalize)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- target = parser.get_name(origin)
- return cls(rdclass, rdtype, target)
-
-
-@dns.immutable.immutable
-class UncompressedNS(NSBase):
- """Base class for rdata that is like an NS record, but whose name
- is not compressed when convert to DNS wire format, and whose
- digestable form is not downcased."""
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- self.target.to_wire(file, None, origin, False)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/svcbbase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/svcbbase.py
deleted file mode 100644
index 0565241..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/svcbbase.py
+++ /dev/null
@@ -1,553 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import base64
-import enum
-import struct
-
-import dns.enum
-import dns.exception
-import dns.immutable
-import dns.ipv4
-import dns.ipv6
-import dns.name
-import dns.rdata
-import dns.rdtypes.util
-import dns.renderer
-import dns.tokenizer
-import dns.wire
-
-# Until there is an RFC, this module is experimental and may be changed in
-# incompatible ways.
-
-
-class UnknownParamKey(dns.exception.DNSException):
- """Unknown SVCB ParamKey"""
-
-
-class ParamKey(dns.enum.IntEnum):
- """SVCB ParamKey"""
-
- MANDATORY = 0
- ALPN = 1
- NO_DEFAULT_ALPN = 2
- PORT = 3
- IPV4HINT = 4
- ECH = 5
- IPV6HINT = 6
- DOHPATH = 7
-
- @classmethod
- def _maximum(cls):
- return 65535
-
- @classmethod
- def _short_name(cls):
- return "SVCBParamKey"
-
- @classmethod
- def _prefix(cls):
- return "KEY"
-
- @classmethod
- def _unknown_exception_class(cls):
- return UnknownParamKey
-
-
-class Emptiness(enum.IntEnum):
- NEVER = 0
- ALWAYS = 1
- ALLOWED = 2
-
-
-def _validate_key(key):
- force_generic = False
- if isinstance(key, bytes):
- # We decode to latin-1 so we get 0-255 as valid and do NOT interpret
- # UTF-8 sequences
- key = key.decode("latin-1")
- if isinstance(key, str):
- if key.lower().startswith("key"):
- force_generic = True
- if key[3:].startswith("0") and len(key) != 4:
- # key has leading zeros
- raise ValueError("leading zeros in key")
- key = key.replace("-", "_")
- return (ParamKey.make(key), force_generic)
-
-
-def key_to_text(key):
- return ParamKey.to_text(key).replace("_", "-").lower()
-
-
-# Like rdata escapify, but escapes ',' too.
-
-_escaped = b'",\\'
-
-
-def _escapify(qstring):
- text = ""
- for c in qstring:
- if c in _escaped:
- text += "\\" + chr(c)
- elif c >= 0x20 and c < 0x7F:
- text += chr(c)
- else:
- text += "\\%03d" % c
- return text
-
-
-def _unescape(value):
- if value == "":
- return value
- unescaped = b""
- l = len(value)
- i = 0
- while i < l:
- c = value[i]
- i += 1
- if c == "\\":
- if i >= l: # pragma: no cover (can't happen via tokenizer get())
- raise dns.exception.UnexpectedEnd
- c = value[i]
- i += 1
- if c.isdigit():
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c2 = value[i]
- i += 1
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c3 = value[i]
- i += 1
- if not (c2.isdigit() and c3.isdigit()):
- raise dns.exception.SyntaxError
- codepoint = int(c) * 100 + int(c2) * 10 + int(c3)
- if codepoint > 255:
- raise dns.exception.SyntaxError
- unescaped += b"%c" % (codepoint)
- continue
- unescaped += c.encode()
- return unescaped
-
-
-def _split(value):
- l = len(value)
- i = 0
- items = []
- unescaped = b""
- while i < l:
- c = value[i]
- i += 1
- if c == ord("\\"):
- if i >= l: # pragma: no cover (can't happen via tokenizer get())
- raise dns.exception.UnexpectedEnd
- c = value[i]
- i += 1
- unescaped += b"%c" % (c)
- elif c == ord(","):
- items.append(unescaped)
- unescaped = b""
- else:
- unescaped += b"%c" % (c)
- items.append(unescaped)
- return items
-
-
-@dns.immutable.immutable
-class Param:
- """Abstract base class for SVCB parameters"""
-
- @classmethod
- def emptiness(cls):
- return Emptiness.NEVER
-
-
-@dns.immutable.immutable
-class GenericParam(Param):
- """Generic SVCB parameter"""
-
- def __init__(self, value):
- self.value = dns.rdata.Rdata._as_bytes(value, True)
-
- @classmethod
- def emptiness(cls):
- return Emptiness.ALLOWED
-
- @classmethod
- def from_value(cls, value):
- if value is None or len(value) == 0:
- return None
- else:
- return cls(_unescape(value))
-
- def to_text(self):
- return '"' + dns.rdata._escapify(self.value) + '"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- value = parser.get_bytes(parser.remaining())
- if len(value) == 0:
- return None
- else:
- return cls(value)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- file.write(self.value)
-
-
-@dns.immutable.immutable
-class MandatoryParam(Param):
- def __init__(self, keys):
- # check for duplicates
- keys = sorted([_validate_key(key)[0] for key in keys])
- prior_k = None
- for k in keys:
- if k == prior_k:
- raise ValueError(f"duplicate key {k:d}")
- prior_k = k
- if k == ParamKey.MANDATORY:
- raise ValueError("listed the mandatory key as mandatory")
- self.keys = tuple(keys)
-
- @classmethod
- def from_value(cls, value):
- keys = [k.encode() for k in value.split(",")]
- return cls(keys)
-
- def to_text(self):
- return '"' + ",".join([key_to_text(key) for key in self.keys]) + '"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- keys = []
- last_key = -1
- while parser.remaining() > 0:
- key = parser.get_uint16()
- if key < last_key:
- raise dns.exception.FormError("manadatory keys not ascending")
- last_key = key
- keys.append(key)
- return cls(keys)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- for key in self.keys:
- file.write(struct.pack("!H", key))
-
-
-@dns.immutable.immutable
-class ALPNParam(Param):
- def __init__(self, ids):
- self.ids = dns.rdata.Rdata._as_tuple(
- ids, lambda x: dns.rdata.Rdata._as_bytes(x, True, 255, False)
- )
-
- @classmethod
- def from_value(cls, value):
- return cls(_split(_unescape(value)))
-
- def to_text(self):
- value = ",".join([_escapify(id) for id in self.ids])
- return '"' + dns.rdata._escapify(value.encode()) + '"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- ids = []
- while parser.remaining() > 0:
- id = parser.get_counted_bytes()
- ids.append(id)
- return cls(ids)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- for id in self.ids:
- file.write(struct.pack("!B", len(id)))
- file.write(id)
-
-
-@dns.immutable.immutable
-class NoDefaultALPNParam(Param):
- # We don't ever expect to instantiate this class, but we need
- # a from_value() and a from_wire_parser(), so we just return None
- # from the class methods when things are OK.
-
- @classmethod
- def emptiness(cls):
- return Emptiness.ALWAYS
-
- @classmethod
- def from_value(cls, value):
- if value is None or value == "":
- return None
- else:
- raise ValueError("no-default-alpn with non-empty value")
-
- def to_text(self):
- raise NotImplementedError # pragma: no cover
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- if parser.remaining() != 0:
- raise dns.exception.FormError
- return None
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- raise NotImplementedError # pragma: no cover
-
-
-@dns.immutable.immutable
-class PortParam(Param):
- def __init__(self, port):
- self.port = dns.rdata.Rdata._as_uint16(port)
-
- @classmethod
- def from_value(cls, value):
- value = int(value)
- return cls(value)
-
- def to_text(self):
- return f'"{self.port}"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- port = parser.get_uint16()
- return cls(port)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- file.write(struct.pack("!H", self.port))
-
-
-@dns.immutable.immutable
-class IPv4HintParam(Param):
- def __init__(self, addresses):
- self.addresses = dns.rdata.Rdata._as_tuple(
- addresses, dns.rdata.Rdata._as_ipv4_address
- )
-
- @classmethod
- def from_value(cls, value):
- addresses = value.split(",")
- return cls(addresses)
-
- def to_text(self):
- return '"' + ",".join(self.addresses) + '"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- addresses = []
- while parser.remaining() > 0:
- ip = parser.get_bytes(4)
- addresses.append(dns.ipv4.inet_ntoa(ip))
- return cls(addresses)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- for address in self.addresses:
- file.write(dns.ipv4.inet_aton(address))
-
-
-@dns.immutable.immutable
-class IPv6HintParam(Param):
- def __init__(self, addresses):
- self.addresses = dns.rdata.Rdata._as_tuple(
- addresses, dns.rdata.Rdata._as_ipv6_address
- )
-
- @classmethod
- def from_value(cls, value):
- addresses = value.split(",")
- return cls(addresses)
-
- def to_text(self):
- return '"' + ",".join(self.addresses) + '"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- addresses = []
- while parser.remaining() > 0:
- ip = parser.get_bytes(16)
- addresses.append(dns.ipv6.inet_ntoa(ip))
- return cls(addresses)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- for address in self.addresses:
- file.write(dns.ipv6.inet_aton(address))
-
-
-@dns.immutable.immutable
-class ECHParam(Param):
- def __init__(self, ech):
- self.ech = dns.rdata.Rdata._as_bytes(ech, True)
-
- @classmethod
- def from_value(cls, value):
- if "\\" in value:
- raise ValueError("escape in ECH value")
- value = base64.b64decode(value.encode())
- return cls(value)
-
- def to_text(self):
- b64 = base64.b64encode(self.ech).decode("ascii")
- return f'"{b64}"'
-
- @classmethod
- def from_wire_parser(cls, parser, origin=None): # pylint: disable=W0613
- value = parser.get_bytes(parser.remaining())
- return cls(value)
-
- def to_wire(self, file, origin=None): # pylint: disable=W0613
- file.write(self.ech)
-
-
-_class_for_key = {
- ParamKey.MANDATORY: MandatoryParam,
- ParamKey.ALPN: ALPNParam,
- ParamKey.NO_DEFAULT_ALPN: NoDefaultALPNParam,
- ParamKey.PORT: PortParam,
- ParamKey.IPV4HINT: IPv4HintParam,
- ParamKey.ECH: ECHParam,
- ParamKey.IPV6HINT: IPv6HintParam,
-}
-
-
-def _validate_and_define(params, key, value):
- (key, force_generic) = _validate_key(_unescape(key))
- if key in params:
- raise SyntaxError(f'duplicate key "{key:d}"')
- cls = _class_for_key.get(key, GenericParam)
- emptiness = cls.emptiness()
- if value is None:
- if emptiness == Emptiness.NEVER:
- raise SyntaxError("value cannot be empty")
- value = cls.from_value(value)
- else:
- if force_generic:
- value = cls.from_wire_parser(dns.wire.Parser(_unescape(value)))
- else:
- value = cls.from_value(value)
- params[key] = value
-
-
-@dns.immutable.immutable
-class SVCBBase(dns.rdata.Rdata):
- """Base class for SVCB-like records"""
-
- # see: draft-ietf-dnsop-svcb-https-11
-
- __slots__ = ["priority", "target", "params"]
-
- def __init__(self, rdclass, rdtype, priority, target, params):
- super().__init__(rdclass, rdtype)
- self.priority = self._as_uint16(priority)
- self.target = self._as_name(target)
- for k, v in params.items():
- k = ParamKey.make(k)
- if not isinstance(v, Param) and v is not None:
- raise ValueError(f"{k:d} not a Param")
- self.params = dns.immutable.Dict(params)
- # Make sure any parameter listed as mandatory is present in the
- # record.
- mandatory = params.get(ParamKey.MANDATORY)
- if mandatory:
- for key in mandatory.keys:
- # Note we have to say "not in" as we have None as a value
- # so a get() and a not None test would be wrong.
- if key not in params:
- raise ValueError(f"key {key:d} declared mandatory but not present")
- # The no-default-alpn parameter requires the alpn parameter.
- if ParamKey.NO_DEFAULT_ALPN in params:
- if ParamKey.ALPN not in params:
- raise ValueError("no-default-alpn present, but alpn missing")
-
- def to_text(self, origin=None, relativize=True, **kw):
- target = self.target.choose_relativity(origin, relativize)
- params = []
- for key in sorted(self.params.keys()):
- value = self.params[key]
- if value is None:
- params.append(key_to_text(key))
- else:
- kv = key_to_text(key) + "=" + value.to_text()
- params.append(kv)
- if len(params) > 0:
- space = " "
- else:
- space = ""
- return "%d %s%s%s" % (self.priority, target, space, " ".join(params))
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- priority = tok.get_uint16()
- target = tok.get_name(origin, relativize, relativize_to)
- if priority == 0:
- token = tok.get()
- if not token.is_eol_or_eof():
- raise SyntaxError("parameters in AliasMode")
- tok.unget(token)
- params = {}
- while True:
- token = tok.get()
- if token.is_eol_or_eof():
- tok.unget(token)
- break
- if token.ttype != dns.tokenizer.IDENTIFIER:
- raise SyntaxError("parameter is not an identifier")
- equals = token.value.find("=")
- if equals == len(token.value) - 1:
- # 'key=', so next token should be a quoted string without
- # any intervening whitespace.
- key = token.value[:-1]
- token = tok.get(want_leading=True)
- if token.ttype != dns.tokenizer.QUOTED_STRING:
- raise SyntaxError("whitespace after =")
- value = token.value
- elif equals > 0:
- # key=value
- key = token.value[:equals]
- value = token.value[equals + 1 :]
- elif equals == 0:
- # =key
- raise SyntaxError('parameter cannot start with "="')
- else:
- # key
- key = token.value
- value = None
- _validate_and_define(params, key, value)
- return cls(rdclass, rdtype, priority, target, params)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- file.write(struct.pack("!H", self.priority))
- self.target.to_wire(file, None, origin, False)
- for key in sorted(self.params):
- file.write(struct.pack("!H", key))
- value = self.params[key]
- with dns.renderer.prefixed_length(file, 2):
- # Note that we're still writing a length of zero if the value is None
- if value is not None:
- value.to_wire(file, origin)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- priority = parser.get_uint16()
- target = parser.get_name(origin)
- if priority == 0 and parser.remaining() != 0:
- raise dns.exception.FormError("parameters in AliasMode")
- params = {}
- prior_key = -1
- while parser.remaining() > 0:
- key = parser.get_uint16()
- if key < prior_key:
- raise dns.exception.FormError("keys not in order")
- prior_key = key
- vlen = parser.get_uint16()
- pcls = _class_for_key.get(key, GenericParam)
- with parser.restrict_to(vlen):
- value = pcls.from_wire_parser(parser, origin)
- params[key] = value
- return cls(rdclass, rdtype, priority, target, params)
-
- def _processing_priority(self):
- return self.priority
-
- @classmethod
- def _processing_order(cls, iterable):
- return dns.rdtypes.util.priority_processing_order(iterable)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/tlsabase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/tlsabase.py
deleted file mode 100644
index a059d2c..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/tlsabase.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2005-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import binascii
-import struct
-
-import dns.immutable
-import dns.rdata
-import dns.rdatatype
-
-
-@dns.immutable.immutable
-class TLSABase(dns.rdata.Rdata):
- """Base class for TLSA and SMIMEA records"""
-
- # see: RFC 6698
-
- __slots__ = ["usage", "selector", "mtype", "cert"]
-
- def __init__(self, rdclass, rdtype, usage, selector, mtype, cert):
- super().__init__(rdclass, rdtype)
- self.usage = self._as_uint8(usage)
- self.selector = self._as_uint8(selector)
- self.mtype = self._as_uint8(mtype)
- self.cert = self._as_bytes(cert)
-
- def to_text(self, origin=None, relativize=True, **kw):
- kw = kw.copy()
- chunksize = kw.pop("chunksize", 128)
- return "%d %d %d %s" % (
- self.usage,
- self.selector,
- self.mtype,
- dns.rdata._hexify(self.cert, chunksize=chunksize, **kw),
- )
-
- @classmethod
- def from_text(
- cls, rdclass, rdtype, tok, origin=None, relativize=True, relativize_to=None
- ):
- usage = tok.get_uint8()
- selector = tok.get_uint8()
- mtype = tok.get_uint8()
- cert = tok.concatenate_remaining_identifiers().encode()
- cert = binascii.unhexlify(cert)
- return cls(rdclass, rdtype, usage, selector, mtype, cert)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- header = struct.pack("!BBB", self.usage, self.selector, self.mtype)
- file.write(header)
- file.write(self.cert)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- header = parser.get_struct("BBB")
- cert = parser.get_remaining()
- return cls(rdclass, rdtype, header[0], header[1], header[2], cert)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/txtbase.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/txtbase.py
deleted file mode 100644
index 44d6df5..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/txtbase.py
+++ /dev/null
@@ -1,104 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""TXT-like base class."""
-
-from typing import Any, Dict, Iterable, Optional, Tuple, Union
-
-import dns.exception
-import dns.immutable
-import dns.rdata
-import dns.renderer
-import dns.tokenizer
-
-
-@dns.immutable.immutable
-class TXTBase(dns.rdata.Rdata):
- """Base class for rdata that is like a TXT record (see RFC 1035)."""
-
- __slots__ = ["strings"]
-
- def __init__(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- strings: Iterable[Union[bytes, str]],
- ):
- """Initialize a TXT-like rdata.
-
- *rdclass*, an ``int`` is the rdataclass of the Rdata.
-
- *rdtype*, an ``int`` is the rdatatype of the Rdata.
-
- *strings*, a tuple of ``bytes``
- """
- super().__init__(rdclass, rdtype)
- self.strings: Tuple[bytes] = self._as_tuple(
- strings, lambda x: self._as_bytes(x, True, 255)
- )
-
- def to_text(
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- **kw: Dict[str, Any],
- ) -> str:
- txt = ""
- prefix = ""
- for s in self.strings:
- txt += '{}"{}"'.format(prefix, dns.rdata._escapify(s))
- prefix = " "
- return txt
-
- @classmethod
- def from_text(
- cls,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- tok: dns.tokenizer.Tokenizer,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
- ) -> dns.rdata.Rdata:
- strings = []
- for token in tok.get_remaining():
- token = token.unescape_to_bytes()
- # The 'if' below is always true in the current code, but we
- # are leaving this check in in case things change some day.
- if not (
- token.is_quoted_string() or token.is_identifier()
- ): # pragma: no cover
- raise dns.exception.SyntaxError("expected a string")
- if len(token.value) > 255:
- raise dns.exception.SyntaxError("string too long")
- strings.append(token.value)
- if len(strings) == 0:
- raise dns.exception.UnexpectedEnd
- return cls(rdclass, rdtype, strings)
-
- def _to_wire(self, file, compress=None, origin=None, canonicalize=False):
- for s in self.strings:
- with dns.renderer.prefixed_length(file, 1):
- file.write(s)
-
- @classmethod
- def from_wire_parser(cls, rdclass, rdtype, parser, origin=None):
- strings = []
- while parser.remaining() > 0:
- s = parser.get_counted_bytes()
- strings.append(s)
- return cls(rdclass, rdtype, strings)
diff --git a/.venv/lib/python3.12/site-packages/dns/rdtypes/util.py b/.venv/lib/python3.12/site-packages/dns/rdtypes/util.py
deleted file mode 100644
index 54908fd..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rdtypes/util.py
+++ /dev/null
@@ -1,257 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006, 2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import collections
-import random
-import struct
-from typing import Any, List
-
-import dns.exception
-import dns.ipv4
-import dns.ipv6
-import dns.name
-import dns.rdata
-
-
-class Gateway:
- """A helper class for the IPSECKEY gateway and AMTRELAY relay fields"""
-
- name = ""
-
- def __init__(self, type, gateway=None):
- self.type = dns.rdata.Rdata._as_uint8(type)
- self.gateway = gateway
- self._check()
-
- @classmethod
- def _invalid_type(cls, gateway_type):
- return f"invalid {cls.name} type: {gateway_type}"
-
- def _check(self):
- if self.type == 0:
- if self.gateway not in (".", None):
- raise SyntaxError(f"invalid {self.name} for type 0")
- self.gateway = None
- elif self.type == 1:
- # check that it's OK
- dns.ipv4.inet_aton(self.gateway)
- elif self.type == 2:
- # check that it's OK
- dns.ipv6.inet_aton(self.gateway)
- elif self.type == 3:
- if not isinstance(self.gateway, dns.name.Name):
- raise SyntaxError(f"invalid {self.name}; not a name")
- else:
- raise SyntaxError(self._invalid_type(self.type))
-
- def to_text(self, origin=None, relativize=True):
- if self.type == 0:
- return "."
- elif self.type in (1, 2):
- return self.gateway
- elif self.type == 3:
- return str(self.gateway.choose_relativity(origin, relativize))
- else:
- raise ValueError(self._invalid_type(self.type)) # pragma: no cover
-
- @classmethod
- def from_text(
- cls, gateway_type, tok, origin=None, relativize=True, relativize_to=None
- ):
- if gateway_type in (0, 1, 2):
- gateway = tok.get_string()
- elif gateway_type == 3:
- gateway = tok.get_name(origin, relativize, relativize_to)
- else:
- raise dns.exception.SyntaxError(
- cls._invalid_type(gateway_type)
- ) # pragma: no cover
- return cls(gateway_type, gateway)
-
- # pylint: disable=unused-argument
- def to_wire(self, file, compress=None, origin=None, canonicalize=False):
- if self.type == 0:
- pass
- elif self.type == 1:
- file.write(dns.ipv4.inet_aton(self.gateway))
- elif self.type == 2:
- file.write(dns.ipv6.inet_aton(self.gateway))
- elif self.type == 3:
- self.gateway.to_wire(file, None, origin, False)
- else:
- raise ValueError(self._invalid_type(self.type)) # pragma: no cover
-
- # pylint: enable=unused-argument
-
- @classmethod
- def from_wire_parser(cls, gateway_type, parser, origin=None):
- if gateway_type == 0:
- gateway = None
- elif gateway_type == 1:
- gateway = dns.ipv4.inet_ntoa(parser.get_bytes(4))
- elif gateway_type == 2:
- gateway = dns.ipv6.inet_ntoa(parser.get_bytes(16))
- elif gateway_type == 3:
- gateway = parser.get_name(origin)
- else:
- raise dns.exception.FormError(cls._invalid_type(gateway_type))
- return cls(gateway_type, gateway)
-
-
-class Bitmap:
- """A helper class for the NSEC/NSEC3/CSYNC type bitmaps"""
-
- type_name = ""
-
- def __init__(self, windows=None):
- last_window = -1
- self.windows = windows
- for window, bitmap in self.windows:
- if not isinstance(window, int):
- raise ValueError(f"bad {self.type_name} window type")
- if window <= last_window:
- raise ValueError(f"bad {self.type_name} window order")
- if window > 256:
- raise ValueError(f"bad {self.type_name} window number")
- last_window = window
- if not isinstance(bitmap, bytes):
- raise ValueError(f"bad {self.type_name} octets type")
- if len(bitmap) == 0 or len(bitmap) > 32:
- raise ValueError(f"bad {self.type_name} octets")
-
- def to_text(self) -> str:
- text = ""
- for window, bitmap in self.windows:
- bits = []
- for i, byte in enumerate(bitmap):
- for j in range(0, 8):
- if byte & (0x80 >> j):
- rdtype = window * 256 + i * 8 + j
- bits.append(dns.rdatatype.to_text(rdtype))
- text += " " + " ".join(bits)
- return text
-
- @classmethod
- def from_text(cls, tok: "dns.tokenizer.Tokenizer") -> "Bitmap":
- rdtypes = []
- for token in tok.get_remaining():
- rdtype = dns.rdatatype.from_text(token.unescape().value)
- if rdtype == 0:
- raise dns.exception.SyntaxError(f"{cls.type_name} with bit 0")
- rdtypes.append(rdtype)
- return cls.from_rdtypes(rdtypes)
-
- @classmethod
- def from_rdtypes(cls, rdtypes: List[dns.rdatatype.RdataType]) -> "Bitmap":
- rdtypes = sorted(rdtypes)
- window = 0
- octets = 0
- prior_rdtype = 0
- bitmap = bytearray(b"\0" * 32)
- windows = []
- for rdtype in rdtypes:
- if rdtype == prior_rdtype:
- continue
- prior_rdtype = rdtype
- new_window = rdtype // 256
- if new_window != window:
- if octets != 0:
- windows.append((window, bytes(bitmap[0:octets])))
- bitmap = bytearray(b"\0" * 32)
- window = new_window
- offset = rdtype % 256
- byte = offset // 8
- bit = offset % 8
- octets = byte + 1
- bitmap[byte] = bitmap[byte] | (0x80 >> bit)
- if octets != 0:
- windows.append((window, bytes(bitmap[0:octets])))
- return cls(windows)
-
- def to_wire(self, file: Any) -> None:
- for window, bitmap in self.windows:
- file.write(struct.pack("!BB", window, len(bitmap)))
- file.write(bitmap)
-
- @classmethod
- def from_wire_parser(cls, parser: "dns.wire.Parser") -> "Bitmap":
- windows = []
- while parser.remaining() > 0:
- window = parser.get_uint8()
- bitmap = parser.get_counted_bytes()
- windows.append((window, bitmap))
- return cls(windows)
-
-
-def _priority_table(items):
- by_priority = collections.defaultdict(list)
- for rdata in items:
- by_priority[rdata._processing_priority()].append(rdata)
- return by_priority
-
-
-def priority_processing_order(iterable):
- items = list(iterable)
- if len(items) == 1:
- return items
- by_priority = _priority_table(items)
- ordered = []
- for k in sorted(by_priority.keys()):
- rdatas = by_priority[k]
- random.shuffle(rdatas)
- ordered.extend(rdatas)
- return ordered
-
-
-_no_weight = 0.1
-
-
-def weighted_processing_order(iterable):
- items = list(iterable)
- if len(items) == 1:
- return items
- by_priority = _priority_table(items)
- ordered = []
- for k in sorted(by_priority.keys()):
- rdatas = by_priority[k]
- total = sum(rdata._processing_weight() or _no_weight for rdata in rdatas)
- while len(rdatas) > 1:
- r = random.uniform(0, total)
- for n, rdata in enumerate(rdatas):
- weight = rdata._processing_weight() or _no_weight
- if weight > r:
- break
- r -= weight
- total -= weight
- ordered.append(rdata) # pylint: disable=undefined-loop-variable
- del rdatas[n] # pylint: disable=undefined-loop-variable
- ordered.append(rdatas[0])
- return ordered
-
-
-def parse_formatted_hex(formatted, num_chunks, chunk_size, separator):
- if len(formatted) != num_chunks * (chunk_size + 1) - 1:
- raise ValueError("invalid formatted hex string")
- value = b""
- for _ in range(num_chunks):
- chunk = formatted[0:chunk_size]
- value += int(chunk, 16).to_bytes(chunk_size // 2, "big")
- formatted = formatted[chunk_size:]
- if len(formatted) > 0 and formatted[0] != separator:
- raise ValueError("invalid formatted hex string")
- formatted = formatted[1:]
- return value
diff --git a/.venv/lib/python3.12/site-packages/dns/renderer.py b/.venv/lib/python3.12/site-packages/dns/renderer.py
deleted file mode 100644
index a77481f..0000000
--- a/.venv/lib/python3.12/site-packages/dns/renderer.py
+++ /dev/null
@@ -1,346 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Help for building DNS wire format messages"""
-
-import contextlib
-import io
-import random
-import struct
-import time
-
-import dns.exception
-import dns.tsig
-
-QUESTION = 0
-ANSWER = 1
-AUTHORITY = 2
-ADDITIONAL = 3
-
-
-@contextlib.contextmanager
-def prefixed_length(output, length_length):
- output.write(b"\00" * length_length)
- start = output.tell()
- yield
- end = output.tell()
- length = end - start
- if length > 0:
- try:
- output.seek(start - length_length)
- try:
- output.write(length.to_bytes(length_length, "big"))
- except OverflowError:
- raise dns.exception.FormError
- finally:
- output.seek(end)
-
-
-class Renderer:
- """Helper class for building DNS wire-format messages.
-
- Most applications can use the higher-level L{dns.message.Message}
- class and its to_wire() method to generate wire-format messages.
- This class is for those applications which need finer control
- over the generation of messages.
-
- Typical use::
-
- r = dns.renderer.Renderer(id=1, flags=0x80, max_size=512)
- r.add_question(qname, qtype, qclass)
- r.add_rrset(dns.renderer.ANSWER, rrset_1)
- r.add_rrset(dns.renderer.ANSWER, rrset_2)
- r.add_rrset(dns.renderer.AUTHORITY, ns_rrset)
- r.add_rrset(dns.renderer.ADDITIONAL, ad_rrset_1)
- r.add_rrset(dns.renderer.ADDITIONAL, ad_rrset_2)
- r.add_edns(0, 0, 4096)
- r.write_header()
- r.add_tsig(keyname, secret, 300, 1, 0, '', request_mac)
- wire = r.get_wire()
-
- If padding is going to be used, then the OPT record MUST be
- written after everything else in the additional section except for
- the TSIG (if any).
-
- output, an io.BytesIO, where rendering is written
-
- id: the message id
-
- flags: the message flags
-
- max_size: the maximum size of the message
-
- origin: the origin to use when rendering relative names
-
- compress: the compression table
-
- section: an int, the section currently being rendered
-
- counts: list of the number of RRs in each section
-
- mac: the MAC of the rendered message (if TSIG was used)
- """
-
- def __init__(self, id=None, flags=0, max_size=65535, origin=None):
- """Initialize a new renderer."""
-
- self.output = io.BytesIO()
- if id is None:
- self.id = random.randint(0, 65535)
- else:
- self.id = id
- self.flags = flags
- self.max_size = max_size
- self.origin = origin
- self.compress = {}
- self.section = QUESTION
- self.counts = [0, 0, 0, 0]
- self.output.write(b"\x00" * 12)
- self.mac = ""
- self.reserved = 0
- self.was_padded = False
-
- def _rollback(self, where):
- """Truncate the output buffer at offset *where*, and remove any
- compression table entries that pointed beyond the truncation
- point.
- """
-
- self.output.seek(where)
- self.output.truncate()
- keys_to_delete = []
- for k, v in self.compress.items():
- if v >= where:
- keys_to_delete.append(k)
- for k in keys_to_delete:
- del self.compress[k]
-
- def _set_section(self, section):
- """Set the renderer's current section.
-
- Sections must be rendered order: QUESTION, ANSWER, AUTHORITY,
- ADDITIONAL. Sections may be empty.
-
- Raises dns.exception.FormError if an attempt was made to set
- a section value less than the current section.
- """
-
- if self.section != section:
- if self.section > section:
- raise dns.exception.FormError
- self.section = section
-
- @contextlib.contextmanager
- def _track_size(self):
- start = self.output.tell()
- yield start
- if self.output.tell() > self.max_size:
- self._rollback(start)
- raise dns.exception.TooBig
-
- @contextlib.contextmanager
- def _temporarily_seek_to(self, where):
- current = self.output.tell()
- try:
- self.output.seek(where)
- yield
- finally:
- self.output.seek(current)
-
- def add_question(self, qname, rdtype, rdclass=dns.rdataclass.IN):
- """Add a question to the message."""
-
- self._set_section(QUESTION)
- with self._track_size():
- qname.to_wire(self.output, self.compress, self.origin)
- self.output.write(struct.pack("!HH", rdtype, rdclass))
- self.counts[QUESTION] += 1
-
- def add_rrset(self, section, rrset, **kw):
- """Add the rrset to the specified section.
-
- Any keyword arguments are passed on to the rdataset's to_wire()
- routine.
- """
-
- self._set_section(section)
- with self._track_size():
- n = rrset.to_wire(self.output, self.compress, self.origin, **kw)
- self.counts[section] += n
-
- def add_rdataset(self, section, name, rdataset, **kw):
- """Add the rdataset to the specified section, using the specified
- name as the owner name.
-
- Any keyword arguments are passed on to the rdataset's to_wire()
- routine.
- """
-
- self._set_section(section)
- with self._track_size():
- n = rdataset.to_wire(name, self.output, self.compress, self.origin, **kw)
- self.counts[section] += n
-
- def add_opt(self, opt, pad=0, opt_size=0, tsig_size=0):
- """Add *opt* to the additional section, applying padding if desired. The
- padding will take the specified precomputed OPT size and TSIG size into
- account.
-
- Note that we don't have reliable way of knowing how big a GSS-TSIG digest
- might be, so we we might not get an even multiple of the pad in that case."""
- if pad:
- ttl = opt.ttl
- assert opt_size >= 11
- opt_rdata = opt[0]
- size_without_padding = self.output.tell() + opt_size + tsig_size
- remainder = size_without_padding % pad
- if remainder:
- pad = b"\x00" * (pad - remainder)
- else:
- pad = b""
- options = list(opt_rdata.options)
- options.append(dns.edns.GenericOption(dns.edns.OptionType.PADDING, pad))
- opt = dns.message.Message._make_opt(ttl, opt_rdata.rdclass, options)
- self.was_padded = True
- self.add_rrset(ADDITIONAL, opt)
-
- def add_edns(self, edns, ednsflags, payload, options=None):
- """Add an EDNS OPT record to the message."""
-
- # make sure the EDNS version in ednsflags agrees with edns
- ednsflags &= 0xFF00FFFF
- ednsflags |= edns << 16
- opt = dns.message.Message._make_opt(ednsflags, payload, options)
- self.add_opt(opt)
-
- def add_tsig(
- self,
- keyname,
- secret,
- fudge,
- id,
- tsig_error,
- other_data,
- request_mac,
- algorithm=dns.tsig.default_algorithm,
- ):
- """Add a TSIG signature to the message."""
-
- s = self.output.getvalue()
-
- if isinstance(secret, dns.tsig.Key):
- key = secret
- else:
- key = dns.tsig.Key(keyname, secret, algorithm)
- tsig = dns.message.Message._make_tsig(
- keyname, algorithm, 0, fudge, b"", id, tsig_error, other_data
- )
- (tsig, _) = dns.tsig.sign(s, key, tsig[0], int(time.time()), request_mac)
- self._write_tsig(tsig, keyname)
-
- def add_multi_tsig(
- self,
- ctx,
- keyname,
- secret,
- fudge,
- id,
- tsig_error,
- other_data,
- request_mac,
- algorithm=dns.tsig.default_algorithm,
- ):
- """Add a TSIG signature to the message. Unlike add_tsig(), this can be
- used for a series of consecutive DNS envelopes, e.g. for a zone
- transfer over TCP [RFC2845, 4.4].
-
- For the first message in the sequence, give ctx=None. For each
- subsequent message, give the ctx that was returned from the
- add_multi_tsig() call for the previous message."""
-
- s = self.output.getvalue()
-
- if isinstance(secret, dns.tsig.Key):
- key = secret
- else:
- key = dns.tsig.Key(keyname, secret, algorithm)
- tsig = dns.message.Message._make_tsig(
- keyname, algorithm, 0, fudge, b"", id, tsig_error, other_data
- )
- (tsig, ctx) = dns.tsig.sign(
- s, key, tsig[0], int(time.time()), request_mac, ctx, True
- )
- self._write_tsig(tsig, keyname)
- return ctx
-
- def _write_tsig(self, tsig, keyname):
- if self.was_padded:
- compress = None
- else:
- compress = self.compress
- self._set_section(ADDITIONAL)
- with self._track_size():
- keyname.to_wire(self.output, compress, self.origin)
- self.output.write(
- struct.pack("!HHI", dns.rdatatype.TSIG, dns.rdataclass.ANY, 0)
- )
- with prefixed_length(self.output, 2):
- tsig.to_wire(self.output)
-
- self.counts[ADDITIONAL] += 1
- with self._temporarily_seek_to(10):
- self.output.write(struct.pack("!H", self.counts[ADDITIONAL]))
-
- def write_header(self):
- """Write the DNS message header.
-
- Writing the DNS message header is done after all sections
- have been rendered, but before the optional TSIG signature
- is added.
- """
-
- with self._temporarily_seek_to(0):
- self.output.write(
- struct.pack(
- "!HHHHHH",
- self.id,
- self.flags,
- self.counts[0],
- self.counts[1],
- self.counts[2],
- self.counts[3],
- )
- )
-
- def get_wire(self):
- """Return the wire format message."""
-
- return self.output.getvalue()
-
- def reserve(self, size: int) -> None:
- """Reserve *size* bytes."""
- if size < 0:
- raise ValueError("reserved amount must be non-negative")
- if size > self.max_size:
- raise ValueError("cannot reserve more than the maximum size")
- self.reserved += size
- self.max_size -= size
-
- def release_reserved(self) -> None:
- """Release the reserved bytes."""
- self.max_size += self.reserved
- self.reserved = 0
diff --git a/.venv/lib/python3.12/site-packages/dns/resolver.py b/.venv/lib/python3.12/site-packages/dns/resolver.py
deleted file mode 100644
index f08f824..0000000
--- a/.venv/lib/python3.12/site-packages/dns/resolver.py
+++ /dev/null
@@ -1,2054 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS stub resolver."""
-
-import contextlib
-import random
-import socket
-import sys
-import threading
-import time
-import warnings
-from typing import Any, Dict, Iterator, List, Optional, Sequence, Tuple, Union
-from urllib.parse import urlparse
-
-import dns._ddr
-import dns.edns
-import dns.exception
-import dns.flags
-import dns.inet
-import dns.ipv4
-import dns.ipv6
-import dns.message
-import dns.name
-import dns.nameserver
-import dns.query
-import dns.rcode
-import dns.rdataclass
-import dns.rdatatype
-import dns.rdtypes.svcbbase
-import dns.reversename
-import dns.tsig
-
-if sys.platform == "win32":
- import dns.win32util
-
-
-class NXDOMAIN(dns.exception.DNSException):
- """The DNS query name does not exist."""
-
- supp_kwargs = {"qnames", "responses"}
- fmt = None # we have our own __str__ implementation
-
- # pylint: disable=arguments-differ
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def _check_kwargs(self, qnames, responses=None):
- if not isinstance(qnames, (list, tuple, set)):
- raise AttributeError("qnames must be a list, tuple or set")
- if len(qnames) == 0:
- raise AttributeError("qnames must contain at least one element")
- if responses is None:
- responses = {}
- elif not isinstance(responses, dict):
- raise AttributeError("responses must be a dict(qname=response)")
- kwargs = dict(qnames=qnames, responses=responses)
- return kwargs
-
- def __str__(self) -> str:
- if "qnames" not in self.kwargs:
- return super().__str__()
- qnames = self.kwargs["qnames"]
- if len(qnames) > 1:
- msg = "None of DNS query names exist"
- else:
- msg = "The DNS query name does not exist"
- qnames = ", ".join(map(str, qnames))
- return "{}: {}".format(msg, qnames)
-
- @property
- def canonical_name(self):
- """Return the unresolved canonical name."""
- if "qnames" not in self.kwargs:
- raise TypeError("parametrized exception required")
- for qname in self.kwargs["qnames"]:
- response = self.kwargs["responses"][qname]
- try:
- cname = response.canonical_name()
- if cname != qname:
- return cname
- except Exception:
- # We can just eat this exception as it means there was
- # something wrong with the response.
- pass
- return self.kwargs["qnames"][0]
-
- def __add__(self, e_nx):
- """Augment by results from another NXDOMAIN exception."""
- qnames0 = list(self.kwargs.get("qnames", []))
- responses0 = dict(self.kwargs.get("responses", {}))
- responses1 = e_nx.kwargs.get("responses", {})
- for qname1 in e_nx.kwargs.get("qnames", []):
- if qname1 not in qnames0:
- qnames0.append(qname1)
- if qname1 in responses1:
- responses0[qname1] = responses1[qname1]
- return NXDOMAIN(qnames=qnames0, responses=responses0)
-
- def qnames(self):
- """All of the names that were tried.
-
- Returns a list of ``dns.name.Name``.
- """
- return self.kwargs["qnames"]
-
- def responses(self):
- """A map from queried names to their NXDOMAIN responses.
-
- Returns a dict mapping a ``dns.name.Name`` to a
- ``dns.message.Message``.
- """
- return self.kwargs["responses"]
-
- def response(self, qname):
- """The response for query *qname*.
-
- Returns a ``dns.message.Message``.
- """
- return self.kwargs["responses"][qname]
-
-
-class YXDOMAIN(dns.exception.DNSException):
- """The DNS query name is too long after DNAME substitution."""
-
-
-ErrorTuple = Tuple[
- Optional[str],
- bool,
- int,
- Union[Exception, str],
- Optional[dns.message.Message],
-]
-
-
-def _errors_to_text(errors: List[ErrorTuple]) -> List[str]:
- """Turn a resolution errors trace into a list of text."""
- texts = []
- for err in errors:
- texts.append("Server {} answered {}".format(err[0], err[3]))
- return texts
-
-
-class LifetimeTimeout(dns.exception.Timeout):
- """The resolution lifetime expired."""
-
- msg = "The resolution lifetime expired."
- fmt = "%s after {timeout:.3f} seconds: {errors}" % msg[:-1]
- supp_kwargs = {"timeout", "errors"}
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def _fmt_kwargs(self, **kwargs):
- srv_msgs = _errors_to_text(kwargs["errors"])
- return super()._fmt_kwargs(
- timeout=kwargs["timeout"], errors="; ".join(srv_msgs)
- )
-
-
-# We added more detail to resolution timeouts, but they are still
-# subclasses of dns.exception.Timeout for backwards compatibility. We also
-# keep dns.resolver.Timeout defined for backwards compatibility.
-Timeout = LifetimeTimeout
-
-
-class NoAnswer(dns.exception.DNSException):
- """The DNS response does not contain an answer to the question."""
-
- fmt = "The DNS response does not contain an answer to the question: {query}"
- supp_kwargs = {"response"}
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def _fmt_kwargs(self, **kwargs):
- return super()._fmt_kwargs(query=kwargs["response"].question)
-
- def response(self):
- return self.kwargs["response"]
-
-
-class NoNameservers(dns.exception.DNSException):
- """All nameservers failed to answer the query.
-
- errors: list of servers and respective errors
- The type of errors is
- [(server IP address, any object convertible to string)].
- Non-empty errors list will add explanatory message ()
- """
-
- msg = "All nameservers failed to answer the query."
- fmt = "%s {query}: {errors}" % msg[:-1]
- supp_kwargs = {"request", "errors"}
-
- # We do this as otherwise mypy complains about unexpected keyword argument
- # idna_exception
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- def _fmt_kwargs(self, **kwargs):
- srv_msgs = _errors_to_text(kwargs["errors"])
- return super()._fmt_kwargs(
- query=kwargs["request"].question, errors="; ".join(srv_msgs)
- )
-
-
-class NotAbsolute(dns.exception.DNSException):
- """An absolute domain name is required but a relative name was provided."""
-
-
-class NoRootSOA(dns.exception.DNSException):
- """There is no SOA RR at the DNS root name. This should never happen!"""
-
-
-class NoMetaqueries(dns.exception.DNSException):
- """DNS metaqueries are not allowed."""
-
-
-class NoResolverConfiguration(dns.exception.DNSException):
- """Resolver configuration could not be read or specified no nameservers."""
-
-
-class Answer:
- """DNS stub resolver answer.
-
- Instances of this class bundle up the result of a successful DNS
- resolution.
-
- For convenience, the answer object implements much of the sequence
- protocol, forwarding to its ``rrset`` attribute. E.g.
- ``for a in answer`` is equivalent to ``for a in answer.rrset``.
- ``answer[i]`` is equivalent to ``answer.rrset[i]``, and
- ``answer[i:j]`` is equivalent to ``answer.rrset[i:j]``.
-
- Note that CNAMEs or DNAMEs in the response may mean that answer
- RRset's name might not be the query name.
- """
-
- def __init__(
- self,
- qname: dns.name.Name,
- rdtype: dns.rdatatype.RdataType,
- rdclass: dns.rdataclass.RdataClass,
- response: dns.message.QueryMessage,
- nameserver: Optional[str] = None,
- port: Optional[int] = None,
- ) -> None:
- self.qname = qname
- self.rdtype = rdtype
- self.rdclass = rdclass
- self.response = response
- self.nameserver = nameserver
- self.port = port
- self.chaining_result = response.resolve_chaining()
- # Copy some attributes out of chaining_result for backwards
- # compatibility and convenience.
- self.canonical_name = self.chaining_result.canonical_name
- self.rrset = self.chaining_result.answer
- self.expiration = time.time() + self.chaining_result.minimum_ttl
-
- def __getattr__(self, attr): # pragma: no cover
- if attr == "name":
- return self.rrset.name
- elif attr == "ttl":
- return self.rrset.ttl
- elif attr == "covers":
- return self.rrset.covers
- elif attr == "rdclass":
- return self.rrset.rdclass
- elif attr == "rdtype":
- return self.rrset.rdtype
- else:
- raise AttributeError(attr)
-
- def __len__(self) -> int:
- return self.rrset and len(self.rrset) or 0
-
- def __iter__(self):
- return self.rrset and iter(self.rrset) or iter(tuple())
-
- def __getitem__(self, i):
- if self.rrset is None:
- raise IndexError
- return self.rrset[i]
-
- def __delitem__(self, i):
- if self.rrset is None:
- raise IndexError
- del self.rrset[i]
-
-
-class Answers(dict):
- """A dict of DNS stub resolver answers, indexed by type."""
-
-
-class HostAnswers(Answers):
- """A dict of DNS stub resolver answers to a host name lookup, indexed by
- type.
- """
-
- @classmethod
- def make(
- cls,
- v6: Optional[Answer] = None,
- v4: Optional[Answer] = None,
- add_empty: bool = True,
- ) -> "HostAnswers":
- answers = HostAnswers()
- if v6 is not None and (add_empty or v6.rrset):
- answers[dns.rdatatype.AAAA] = v6
- if v4 is not None and (add_empty or v4.rrset):
- answers[dns.rdatatype.A] = v4
- return answers
-
- # Returns pairs of (address, family) from this result, potentiallys
- # filtering by address family.
- def addresses_and_families(
- self, family: int = socket.AF_UNSPEC
- ) -> Iterator[Tuple[str, int]]:
- if family == socket.AF_UNSPEC:
- yield from self.addresses_and_families(socket.AF_INET6)
- yield from self.addresses_and_families(socket.AF_INET)
- return
- elif family == socket.AF_INET6:
- answer = self.get(dns.rdatatype.AAAA)
- elif family == socket.AF_INET:
- answer = self.get(dns.rdatatype.A)
- else:
- raise NotImplementedError(f"unknown address family {family}")
- if answer:
- for rdata in answer:
- yield (rdata.address, family)
-
- # Returns addresses from this result, potentially filtering by
- # address family.
- def addresses(self, family: int = socket.AF_UNSPEC) -> Iterator[str]:
- return (pair[0] for pair in self.addresses_and_families(family))
-
- # Returns the canonical name from this result.
- def canonical_name(self) -> dns.name.Name:
- answer = self.get(dns.rdatatype.AAAA, self.get(dns.rdatatype.A))
- return answer.canonical_name
-
-
-class CacheStatistics:
- """Cache Statistics"""
-
- def __init__(self, hits: int = 0, misses: int = 0) -> None:
- self.hits = hits
- self.misses = misses
-
- def reset(self) -> None:
- self.hits = 0
- self.misses = 0
-
- def clone(self) -> "CacheStatistics":
- return CacheStatistics(self.hits, self.misses)
-
-
-class CacheBase:
- def __init__(self) -> None:
- self.lock = threading.Lock()
- self.statistics = CacheStatistics()
-
- def reset_statistics(self) -> None:
- """Reset all statistics to zero."""
- with self.lock:
- self.statistics.reset()
-
- def hits(self) -> int:
- """How many hits has the cache had?"""
- with self.lock:
- return self.statistics.hits
-
- def misses(self) -> int:
- """How many misses has the cache had?"""
- with self.lock:
- return self.statistics.misses
-
- def get_statistics_snapshot(self) -> CacheStatistics:
- """Return a consistent snapshot of all the statistics.
-
- If running with multiple threads, it's better to take a
- snapshot than to call statistics methods such as hits() and
- misses() individually.
- """
- with self.lock:
- return self.statistics.clone()
-
-
-CacheKey = Tuple[dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass]
-
-
-class Cache(CacheBase):
- """Simple thread-safe DNS answer cache."""
-
- def __init__(self, cleaning_interval: float = 300.0) -> None:
- """*cleaning_interval*, a ``float`` is the number of seconds between
- periodic cleanings.
- """
-
- super().__init__()
- self.data: Dict[CacheKey, Answer] = {}
- self.cleaning_interval = cleaning_interval
- self.next_cleaning: float = time.time() + self.cleaning_interval
-
- def _maybe_clean(self) -> None:
- """Clean the cache if it's time to do so."""
-
- now = time.time()
- if self.next_cleaning <= now:
- keys_to_delete = []
- for k, v in self.data.items():
- if v.expiration <= now:
- keys_to_delete.append(k)
- for k in keys_to_delete:
- del self.data[k]
- now = time.time()
- self.next_cleaning = now + self.cleaning_interval
-
- def get(self, key: CacheKey) -> Optional[Answer]:
- """Get the answer associated with *key*.
-
- Returns None if no answer is cached for the key.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
-
- Returns a ``dns.resolver.Answer`` or ``None``.
- """
-
- with self.lock:
- self._maybe_clean()
- v = self.data.get(key)
- if v is None or v.expiration <= time.time():
- self.statistics.misses += 1
- return None
- self.statistics.hits += 1
- return v
-
- def put(self, key: CacheKey, value: Answer) -> None:
- """Associate key and value in the cache.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
-
- *value*, a ``dns.resolver.Answer``, the answer.
- """
-
- with self.lock:
- self._maybe_clean()
- self.data[key] = value
-
- def flush(self, key: Optional[CacheKey] = None) -> None:
- """Flush the cache.
-
- If *key* is not ``None``, only that item is flushed. Otherwise the entire cache
- is flushed.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
- """
-
- with self.lock:
- if key is not None:
- if key in self.data:
- del self.data[key]
- else:
- self.data = {}
- self.next_cleaning = time.time() + self.cleaning_interval
-
-
-class LRUCacheNode:
- """LRUCache node."""
-
- def __init__(self, key, value):
- self.key = key
- self.value = value
- self.hits = 0
- self.prev = self
- self.next = self
-
- def link_after(self, node: "LRUCacheNode") -> None:
- self.prev = node
- self.next = node.next
- node.next.prev = self
- node.next = self
-
- def unlink(self) -> None:
- self.next.prev = self.prev
- self.prev.next = self.next
-
-
-class LRUCache(CacheBase):
- """Thread-safe, bounded, least-recently-used DNS answer cache.
-
- This cache is better than the simple cache (above) if you're
- running a web crawler or other process that does a lot of
- resolutions. The LRUCache has a maximum number of nodes, and when
- it is full, the least-recently used node is removed to make space
- for a new one.
- """
-
- def __init__(self, max_size: int = 100000) -> None:
- """*max_size*, an ``int``, is the maximum number of nodes to cache;
- it must be greater than 0.
- """
-
- super().__init__()
- self.data: Dict[CacheKey, LRUCacheNode] = {}
- self.set_max_size(max_size)
- self.sentinel: LRUCacheNode = LRUCacheNode(None, None)
- self.sentinel.prev = self.sentinel
- self.sentinel.next = self.sentinel
-
- def set_max_size(self, max_size: int) -> None:
- if max_size < 1:
- max_size = 1
- self.max_size = max_size
-
- def get(self, key: CacheKey) -> Optional[Answer]:
- """Get the answer associated with *key*.
-
- Returns None if no answer is cached for the key.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
-
- Returns a ``dns.resolver.Answer`` or ``None``.
- """
-
- with self.lock:
- node = self.data.get(key)
- if node is None:
- self.statistics.misses += 1
- return None
- # Unlink because we're either going to move the node to the front
- # of the LRU list or we're going to free it.
- node.unlink()
- if node.value.expiration <= time.time():
- del self.data[node.key]
- self.statistics.misses += 1
- return None
- node.link_after(self.sentinel)
- self.statistics.hits += 1
- node.hits += 1
- return node.value
-
- def get_hits_for_key(self, key: CacheKey) -> int:
- """Return the number of cache hits associated with the specified key."""
- with self.lock:
- node = self.data.get(key)
- if node is None or node.value.expiration <= time.time():
- return 0
- else:
- return node.hits
-
- def put(self, key: CacheKey, value: Answer) -> None:
- """Associate key and value in the cache.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
-
- *value*, a ``dns.resolver.Answer``, the answer.
- """
-
- with self.lock:
- node = self.data.get(key)
- if node is not None:
- node.unlink()
- del self.data[node.key]
- while len(self.data) >= self.max_size:
- gnode = self.sentinel.prev
- gnode.unlink()
- del self.data[gnode.key]
- node = LRUCacheNode(key, value)
- node.link_after(self.sentinel)
- self.data[key] = node
-
- def flush(self, key: Optional[CacheKey] = None) -> None:
- """Flush the cache.
-
- If *key* is not ``None``, only that item is flushed. Otherwise the entire cache
- is flushed.
-
- *key*, a ``(dns.name.Name, dns.rdatatype.RdataType, dns.rdataclass.RdataClass)``
- tuple whose values are the query name, rdtype, and rdclass respectively.
- """
-
- with self.lock:
- if key is not None:
- node = self.data.get(key)
- if node is not None:
- node.unlink()
- del self.data[node.key]
- else:
- gnode = self.sentinel.next
- while gnode != self.sentinel:
- next = gnode.next
- gnode.unlink()
- gnode = next
- self.data = {}
-
-
-class _Resolution:
- """Helper class for dns.resolver.Resolver.resolve().
-
- All of the "business logic" of resolution is encapsulated in this
- class, allowing us to have multiple resolve() implementations
- using different I/O schemes without copying all of the
- complicated logic.
-
- This class is a "friend" to dns.resolver.Resolver and manipulates
- resolver data structures directly.
- """
-
- def __init__(
- self,
- resolver: "BaseResolver",
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- rdclass: Union[dns.rdataclass.RdataClass, str],
- tcp: bool,
- raise_on_no_answer: bool,
- search: Optional[bool],
- ) -> None:
- if isinstance(qname, str):
- qname = dns.name.from_text(qname, None)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- if dns.rdatatype.is_metatype(rdtype):
- raise NoMetaqueries
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- if dns.rdataclass.is_metaclass(rdclass):
- raise NoMetaqueries
- self.resolver = resolver
- self.qnames_to_try = resolver._get_qnames_to_try(qname, search)
- self.qnames = self.qnames_to_try[:]
- self.rdtype = rdtype
- self.rdclass = rdclass
- self.tcp = tcp
- self.raise_on_no_answer = raise_on_no_answer
- self.nxdomain_responses: Dict[dns.name.Name, dns.message.QueryMessage] = {}
- # Initialize other things to help analysis tools
- self.qname = dns.name.empty
- self.nameservers: List[dns.nameserver.Nameserver] = []
- self.current_nameservers: List[dns.nameserver.Nameserver] = []
- self.errors: List[ErrorTuple] = []
- self.nameserver: Optional[dns.nameserver.Nameserver] = None
- self.tcp_attempt = False
- self.retry_with_tcp = False
- self.request: Optional[dns.message.QueryMessage] = None
- self.backoff = 0.0
-
- def next_request(
- self,
- ) -> Tuple[Optional[dns.message.QueryMessage], Optional[Answer]]:
- """Get the next request to send, and check the cache.
-
- Returns a (request, answer) tuple. At most one of request or
- answer will not be None.
- """
-
- # We return a tuple instead of Union[Message,Answer] as it lets
- # the caller avoid isinstance().
-
- while len(self.qnames) > 0:
- self.qname = self.qnames.pop(0)
-
- # Do we know the answer?
- if self.resolver.cache:
- answer = self.resolver.cache.get(
- (self.qname, self.rdtype, self.rdclass)
- )
- if answer is not None:
- if answer.rrset is None and self.raise_on_no_answer:
- raise NoAnswer(response=answer.response)
- else:
- return (None, answer)
- answer = self.resolver.cache.get(
- (self.qname, dns.rdatatype.ANY, self.rdclass)
- )
- if answer is not None and answer.response.rcode() == dns.rcode.NXDOMAIN:
- # cached NXDOMAIN; record it and continue to next
- # name.
- self.nxdomain_responses[self.qname] = answer.response
- continue
-
- # Build the request
- request = dns.message.make_query(self.qname, self.rdtype, self.rdclass)
- if self.resolver.keyname is not None:
- request.use_tsig(
- self.resolver.keyring,
- self.resolver.keyname,
- algorithm=self.resolver.keyalgorithm,
- )
- request.use_edns(
- self.resolver.edns,
- self.resolver.ednsflags,
- self.resolver.payload,
- options=self.resolver.ednsoptions,
- )
- if self.resolver.flags is not None:
- request.flags = self.resolver.flags
-
- self.nameservers = self.resolver._enrich_nameservers(
- self.resolver._nameservers,
- self.resolver.nameserver_ports,
- self.resolver.port,
- )
- if self.resolver.rotate:
- random.shuffle(self.nameservers)
- self.current_nameservers = self.nameservers[:]
- self.errors = []
- self.nameserver = None
- self.tcp_attempt = False
- self.retry_with_tcp = False
- self.request = request
- self.backoff = 0.10
-
- return (request, None)
-
- #
- # We've tried everything and only gotten NXDOMAINs. (We know
- # it's only NXDOMAINs as anything else would have returned
- # before now.)
- #
- raise NXDOMAIN(qnames=self.qnames_to_try, responses=self.nxdomain_responses)
-
- def next_nameserver(self) -> Tuple[dns.nameserver.Nameserver, bool, float]:
- if self.retry_with_tcp:
- assert self.nameserver is not None
- assert not self.nameserver.is_always_max_size()
- self.tcp_attempt = True
- self.retry_with_tcp = False
- return (self.nameserver, True, 0)
-
- backoff = 0.0
- if not self.current_nameservers:
- if len(self.nameservers) == 0:
- # Out of things to try!
- raise NoNameservers(request=self.request, errors=self.errors)
- self.current_nameservers = self.nameservers[:]
- backoff = self.backoff
- self.backoff = min(self.backoff * 2, 2)
-
- self.nameserver = self.current_nameservers.pop(0)
- self.tcp_attempt = self.tcp or self.nameserver.is_always_max_size()
- return (self.nameserver, self.tcp_attempt, backoff)
-
- def query_result(
- self, response: Optional[dns.message.Message], ex: Optional[Exception]
- ) -> Tuple[Optional[Answer], bool]:
- #
- # returns an (answer: Answer, end_loop: bool) tuple.
- #
- assert self.nameserver is not None
- if ex:
- # Exception during I/O or from_wire()
- assert response is None
- self.errors.append(
- (
- str(self.nameserver),
- self.tcp_attempt,
- self.nameserver.answer_port(),
- ex,
- response,
- )
- )
- if (
- isinstance(ex, dns.exception.FormError)
- or isinstance(ex, EOFError)
- or isinstance(ex, OSError)
- or isinstance(ex, NotImplementedError)
- ):
- # This nameserver is no good, take it out of the mix.
- self.nameservers.remove(self.nameserver)
- elif isinstance(ex, dns.message.Truncated):
- if self.tcp_attempt:
- # Truncation with TCP is no good!
- self.nameservers.remove(self.nameserver)
- else:
- self.retry_with_tcp = True
- return (None, False)
- # We got an answer!
- assert response is not None
- assert isinstance(response, dns.message.QueryMessage)
- rcode = response.rcode()
- if rcode == dns.rcode.NOERROR:
- try:
- answer = Answer(
- self.qname,
- self.rdtype,
- self.rdclass,
- response,
- self.nameserver.answer_nameserver(),
- self.nameserver.answer_port(),
- )
- except Exception as e:
- self.errors.append(
- (
- str(self.nameserver),
- self.tcp_attempt,
- self.nameserver.answer_port(),
- e,
- response,
- )
- )
- # The nameserver is no good, take it out of the mix.
- self.nameservers.remove(self.nameserver)
- return (None, False)
- if self.resolver.cache:
- self.resolver.cache.put((self.qname, self.rdtype, self.rdclass), answer)
- if answer.rrset is None and self.raise_on_no_answer:
- raise NoAnswer(response=answer.response)
- return (answer, True)
- elif rcode == dns.rcode.NXDOMAIN:
- # Further validate the response by making an Answer, even
- # if we aren't going to cache it.
- try:
- answer = Answer(
- self.qname, dns.rdatatype.ANY, dns.rdataclass.IN, response
- )
- except Exception as e:
- self.errors.append(
- (
- str(self.nameserver),
- self.tcp_attempt,
- self.nameserver.answer_port(),
- e,
- response,
- )
- )
- # The nameserver is no good, take it out of the mix.
- self.nameservers.remove(self.nameserver)
- return (None, False)
- self.nxdomain_responses[self.qname] = response
- if self.resolver.cache:
- self.resolver.cache.put(
- (self.qname, dns.rdatatype.ANY, self.rdclass), answer
- )
- # Make next_nameserver() return None, so caller breaks its
- # inner loop and calls next_request().
- return (None, True)
- elif rcode == dns.rcode.YXDOMAIN:
- yex = YXDOMAIN()
- self.errors.append(
- (
- str(self.nameserver),
- self.tcp_attempt,
- self.nameserver.answer_port(),
- yex,
- response,
- )
- )
- raise yex
- else:
- #
- # We got a response, but we're not happy with the
- # rcode in it.
- #
- if rcode != dns.rcode.SERVFAIL or not self.resolver.retry_servfail:
- self.nameservers.remove(self.nameserver)
- self.errors.append(
- (
- str(self.nameserver),
- self.tcp_attempt,
- self.nameserver.answer_port(),
- dns.rcode.to_text(rcode),
- response,
- )
- )
- return (None, False)
-
-
-class BaseResolver:
- """DNS stub resolver."""
-
- # We initialize in reset()
- #
- # pylint: disable=attribute-defined-outside-init
-
- domain: dns.name.Name
- nameserver_ports: Dict[str, int]
- port: int
- search: List[dns.name.Name]
- use_search_by_default: bool
- timeout: float
- lifetime: float
- keyring: Optional[Any]
- keyname: Optional[Union[dns.name.Name, str]]
- keyalgorithm: Union[dns.name.Name, str]
- edns: int
- ednsflags: int
- ednsoptions: Optional[List[dns.edns.Option]]
- payload: int
- cache: Any
- flags: Optional[int]
- retry_servfail: bool
- rotate: bool
- ndots: Optional[int]
- _nameservers: Sequence[Union[str, dns.nameserver.Nameserver]]
-
- def __init__(
- self, filename: str = "/etc/resolv.conf", configure: bool = True
- ) -> None:
- """*filename*, a ``str`` or file object, specifying a file
- in standard /etc/resolv.conf format. This parameter is meaningful
- only when *configure* is true and the platform is POSIX.
-
- *configure*, a ``bool``. If True (the default), the resolver
- instance is configured in the normal fashion for the operating
- system the resolver is running on. (I.e. by reading a
- /etc/resolv.conf file on POSIX systems and from the registry
- on Windows systems.)
- """
-
- self.reset()
- if configure:
- if sys.platform == "win32":
- self.read_registry()
- elif filename:
- self.read_resolv_conf(filename)
-
- def reset(self) -> None:
- """Reset all resolver configuration to the defaults."""
-
- self.domain = dns.name.Name(dns.name.from_text(socket.gethostname())[1:])
- if len(self.domain) == 0:
- self.domain = dns.name.root
- self._nameservers = []
- self.nameserver_ports = {}
- self.port = 53
- self.search = []
- self.use_search_by_default = False
- self.timeout = 2.0
- self.lifetime = 5.0
- self.keyring = None
- self.keyname = None
- self.keyalgorithm = dns.tsig.default_algorithm
- self.edns = -1
- self.ednsflags = 0
- self.ednsoptions = None
- self.payload = 0
- self.cache = None
- self.flags = None
- self.retry_servfail = False
- self.rotate = False
- self.ndots = None
-
- def read_resolv_conf(self, f: Any) -> None:
- """Process *f* as a file in the /etc/resolv.conf format. If f is
- a ``str``, it is used as the name of the file to open; otherwise it
- is treated as the file itself.
-
- Interprets the following items:
-
- - nameserver - name server IP address
-
- - domain - local domain name
-
- - search - search list for host-name lookup
-
- - options - supported options are rotate, timeout, edns0, and ndots
-
- """
-
- nameservers = []
- if isinstance(f, str):
- try:
- cm: contextlib.AbstractContextManager = open(f)
- except OSError:
- # /etc/resolv.conf doesn't exist, can't be read, etc.
- raise NoResolverConfiguration(f"cannot open {f}")
- else:
- cm = contextlib.nullcontext(f)
- with cm as f:
- for l in f:
- if len(l) == 0 or l[0] == "#" or l[0] == ";":
- continue
- tokens = l.split()
-
- # Any line containing less than 2 tokens is malformed
- if len(tokens) < 2:
- continue
-
- if tokens[0] == "nameserver":
- nameservers.append(tokens[1])
- elif tokens[0] == "domain":
- self.domain = dns.name.from_text(tokens[1])
- # domain and search are exclusive
- self.search = []
- elif tokens[0] == "search":
- # the last search wins
- self.search = []
- for suffix in tokens[1:]:
- self.search.append(dns.name.from_text(suffix))
- # We don't set domain as it is not used if
- # len(self.search) > 0
- elif tokens[0] == "options":
- for opt in tokens[1:]:
- if opt == "rotate":
- self.rotate = True
- elif opt == "edns0":
- self.use_edns()
- elif "timeout" in opt:
- try:
- self.timeout = int(opt.split(":")[1])
- except (ValueError, IndexError):
- pass
- elif "ndots" in opt:
- try:
- self.ndots = int(opt.split(":")[1])
- except (ValueError, IndexError):
- pass
- if len(nameservers) == 0:
- raise NoResolverConfiguration("no nameservers")
- # Assigning directly instead of appending means we invoke the
- # setter logic, with additonal checking and enrichment.
- self.nameservers = nameservers
-
- def read_registry(self) -> None:
- """Extract resolver configuration from the Windows registry."""
- try:
- info = dns.win32util.get_dns_info() # type: ignore
- if info.domain is not None:
- self.domain = info.domain
- self.nameservers = info.nameservers
- self.search = info.search
- except AttributeError:
- raise NotImplementedError
-
- def _compute_timeout(
- self,
- start: float,
- lifetime: Optional[float] = None,
- errors: Optional[List[ErrorTuple]] = None,
- ) -> float:
- lifetime = self.lifetime if lifetime is None else lifetime
- now = time.time()
- duration = now - start
- if errors is None:
- errors = []
- if duration < 0:
- if duration < -1:
- # Time going backwards is bad. Just give up.
- raise LifetimeTimeout(timeout=duration, errors=errors)
- else:
- # Time went backwards, but only a little. This can
- # happen, e.g. under vmware with older linux kernels.
- # Pretend it didn't happen.
- duration = 0
- if duration >= lifetime:
- raise LifetimeTimeout(timeout=duration, errors=errors)
- return min(lifetime - duration, self.timeout)
-
- def _get_qnames_to_try(
- self, qname: dns.name.Name, search: Optional[bool]
- ) -> List[dns.name.Name]:
- # This is a separate method so we can unit test the search
- # rules without requiring the Internet.
- if search is None:
- search = self.use_search_by_default
- qnames_to_try = []
- if qname.is_absolute():
- qnames_to_try.append(qname)
- else:
- abs_qname = qname.concatenate(dns.name.root)
- if search:
- if len(self.search) > 0:
- # There is a search list, so use it exclusively
- search_list = self.search[:]
- elif self.domain != dns.name.root and self.domain is not None:
- # We have some notion of a domain that isn't the root, so
- # use it as the search list.
- search_list = [self.domain]
- else:
- search_list = []
- # Figure out the effective ndots (default is 1)
- if self.ndots is None:
- ndots = 1
- else:
- ndots = self.ndots
- for suffix in search_list:
- qnames_to_try.append(qname + suffix)
- if len(qname) > ndots:
- # The name has at least ndots dots, so we should try an
- # absolute query first.
- qnames_to_try.insert(0, abs_qname)
- else:
- # The name has less than ndots dots, so we should search
- # first, then try the absolute name.
- qnames_to_try.append(abs_qname)
- else:
- qnames_to_try.append(abs_qname)
- return qnames_to_try
-
- def use_tsig(
- self,
- keyring: Any,
- keyname: Optional[Union[dns.name.Name, str]] = None,
- algorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm,
- ) -> None:
- """Add a TSIG signature to each query.
-
- The parameters are passed to ``dns.message.Message.use_tsig()``;
- see its documentation for details.
- """
-
- self.keyring = keyring
- self.keyname = keyname
- self.keyalgorithm = algorithm
-
- def use_edns(
- self,
- edns: Optional[Union[int, bool]] = 0,
- ednsflags: int = 0,
- payload: int = dns.message.DEFAULT_EDNS_PAYLOAD,
- options: Optional[List[dns.edns.Option]] = None,
- ) -> None:
- """Configure EDNS behavior.
-
- *edns*, an ``int``, is the EDNS level to use. Specifying
- ``None``, ``False``, or ``-1`` means "do not use EDNS", and in this case
- the other parameters are ignored. Specifying ``True`` is
- equivalent to specifying 0, i.e. "use EDNS0".
-
- *ednsflags*, an ``int``, the EDNS flag values.
-
- *payload*, an ``int``, is the EDNS sender's payload field, which is the
- maximum size of UDP datagram the sender can handle. I.e. how big
- a response to this message can be.
-
- *options*, a list of ``dns.edns.Option`` objects or ``None``, the EDNS
- options.
- """
-
- if edns is None or edns is False:
- edns = -1
- elif edns is True:
- edns = 0
- self.edns = edns
- self.ednsflags = ednsflags
- self.payload = payload
- self.ednsoptions = options
-
- def set_flags(self, flags: int) -> None:
- """Overrides the default flags with your own.
-
- *flags*, an ``int``, the message flags to use.
- """
-
- self.flags = flags
-
- @classmethod
- def _enrich_nameservers(
- cls,
- nameservers: Sequence[Union[str, dns.nameserver.Nameserver]],
- nameserver_ports: Dict[str, int],
- default_port: int,
- ) -> List[dns.nameserver.Nameserver]:
- enriched_nameservers = []
- if isinstance(nameservers, list):
- for nameserver in nameservers:
- enriched_nameserver: dns.nameserver.Nameserver
- if isinstance(nameserver, dns.nameserver.Nameserver):
- enriched_nameserver = nameserver
- elif dns.inet.is_address(nameserver):
- port = nameserver_ports.get(nameserver, default_port)
- enriched_nameserver = dns.nameserver.Do53Nameserver(
- nameserver, port
- )
- else:
- try:
- if urlparse(nameserver).scheme != "https":
- raise NotImplementedError
- except Exception:
- raise ValueError(
- f"nameserver {nameserver} is not a "
- "dns.nameserver.Nameserver instance or text form, "
- "IP address, nor a valid https URL"
- )
- enriched_nameserver = dns.nameserver.DoHNameserver(nameserver)
- enriched_nameservers.append(enriched_nameserver)
- else:
- raise ValueError(
- "nameservers must be a list or tuple (not a {})".format(
- type(nameservers)
- )
- )
- return enriched_nameservers
-
- @property
- def nameservers(
- self,
- ) -> Sequence[Union[str, dns.nameserver.Nameserver]]:
- return self._nameservers
-
- @nameservers.setter
- def nameservers(
- self, nameservers: Sequence[Union[str, dns.nameserver.Nameserver]]
- ) -> None:
- """
- *nameservers*, a ``list`` of nameservers, where a nameserver is either
- a string interpretable as a nameserver, or a ``dns.nameserver.Nameserver``
- instance.
-
- Raises ``ValueError`` if *nameservers* is not a list of nameservers.
- """
- # We just call _enrich_nameservers() for checking
- self._enrich_nameservers(nameservers, self.nameserver_ports, self.port)
- self._nameservers = nameservers
-
-
-class Resolver(BaseResolver):
- """DNS stub resolver."""
-
- def resolve(
- self,
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
- ) -> Answer: # pylint: disable=arguments-differ
- """Query nameservers to find the answer to the question.
-
- The *qname*, *rdtype*, and *rdclass* parameters may be objects
- of the appropriate type, or strings that can be converted into objects
- of the appropriate type.
-
- *qname*, a ``dns.name.Name`` or ``str``, the query name.
-
- *rdtype*, an ``int`` or ``str``, the query type.
-
- *rdclass*, an ``int`` or ``str``, the query class.
-
- *tcp*, a ``bool``. If ``True``, use TCP to make the query.
-
- *source*, a ``str`` or ``None``. If not ``None``, bind to this IP
- address when making queries.
-
- *raise_on_no_answer*, a ``bool``. If ``True``, raise
- ``dns.resolver.NoAnswer`` if there's no answer to the question.
-
- *source_port*, an ``int``, the port from which to send the message.
-
- *lifetime*, a ``float``, how many seconds a query should run
- before timing out.
-
- *search*, a ``bool`` or ``None``, determines whether the
- search list configured in the system's resolver configuration
- are used for relative names, and whether the resolver's domain
- may be added to relative names. The default is ``None``,
- which causes the value of the resolver's
- ``use_search_by_default`` attribute to be used.
-
- Raises ``dns.resolver.LifetimeTimeout`` if no answers could be found
- in the specified lifetime.
-
- Raises ``dns.resolver.NXDOMAIN`` if the query name does not exist.
-
- Raises ``dns.resolver.YXDOMAIN`` if the query name is too long after
- DNAME substitution.
-
- Raises ``dns.resolver.NoAnswer`` if *raise_on_no_answer* is
- ``True`` and the query name exists but has no RRset of the
- desired type and class.
-
- Raises ``dns.resolver.NoNameservers`` if no non-broken
- nameservers are available to answer the question.
-
- Returns a ``dns.resolver.Answer`` instance.
-
- """
-
- resolution = _Resolution(
- self, qname, rdtype, rdclass, tcp, raise_on_no_answer, search
- )
- start = time.time()
- while True:
- (request, answer) = resolution.next_request()
- # Note we need to say "if answer is not None" and not just
- # "if answer" because answer implements __len__, and python
- # will call that. We want to return if we have an answer
- # object, including in cases where its length is 0.
- if answer is not None:
- # cache hit!
- return answer
- assert request is not None # needed for type checking
- done = False
- while not done:
- (nameserver, tcp, backoff) = resolution.next_nameserver()
- if backoff:
- time.sleep(backoff)
- timeout = self._compute_timeout(start, lifetime, resolution.errors)
- try:
- response = nameserver.query(
- request,
- timeout=timeout,
- source=source,
- source_port=source_port,
- max_size=tcp,
- )
- except Exception as ex:
- (_, done) = resolution.query_result(None, ex)
- continue
- (answer, done) = resolution.query_result(response, None)
- # Note we need to say "if answer is not None" and not just
- # "if answer" because answer implements __len__, and python
- # will call that. We want to return if we have an answer
- # object, including in cases where its length is 0.
- if answer is not None:
- return answer
-
- def query(
- self,
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- ) -> Answer: # pragma: no cover
- """Query nameservers to find the answer to the question.
-
- This method calls resolve() with ``search=True``, and is
- provided for backwards compatibility with prior versions of
- dnspython. See the documentation for the resolve() method for
- further details.
- """
- warnings.warn(
- "please use dns.resolver.Resolver.resolve() instead",
- DeprecationWarning,
- stacklevel=2,
- )
- return self.resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- True,
- )
-
- def resolve_address(self, ipaddr: str, *args: Any, **kwargs: Any) -> Answer:
- """Use a resolver to run a reverse query for PTR records.
-
- This utilizes the resolve() method to perform a PTR lookup on the
- specified IP address.
-
- *ipaddr*, a ``str``, the IPv4 or IPv6 address you want to get
- the PTR record for.
-
- All other arguments that can be passed to the resolve() function
- except for rdtype and rdclass are also supported by this
- function.
- """
- # We make a modified kwargs for type checking happiness, as otherwise
- # we get a legit warning about possibly having rdtype and rdclass
- # in the kwargs more than once.
- modified_kwargs: Dict[str, Any] = {}
- modified_kwargs.update(kwargs)
- modified_kwargs["rdtype"] = dns.rdatatype.PTR
- modified_kwargs["rdclass"] = dns.rdataclass.IN
- return self.resolve(
- dns.reversename.from_address(ipaddr), *args, **modified_kwargs
- )
-
- def resolve_name(
- self,
- name: Union[dns.name.Name, str],
- family: int = socket.AF_UNSPEC,
- **kwargs: Any,
- ) -> HostAnswers:
- """Use a resolver to query for address records.
-
- This utilizes the resolve() method to perform A and/or AAAA lookups on
- the specified name.
-
- *qname*, a ``dns.name.Name`` or ``str``, the name to resolve.
-
- *family*, an ``int``, the address family. If socket.AF_UNSPEC
- (the default), both A and AAAA records will be retrieved.
-
- All other arguments that can be passed to the resolve() function
- except for rdtype and rdclass are also supported by this
- function.
- """
- # We make a modified kwargs for type checking happiness, as otherwise
- # we get a legit warning about possibly having rdtype and rdclass
- # in the kwargs more than once.
- modified_kwargs: Dict[str, Any] = {}
- modified_kwargs.update(kwargs)
- modified_kwargs.pop("rdtype", None)
- modified_kwargs["rdclass"] = dns.rdataclass.IN
-
- if family == socket.AF_INET:
- v4 = self.resolve(name, dns.rdatatype.A, **modified_kwargs)
- return HostAnswers.make(v4=v4)
- elif family == socket.AF_INET6:
- v6 = self.resolve(name, dns.rdatatype.AAAA, **modified_kwargs)
- return HostAnswers.make(v6=v6)
- elif family != socket.AF_UNSPEC:
- raise NotImplementedError(f"unknown address family {family}")
-
- raise_on_no_answer = modified_kwargs.pop("raise_on_no_answer", True)
- lifetime = modified_kwargs.pop("lifetime", None)
- start = time.time()
- v6 = self.resolve(
- name,
- dns.rdatatype.AAAA,
- raise_on_no_answer=False,
- lifetime=self._compute_timeout(start, lifetime),
- **modified_kwargs,
- )
- # Note that setting name ensures we query the same name
- # for A as we did for AAAA. (This is just in case search lists
- # are active by default in the resolver configuration and
- # we might be talking to a server that says NXDOMAIN when it
- # wants to say NOERROR no data.
- name = v6.qname
- v4 = self.resolve(
- name,
- dns.rdatatype.A,
- raise_on_no_answer=False,
- lifetime=self._compute_timeout(start, lifetime),
- **modified_kwargs,
- )
- answers = HostAnswers.make(v6=v6, v4=v4, add_empty=not raise_on_no_answer)
- if not answers:
- raise NoAnswer(response=v6.response)
- return answers
-
- # pylint: disable=redefined-outer-name
-
- def canonical_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name:
- """Determine the canonical name of *name*.
-
- The canonical name is the name the resolver uses for queries
- after all CNAME and DNAME renamings have been applied.
-
- *name*, a ``dns.name.Name`` or ``str``, the query name.
-
- This method can raise any exception that ``resolve()`` can
- raise, other than ``dns.resolver.NoAnswer`` and
- ``dns.resolver.NXDOMAIN``.
-
- Returns a ``dns.name.Name``.
- """
- try:
- answer = self.resolve(name, raise_on_no_answer=False)
- canonical_name = answer.canonical_name
- except dns.resolver.NXDOMAIN as e:
- canonical_name = e.canonical_name
- return canonical_name
-
- # pylint: enable=redefined-outer-name
-
- def try_ddr(self, lifetime: float = 5.0) -> None:
- """Try to update the resolver's nameservers using Discovery of Designated
- Resolvers (DDR). If successful, the resolver will subsequently use
- DNS-over-HTTPS or DNS-over-TLS for future queries.
-
- *lifetime*, a float, is the maximum time to spend attempting DDR. The default
- is 5 seconds.
-
- If the SVCB query is successful and results in a non-empty list of nameservers,
- then the resolver's nameservers are set to the returned servers in priority
- order.
-
- The current implementation does not use any address hints from the SVCB record,
- nor does it resolve addresses for the SCVB target name, rather it assumes that
- the bootstrap nameserver will always be one of the addresses and uses it.
- A future revision to the code may offer fuller support. The code verifies that
- the bootstrap nameserver is in the Subject Alternative Name field of the
- TLS certficate.
- """
- try:
- expiration = time.time() + lifetime
- answer = self.resolve(
- dns._ddr._local_resolver_name, "SVCB", lifetime=lifetime
- )
- timeout = dns.query._remaining(expiration)
- nameservers = dns._ddr._get_nameservers_sync(answer, timeout)
- if len(nameservers) > 0:
- self.nameservers = nameservers
- except Exception:
- pass
-
-
-#: The default resolver.
-default_resolver: Optional[Resolver] = None
-
-
-def get_default_resolver() -> Resolver:
- """Get the default resolver, initializing it if necessary."""
- if default_resolver is None:
- reset_default_resolver()
- assert default_resolver is not None
- return default_resolver
-
-
-def reset_default_resolver() -> None:
- """Re-initialize default resolver.
-
- Note that the resolver configuration (i.e. /etc/resolv.conf on UNIX
- systems) will be re-read immediately.
- """
-
- global default_resolver
- default_resolver = Resolver()
-
-
-def resolve(
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
-) -> Answer: # pragma: no cover
- """Query nameservers to find the answer to the question.
-
- This is a convenience function that uses the default resolver
- object to make the query.
-
- See ``dns.resolver.Resolver.resolve`` for more information on the
- parameters.
- """
-
- return get_default_resolver().resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- search,
- )
-
-
-def query(
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
-) -> Answer: # pragma: no cover
- """Query nameservers to find the answer to the question.
-
- This method calls resolve() with ``search=True``, and is
- provided for backwards compatibility with prior versions of
- dnspython. See the documentation for the resolve() method for
- further details.
- """
- warnings.warn(
- "please use dns.resolver.resolve() instead", DeprecationWarning, stacklevel=2
- )
- return resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- True,
- )
-
-
-def resolve_address(ipaddr: str, *args: Any, **kwargs: Any) -> Answer:
- """Use a resolver to run a reverse query for PTR records.
-
- See ``dns.resolver.Resolver.resolve_address`` for more information on the
- parameters.
- """
-
- return get_default_resolver().resolve_address(ipaddr, *args, **kwargs)
-
-
-def resolve_name(
- name: Union[dns.name.Name, str], family: int = socket.AF_UNSPEC, **kwargs: Any
-) -> HostAnswers:
- """Use a resolver to query for address records.
-
- See ``dns.resolver.Resolver.resolve_name`` for more information on the
- parameters.
- """
-
- return get_default_resolver().resolve_name(name, family, **kwargs)
-
-
-def canonical_name(name: Union[dns.name.Name, str]) -> dns.name.Name:
- """Determine the canonical name of *name*.
-
- See ``dns.resolver.Resolver.canonical_name`` for more information on the
- parameters and possible exceptions.
- """
-
- return get_default_resolver().canonical_name(name)
-
-
-def try_ddr(lifetime: float = 5.0) -> None:
- """Try to update the default resolver's nameservers using Discovery of Designated
- Resolvers (DDR). If successful, the resolver will subsequently use
- DNS-over-HTTPS or DNS-over-TLS for future queries.
-
- See :py:func:`dns.resolver.Resolver.try_ddr` for more information.
- """
- return get_default_resolver().try_ddr(lifetime)
-
-
-def zone_for_name(
- name: Union[dns.name.Name, str],
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- tcp: bool = False,
- resolver: Optional[Resolver] = None,
- lifetime: Optional[float] = None,
-) -> dns.name.Name:
- """Find the name of the zone which contains the specified name.
-
- *name*, an absolute ``dns.name.Name`` or ``str``, the query name.
-
- *rdclass*, an ``int``, the query class.
-
- *tcp*, a ``bool``. If ``True``, use TCP to make the query.
-
- *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use.
- If ``None``, the default, then the default resolver is used.
-
- *lifetime*, a ``float``, the total time to allow for the queries needed
- to determine the zone. If ``None``, the default, then only the individual
- query limits of the resolver apply.
-
- Raises ``dns.resolver.NoRootSOA`` if there is no SOA RR at the DNS
- root. (This is only likely to happen if you're using non-default
- root servers in your network and they are misconfigured.)
-
- Raises ``dns.resolver.LifetimeTimeout`` if the answer could not be
- found in the allotted lifetime.
-
- Returns a ``dns.name.Name``.
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, dns.name.root)
- if resolver is None:
- resolver = get_default_resolver()
- if not name.is_absolute():
- raise NotAbsolute(name)
- start = time.time()
- expiration: Optional[float]
- if lifetime is not None:
- expiration = start + lifetime
- else:
- expiration = None
- while 1:
- try:
- rlifetime: Optional[float]
- if expiration is not None:
- rlifetime = expiration - time.time()
- if rlifetime <= 0:
- rlifetime = 0
- else:
- rlifetime = None
- answer = resolver.resolve(
- name, dns.rdatatype.SOA, rdclass, tcp, lifetime=rlifetime
- )
- assert answer.rrset is not None
- if answer.rrset.name == name:
- return name
- # otherwise we were CNAMEd or DNAMEd and need to look higher
- except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer) as e:
- if isinstance(e, dns.resolver.NXDOMAIN):
- response = e.responses().get(name)
- else:
- response = e.response() # pylint: disable=no-value-for-parameter
- if response:
- for rrs in response.authority:
- if rrs.rdtype == dns.rdatatype.SOA and rrs.rdclass == rdclass:
- (nr, _, _) = rrs.name.fullcompare(name)
- if nr == dns.name.NAMERELN_SUPERDOMAIN:
- # We're doing a proper superdomain check as
- # if the name were equal we ought to have gotten
- # it in the answer section! We are ignoring the
- # possibility that the authority is insane and
- # is including multiple SOA RRs for different
- # authorities.
- return rrs.name
- # we couldn't extract anything useful from the response (e.g. it's
- # a type 3 NXDOMAIN)
- try:
- name = name.parent()
- except dns.name.NoParent:
- raise NoRootSOA
-
-
-def make_resolver_at(
- where: Union[dns.name.Name, str],
- port: int = 53,
- family: int = socket.AF_UNSPEC,
- resolver: Optional[Resolver] = None,
-) -> Resolver:
- """Make a stub resolver using the specified destination as the full resolver.
-
- *where*, a ``dns.name.Name`` or ``str`` the domain name or IP address of the
- full resolver.
-
- *port*, an ``int``, the port to use. If not specified, the default is 53.
-
- *family*, an ``int``, the address family to use. This parameter is used if
- *where* is not an address. The default is ``socket.AF_UNSPEC`` in which case
- the first address returned by ``resolve_name()`` will be used, otherwise the
- first address of the specified family will be used.
-
- *resolver*, a ``dns.resolver.Resolver`` or ``None``, the resolver to use for
- resolution of hostnames. If not specified, the default resolver will be used.
-
- Returns a ``dns.resolver.Resolver`` or raises an exception.
- """
- if resolver is None:
- resolver = get_default_resolver()
- nameservers: List[Union[str, dns.nameserver.Nameserver]] = []
- if isinstance(where, str) and dns.inet.is_address(where):
- nameservers.append(dns.nameserver.Do53Nameserver(where, port))
- else:
- for address in resolver.resolve_name(where, family).addresses():
- nameservers.append(dns.nameserver.Do53Nameserver(address, port))
- res = dns.resolver.Resolver(configure=False)
- res.nameservers = nameservers
- return res
-
-
-def resolve_at(
- where: Union[dns.name.Name, str],
- qname: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.A,
- rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- tcp: bool = False,
- source: Optional[str] = None,
- raise_on_no_answer: bool = True,
- source_port: int = 0,
- lifetime: Optional[float] = None,
- search: Optional[bool] = None,
- port: int = 53,
- family: int = socket.AF_UNSPEC,
- resolver: Optional[Resolver] = None,
-) -> Answer:
- """Query nameservers to find the answer to the question.
-
- This is a convenience function that calls ``dns.resolver.make_resolver_at()`` to
- make a resolver, and then uses it to resolve the query.
-
- See ``dns.resolver.Resolver.resolve`` for more information on the resolution
- parameters, and ``dns.resolver.make_resolver_at`` for information about the resolver
- parameters *where*, *port*, *family*, and *resolver*.
-
- If making more than one query, it is more efficient to call
- ``dns.resolver.make_resolver_at()`` and then use that resolver for the queries
- instead of calling ``resolve_at()`` multiple times.
- """
- return make_resolver_at(where, port, family, resolver).resolve(
- qname,
- rdtype,
- rdclass,
- tcp,
- source,
- raise_on_no_answer,
- source_port,
- lifetime,
- search,
- )
-
-
-#
-# Support for overriding the system resolver for all python code in the
-# running process.
-#
-
-_protocols_for_socktype = {
- socket.SOCK_DGRAM: [socket.SOL_UDP],
- socket.SOCK_STREAM: [socket.SOL_TCP],
-}
-
-_resolver = None
-_original_getaddrinfo = socket.getaddrinfo
-_original_getnameinfo = socket.getnameinfo
-_original_getfqdn = socket.getfqdn
-_original_gethostbyname = socket.gethostbyname
-_original_gethostbyname_ex = socket.gethostbyname_ex
-_original_gethostbyaddr = socket.gethostbyaddr
-
-
-def _getaddrinfo(
- host=None, service=None, family=socket.AF_UNSPEC, socktype=0, proto=0, flags=0
-):
- if flags & socket.AI_NUMERICHOST != 0:
- # Short circuit directly into the system's getaddrinfo(). We're
- # not adding any value in this case, and this avoids infinite loops
- # because dns.query.* needs to call getaddrinfo() for IPv6 scoping
- # reasons. We will also do this short circuit below if we
- # discover that the host is an address literal.
- return _original_getaddrinfo(host, service, family, socktype, proto, flags)
- if flags & (socket.AI_ADDRCONFIG | socket.AI_V4MAPPED) != 0:
- # Not implemented. We raise a gaierror as opposed to a
- # NotImplementedError as it helps callers handle errors more
- # appropriately. [Issue #316]
- #
- # We raise EAI_FAIL as opposed to EAI_SYSTEM because there is
- # no EAI_SYSTEM on Windows [Issue #416]. We didn't go for
- # EAI_BADFLAGS as the flags aren't bad, we just don't
- # implement them.
- raise socket.gaierror(
- socket.EAI_FAIL, "Non-recoverable failure in name resolution"
- )
- if host is None and service is None:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- addrs = []
- canonical_name = None # pylint: disable=redefined-outer-name
- # Is host None or an address literal? If so, use the system's
- # getaddrinfo().
- if host is None:
- return _original_getaddrinfo(host, service, family, socktype, proto, flags)
- try:
- # We don't care about the result of af_for_address(), we're just
- # calling it so it raises an exception if host is not an IPv4 or
- # IPv6 address.
- dns.inet.af_for_address(host)
- return _original_getaddrinfo(host, service, family, socktype, proto, flags)
- except Exception:
- pass
- # Something needs resolution!
- try:
- answers = _resolver.resolve_name(host, family)
- addrs = answers.addresses_and_families()
- canonical_name = answers.canonical_name().to_text(True)
- except dns.resolver.NXDOMAIN:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- except Exception:
- # We raise EAI_AGAIN here as the failure may be temporary
- # (e.g. a timeout) and EAI_SYSTEM isn't defined on Windows.
- # [Issue #416]
- raise socket.gaierror(socket.EAI_AGAIN, "Temporary failure in name resolution")
- port = None
- try:
- # Is it a port literal?
- if service is None:
- port = 0
- else:
- port = int(service)
- except Exception:
- if flags & socket.AI_NUMERICSERV == 0:
- try:
- port = socket.getservbyname(service)
- except Exception:
- pass
- if port is None:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- tuples = []
- if socktype == 0:
- socktypes = [socket.SOCK_DGRAM, socket.SOCK_STREAM]
- else:
- socktypes = [socktype]
- if flags & socket.AI_CANONNAME != 0:
- cname = canonical_name
- else:
- cname = ""
- for addr, af in addrs:
- for socktype in socktypes:
- for proto in _protocols_for_socktype[socktype]:
- addr_tuple = dns.inet.low_level_address_tuple((addr, port), af)
- tuples.append((af, socktype, proto, cname, addr_tuple))
- if len(tuples) == 0:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- return tuples
-
-
-def _getnameinfo(sockaddr, flags=0):
- host = sockaddr[0]
- port = sockaddr[1]
- if len(sockaddr) == 4:
- scope = sockaddr[3]
- family = socket.AF_INET6
- else:
- scope = None
- family = socket.AF_INET
- tuples = _getaddrinfo(host, port, family, socket.SOCK_STREAM, socket.SOL_TCP, 0)
- if len(tuples) > 1:
- raise socket.error("sockaddr resolved to multiple addresses")
- addr = tuples[0][4][0]
- if flags & socket.NI_DGRAM:
- pname = "udp"
- else:
- pname = "tcp"
- qname = dns.reversename.from_address(addr)
- if flags & socket.NI_NUMERICHOST == 0:
- try:
- answer = _resolver.resolve(qname, "PTR")
- hostname = answer.rrset[0].target.to_text(True)
- except (dns.resolver.NXDOMAIN, dns.resolver.NoAnswer):
- if flags & socket.NI_NAMEREQD:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- hostname = addr
- if scope is not None:
- hostname += "%" + str(scope)
- else:
- hostname = addr
- if scope is not None:
- hostname += "%" + str(scope)
- if flags & socket.NI_NUMERICSERV:
- service = str(port)
- else:
- service = socket.getservbyport(port, pname)
- return (hostname, service)
-
-
-def _getfqdn(name=None):
- if name is None:
- name = socket.gethostname()
- try:
- (name, _, _) = _gethostbyaddr(name)
- # Python's version checks aliases too, but our gethostbyname
- # ignores them, so we do so here as well.
- except Exception:
- pass
- return name
-
-
-def _gethostbyname(name):
- return _gethostbyname_ex(name)[2][0]
-
-
-def _gethostbyname_ex(name):
- aliases = []
- addresses = []
- tuples = _getaddrinfo(
- name, 0, socket.AF_INET, socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_CANONNAME
- )
- canonical = tuples[0][3]
- for item in tuples:
- addresses.append(item[4][0])
- # XXX we just ignore aliases
- return (canonical, aliases, addresses)
-
-
-def _gethostbyaddr(ip):
- try:
- dns.ipv6.inet_aton(ip)
- sockaddr = (ip, 80, 0, 0)
- family = socket.AF_INET6
- except Exception:
- try:
- dns.ipv4.inet_aton(ip)
- except Exception:
- raise socket.gaierror(socket.EAI_NONAME, "Name or service not known")
- sockaddr = (ip, 80)
- family = socket.AF_INET
- (name, _) = _getnameinfo(sockaddr, socket.NI_NAMEREQD)
- aliases = []
- addresses = []
- tuples = _getaddrinfo(
- name, 0, family, socket.SOCK_STREAM, socket.SOL_TCP, socket.AI_CANONNAME
- )
- canonical = tuples[0][3]
- # We only want to include an address from the tuples if it's the
- # same as the one we asked about. We do this comparison in binary
- # to avoid any differences in text representations.
- bin_ip = dns.inet.inet_pton(family, ip)
- for item in tuples:
- addr = item[4][0]
- bin_addr = dns.inet.inet_pton(family, addr)
- if bin_ip == bin_addr:
- addresses.append(addr)
- # XXX we just ignore aliases
- return (canonical, aliases, addresses)
-
-
-def override_system_resolver(resolver: Optional[Resolver] = None) -> None:
- """Override the system resolver routines in the socket module with
- versions which use dnspython's resolver.
-
- This can be useful in testing situations where you want to control
- the resolution behavior of python code without having to change
- the system's resolver settings (e.g. /etc/resolv.conf).
-
- The resolver to use may be specified; if it's not, the default
- resolver will be used.
-
- resolver, a ``dns.resolver.Resolver`` or ``None``, the resolver to use.
- """
-
- if resolver is None:
- resolver = get_default_resolver()
- global _resolver
- _resolver = resolver
- socket.getaddrinfo = _getaddrinfo
- socket.getnameinfo = _getnameinfo
- socket.getfqdn = _getfqdn
- socket.gethostbyname = _gethostbyname
- socket.gethostbyname_ex = _gethostbyname_ex
- socket.gethostbyaddr = _gethostbyaddr
-
-
-def restore_system_resolver() -> None:
- """Undo the effects of prior override_system_resolver()."""
-
- global _resolver
- _resolver = None
- socket.getaddrinfo = _original_getaddrinfo
- socket.getnameinfo = _original_getnameinfo
- socket.getfqdn = _original_getfqdn
- socket.gethostbyname = _original_gethostbyname
- socket.gethostbyname_ex = _original_gethostbyname_ex
- socket.gethostbyaddr = _original_gethostbyaddr
diff --git a/.venv/lib/python3.12/site-packages/dns/reversename.py b/.venv/lib/python3.12/site-packages/dns/reversename.py
deleted file mode 100644
index 8236c71..0000000
--- a/.venv/lib/python3.12/site-packages/dns/reversename.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2006-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Reverse Map Names."""
-
-import binascii
-
-import dns.ipv4
-import dns.ipv6
-import dns.name
-
-ipv4_reverse_domain = dns.name.from_text("in-addr.arpa.")
-ipv6_reverse_domain = dns.name.from_text("ip6.arpa.")
-
-
-def from_address(
- text: str,
- v4_origin: dns.name.Name = ipv4_reverse_domain,
- v6_origin: dns.name.Name = ipv6_reverse_domain,
-) -> dns.name.Name:
- """Convert an IPv4 or IPv6 address in textual form into a Name object whose
- value is the reverse-map domain name of the address.
-
- *text*, a ``str``, is an IPv4 or IPv6 address in textual form
- (e.g. '127.0.0.1', '::1')
-
- *v4_origin*, a ``dns.name.Name`` to append to the labels corresponding to
- the address if the address is an IPv4 address, instead of the default
- (in-addr.arpa.)
-
- *v6_origin*, a ``dns.name.Name`` to append to the labels corresponding to
- the address if the address is an IPv6 address, instead of the default
- (ip6.arpa.)
-
- Raises ``dns.exception.SyntaxError`` if the address is badly formed.
-
- Returns a ``dns.name.Name``.
- """
-
- try:
- v6 = dns.ipv6.inet_aton(text)
- if dns.ipv6.is_mapped(v6):
- parts = ["%d" % byte for byte in v6[12:]]
- origin = v4_origin
- else:
- parts = [x for x in str(binascii.hexlify(v6).decode())]
- origin = v6_origin
- except Exception:
- parts = ["%d" % byte for byte in dns.ipv4.inet_aton(text)]
- origin = v4_origin
- return dns.name.from_text(".".join(reversed(parts)), origin=origin)
-
-
-def to_address(
- name: dns.name.Name,
- v4_origin: dns.name.Name = ipv4_reverse_domain,
- v6_origin: dns.name.Name = ipv6_reverse_domain,
-) -> str:
- """Convert a reverse map domain name into textual address form.
-
- *name*, a ``dns.name.Name``, an IPv4 or IPv6 address in reverse-map name
- form.
-
- *v4_origin*, a ``dns.name.Name`` representing the top-level domain for
- IPv4 addresses, instead of the default (in-addr.arpa.)
-
- *v6_origin*, a ``dns.name.Name`` representing the top-level domain for
- IPv4 addresses, instead of the default (ip6.arpa.)
-
- Raises ``dns.exception.SyntaxError`` if the name does not have a
- reverse-map form.
-
- Returns a ``str``.
- """
-
- if name.is_subdomain(v4_origin):
- name = name.relativize(v4_origin)
- text = b".".join(reversed(name.labels))
- # run through inet_ntoa() to check syntax and make pretty.
- return dns.ipv4.inet_ntoa(dns.ipv4.inet_aton(text))
- elif name.is_subdomain(v6_origin):
- name = name.relativize(v6_origin)
- labels = list(reversed(name.labels))
- parts = []
- for i in range(0, len(labels), 4):
- parts.append(b"".join(labels[i : i + 4]))
- text = b":".join(parts)
- # run through inet_ntoa() to check syntax and make pretty.
- return dns.ipv6.inet_ntoa(dns.ipv6.inet_aton(text))
- else:
- raise dns.exception.SyntaxError("unknown reverse-map address family")
diff --git a/.venv/lib/python3.12/site-packages/dns/rrset.py b/.venv/lib/python3.12/site-packages/dns/rrset.py
deleted file mode 100644
index 6f39b10..0000000
--- a/.venv/lib/python3.12/site-packages/dns/rrset.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS RRsets (an RRset is a named rdataset)"""
-
-from typing import Any, Collection, Dict, Optional, Union, cast
-
-import dns.name
-import dns.rdataclass
-import dns.rdataset
-import dns.renderer
-
-
-class RRset(dns.rdataset.Rdataset):
- """A DNS RRset (named rdataset).
-
- RRset inherits from Rdataset, and RRsets can be treated as
- Rdatasets in most cases. There are, however, a few notable
- exceptions. RRsets have different to_wire() and to_text() method
- arguments, reflecting the fact that RRsets always have an owner
- name.
- """
-
- __slots__ = ["name", "deleting"]
-
- def __init__(
- self,
- name: dns.name.Name,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- deleting: Optional[dns.rdataclass.RdataClass] = None,
- ):
- """Create a new RRset."""
-
- super().__init__(rdclass, rdtype, covers)
- self.name = name
- self.deleting = deleting
-
- def _clone(self):
- obj = super()._clone()
- obj.name = self.name
- obj.deleting = self.deleting
- return obj
-
- def __repr__(self):
- if self.covers == 0:
- ctext = ""
- else:
- ctext = "(" + dns.rdatatype.to_text(self.covers) + ")"
- if self.deleting is not None:
- dtext = " delete=" + dns.rdataclass.to_text(self.deleting)
- else:
- dtext = ""
- return (
- ""
- )
-
- def __str__(self):
- return self.to_text()
-
- def __eq__(self, other):
- if isinstance(other, RRset):
- if self.name != other.name:
- return False
- elif not isinstance(other, dns.rdataset.Rdataset):
- return False
- return super().__eq__(other)
-
- def match(self, *args: Any, **kwargs: Any) -> bool: # type: ignore[override]
- """Does this rrset match the specified attributes?
-
- Behaves as :py:func:`full_match()` if the first argument is a
- ``dns.name.Name``, and as :py:func:`dns.rdataset.Rdataset.match()`
- otherwise.
-
- (This behavior fixes a design mistake where the signature of this
- method became incompatible with that of its superclass. The fix
- makes RRsets matchable as Rdatasets while preserving backwards
- compatibility.)
- """
- if isinstance(args[0], dns.name.Name):
- return self.full_match(*args, **kwargs) # type: ignore[arg-type]
- else:
- return super().match(*args, **kwargs) # type: ignore[arg-type]
-
- def full_match(
- self,
- name: dns.name.Name,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType,
- deleting: Optional[dns.rdataclass.RdataClass] = None,
- ) -> bool:
- """Returns ``True`` if this rrset matches the specified name, class,
- type, covers, and deletion state.
- """
- if not super().match(rdclass, rdtype, covers):
- return False
- if self.name != name or self.deleting != deleting:
- return False
- return True
-
- # pylint: disable=arguments-differ
-
- def to_text( # type: ignore[override]
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- **kw: Dict[str, Any],
- ) -> str:
- """Convert the RRset into DNS zone file format.
-
- See ``dns.name.Name.choose_relativity`` for more information
- on how *origin* and *relativize* determine the way names
- are emitted.
-
- Any additional keyword arguments are passed on to the rdata
- ``to_text()`` method.
-
- *origin*, a ``dns.name.Name`` or ``None``, the origin for relative
- names.
-
- *relativize*, a ``bool``. If ``True``, names will be relativized
- to *origin*.
- """
-
- return super().to_text(
- self.name, origin, relativize, self.deleting, **kw # type: ignore
- )
-
- def to_wire( # type: ignore[override]
- self,
- file: Any,
- compress: Optional[dns.name.CompressType] = None, # type: ignore
- origin: Optional[dns.name.Name] = None,
- **kw: Dict[str, Any],
- ) -> int:
- """Convert the RRset to wire format.
-
- All keyword arguments are passed to ``dns.rdataset.to_wire()``; see
- that function for details.
-
- Returns an ``int``, the number of records emitted.
- """
-
- return super().to_wire(
- self.name, file, compress, origin, self.deleting, **kw # type:ignore
- )
-
- # pylint: enable=arguments-differ
-
- def to_rdataset(self) -> dns.rdataset.Rdataset:
- """Convert an RRset into an Rdataset.
-
- Returns a ``dns.rdataset.Rdataset``.
- """
- return dns.rdataset.from_rdata_list(self.ttl, list(self))
-
-
-def from_text_list(
- name: Union[dns.name.Name, str],
- ttl: int,
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- text_rdatas: Collection[str],
- idna_codec: Optional[dns.name.IDNACodec] = None,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = True,
- relativize_to: Optional[dns.name.Name] = None,
-) -> RRset:
- """Create an RRset with the specified name, TTL, class, and type, and with
- the specified list of rdatas in text format.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder to use; if ``None``, the default IDNA 2003
- encoder/decoder is used.
-
- *origin*, a ``dns.name.Name`` (or ``None``), the
- origin to use for relative names.
-
- *relativize*, a ``bool``. If true, name will be relativized.
-
- *relativize_to*, a ``dns.name.Name`` (or ``None``), the origin to use
- when relativizing names. If not set, the *origin* value will be used.
-
- Returns a ``dns.rrset.RRset`` object.
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None, idna_codec=idna_codec)
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- r = RRset(name, rdclass, rdtype)
- r.update_ttl(ttl)
- for t in text_rdatas:
- rd = dns.rdata.from_text(
- r.rdclass, r.rdtype, t, origin, relativize, relativize_to, idna_codec
- )
- r.add(rd)
- return r
-
-
-def from_text(
- name: Union[dns.name.Name, str],
- ttl: int,
- rdclass: Union[dns.rdataclass.RdataClass, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- *text_rdatas: Any,
-) -> RRset:
- """Create an RRset with the specified name, TTL, class, and type and with
- the specified rdatas in text format.
-
- Returns a ``dns.rrset.RRset`` object.
- """
-
- return from_text_list(
- name, ttl, rdclass, rdtype, cast(Collection[str], text_rdatas)
- )
-
-
-def from_rdata_list(
- name: Union[dns.name.Name, str],
- ttl: int,
- rdatas: Collection[dns.rdata.Rdata],
- idna_codec: Optional[dns.name.IDNACodec] = None,
-) -> RRset:
- """Create an RRset with the specified name and TTL, and with
- the specified list of rdata objects.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder to use; if ``None``, the default IDNA 2003
- encoder/decoder is used.
-
- Returns a ``dns.rrset.RRset`` object.
-
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None, idna_codec=idna_codec)
-
- if len(rdatas) == 0:
- raise ValueError("rdata list must not be empty")
- r = None
- for rd in rdatas:
- if r is None:
- r = RRset(name, rd.rdclass, rd.rdtype)
- r.update_ttl(ttl)
- r.add(rd)
- assert r is not None
- return r
-
-
-def from_rdata(name: Union[dns.name.Name, str], ttl: int, *rdatas: Any) -> RRset:
- """Create an RRset with the specified name and TTL, and with
- the specified rdata objects.
-
- Returns a ``dns.rrset.RRset`` object.
- """
-
- return from_rdata_list(name, ttl, cast(Collection[dns.rdata.Rdata], rdatas))
diff --git a/.venv/lib/python3.12/site-packages/dns/serial.py b/.venv/lib/python3.12/site-packages/dns/serial.py
deleted file mode 100644
index 3417299..0000000
--- a/.venv/lib/python3.12/site-packages/dns/serial.py
+++ /dev/null
@@ -1,118 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-"""Serial Number Arthimetic from RFC 1982"""
-
-
-class Serial:
- def __init__(self, value: int, bits: int = 32):
- self.value = value % 2**bits
- self.bits = bits
-
- def __repr__(self):
- return f"dns.serial.Serial({self.value}, {self.bits})"
-
- def __eq__(self, other):
- if isinstance(other, int):
- other = Serial(other, self.bits)
- elif not isinstance(other, Serial) or other.bits != self.bits:
- return NotImplemented
- return self.value == other.value
-
- def __ne__(self, other):
- if isinstance(other, int):
- other = Serial(other, self.bits)
- elif not isinstance(other, Serial) or other.bits != self.bits:
- return NotImplemented
- return self.value != other.value
-
- def __lt__(self, other):
- if isinstance(other, int):
- other = Serial(other, self.bits)
- elif not isinstance(other, Serial) or other.bits != self.bits:
- return NotImplemented
- if self.value < other.value and other.value - self.value < 2 ** (self.bits - 1):
- return True
- elif self.value > other.value and self.value - other.value > 2 ** (
- self.bits - 1
- ):
- return True
- else:
- return False
-
- def __le__(self, other):
- return self == other or self < other
-
- def __gt__(self, other):
- if isinstance(other, int):
- other = Serial(other, self.bits)
- elif not isinstance(other, Serial) or other.bits != self.bits:
- return NotImplemented
- if self.value < other.value and other.value - self.value > 2 ** (self.bits - 1):
- return True
- elif self.value > other.value and self.value - other.value < 2 ** (
- self.bits - 1
- ):
- return True
- else:
- return False
-
- def __ge__(self, other):
- return self == other or self > other
-
- def __add__(self, other):
- v = self.value
- if isinstance(other, Serial):
- delta = other.value
- elif isinstance(other, int):
- delta = other
- else:
- raise ValueError
- if abs(delta) > (2 ** (self.bits - 1) - 1):
- raise ValueError
- v += delta
- v = v % 2**self.bits
- return Serial(v, self.bits)
-
- def __iadd__(self, other):
- v = self.value
- if isinstance(other, Serial):
- delta = other.value
- elif isinstance(other, int):
- delta = other
- else:
- raise ValueError
- if abs(delta) > (2 ** (self.bits - 1) - 1):
- raise ValueError
- v += delta
- v = v % 2**self.bits
- self.value = v
- return self
-
- def __sub__(self, other):
- v = self.value
- if isinstance(other, Serial):
- delta = other.value
- elif isinstance(other, int):
- delta = other
- else:
- raise ValueError
- if abs(delta) > (2 ** (self.bits - 1) - 1):
- raise ValueError
- v -= delta
- v = v % 2**self.bits
- return Serial(v, self.bits)
-
- def __isub__(self, other):
- v = self.value
- if isinstance(other, Serial):
- delta = other.value
- elif isinstance(other, int):
- delta = other
- else:
- raise ValueError
- if abs(delta) > (2 ** (self.bits - 1) - 1):
- raise ValueError
- v -= delta
- v = v % 2**self.bits
- self.value = v
- return self
diff --git a/.venv/lib/python3.12/site-packages/dns/set.py b/.venv/lib/python3.12/site-packages/dns/set.py
deleted file mode 100644
index f0fb0d5..0000000
--- a/.venv/lib/python3.12/site-packages/dns/set.py
+++ /dev/null
@@ -1,307 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-import itertools
-
-
-class Set:
- """A simple set class.
-
- This class was originally used to deal with sets being missing in
- ancient versions of python, but dnspython will continue to use it
- as these sets are based on lists and are thus indexable, and this
- ability is widely used in dnspython applications.
- """
-
- __slots__ = ["items"]
-
- def __init__(self, items=None):
- """Initialize the set.
-
- *items*, an iterable or ``None``, the initial set of items.
- """
-
- self.items = dict()
- if items is not None:
- for item in items:
- # This is safe for how we use set, but if other code
- # subclasses it could be a legitimate issue.
- self.add(item) # lgtm[py/init-calls-subclass]
-
- def __repr__(self):
- return "dns.set.Set(%s)" % repr(list(self.items.keys()))
-
- def add(self, item):
- """Add an item to the set."""
-
- if item not in self.items:
- self.items[item] = None
-
- def remove(self, item):
- """Remove an item from the set."""
-
- try:
- del self.items[item]
- except KeyError:
- raise ValueError
-
- def discard(self, item):
- """Remove an item from the set if present."""
-
- self.items.pop(item, None)
-
- def pop(self):
- """Remove an arbitrary item from the set."""
- (k, _) = self.items.popitem()
- return k
-
- def _clone(self) -> "Set":
- """Make a (shallow) copy of the set.
-
- There is a 'clone protocol' that subclasses of this class
- should use. To make a copy, first call your super's _clone()
- method, and use the object returned as the new instance. Then
- make shallow copies of the attributes defined in the subclass.
-
- This protocol allows us to write the set algorithms that
- return new instances (e.g. union) once, and keep using them in
- subclasses.
- """
-
- if hasattr(self, "_clone_class"):
- cls = self._clone_class # type: ignore
- else:
- cls = self.__class__
- obj = cls.__new__(cls)
- obj.items = dict()
- obj.items.update(self.items)
- return obj
-
- def __copy__(self):
- """Make a (shallow) copy of the set."""
-
- return self._clone()
-
- def copy(self):
- """Make a (shallow) copy of the set."""
-
- return self._clone()
-
- def union_update(self, other):
- """Update the set, adding any elements from other which are not
- already in the set.
- """
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- if self is other: # lgtm[py/comparison-using-is]
- return
- for item in other.items:
- self.add(item)
-
- def intersection_update(self, other):
- """Update the set, removing any elements from other which are not
- in both sets.
- """
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- if self is other: # lgtm[py/comparison-using-is]
- return
- # we make a copy of the list so that we can remove items from
- # the list without breaking the iterator.
- for item in list(self.items):
- if item not in other.items:
- del self.items[item]
-
- def difference_update(self, other):
- """Update the set, removing any elements from other which are in
- the set.
- """
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- if self is other: # lgtm[py/comparison-using-is]
- self.items.clear()
- else:
- for item in other.items:
- self.discard(item)
-
- def symmetric_difference_update(self, other):
- """Update the set, retaining only elements unique to both sets."""
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- if self is other: # lgtm[py/comparison-using-is]
- self.items.clear()
- else:
- overlap = self.intersection(other)
- self.union_update(other)
- self.difference_update(overlap)
-
- def union(self, other):
- """Return a new set which is the union of ``self`` and ``other``.
-
- Returns the same Set type as this set.
- """
-
- obj = self._clone()
- obj.union_update(other)
- return obj
-
- def intersection(self, other):
- """Return a new set which is the intersection of ``self`` and
- ``other``.
-
- Returns the same Set type as this set.
- """
-
- obj = self._clone()
- obj.intersection_update(other)
- return obj
-
- def difference(self, other):
- """Return a new set which ``self`` - ``other``, i.e. the items
- in ``self`` which are not also in ``other``.
-
- Returns the same Set type as this set.
- """
-
- obj = self._clone()
- obj.difference_update(other)
- return obj
-
- def symmetric_difference(self, other):
- """Return a new set which (``self`` - ``other``) | (``other``
- - ``self), ie: the items in either ``self`` or ``other`` which
- are not contained in their intersection.
-
- Returns the same Set type as this set.
- """
-
- obj = self._clone()
- obj.symmetric_difference_update(other)
- return obj
-
- def __or__(self, other):
- return self.union(other)
-
- def __and__(self, other):
- return self.intersection(other)
-
- def __add__(self, other):
- return self.union(other)
-
- def __sub__(self, other):
- return self.difference(other)
-
- def __xor__(self, other):
- return self.symmetric_difference(other)
-
- def __ior__(self, other):
- self.union_update(other)
- return self
-
- def __iand__(self, other):
- self.intersection_update(other)
- return self
-
- def __iadd__(self, other):
- self.union_update(other)
- return self
-
- def __isub__(self, other):
- self.difference_update(other)
- return self
-
- def __ixor__(self, other):
- self.symmetric_difference_update(other)
- return self
-
- def update(self, other):
- """Update the set, adding any elements from other which are not
- already in the set.
-
- *other*, the collection of items with which to update the set, which
- may be any iterable type.
- """
-
- for item in other:
- self.add(item)
-
- def clear(self):
- """Make the set empty."""
- self.items.clear()
-
- def __eq__(self, other):
- return self.items == other.items
-
- def __ne__(self, other):
- return not self.__eq__(other)
-
- def __len__(self):
- return len(self.items)
-
- def __iter__(self):
- return iter(self.items)
-
- def __getitem__(self, i):
- if isinstance(i, slice):
- return list(itertools.islice(self.items, i.start, i.stop, i.step))
- else:
- return next(itertools.islice(self.items, i, i + 1))
-
- def __delitem__(self, i):
- if isinstance(i, slice):
- for elt in list(self[i]):
- del self.items[elt]
- else:
- del self.items[self[i]]
-
- def issubset(self, other):
- """Is this set a subset of *other*?
-
- Returns a ``bool``.
- """
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- for item in self.items:
- if item not in other.items:
- return False
- return True
-
- def issuperset(self, other):
- """Is this set a superset of *other*?
-
- Returns a ``bool``.
- """
-
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- for item in other.items:
- if item not in self.items:
- return False
- return True
-
- def isdisjoint(self, other):
- if not isinstance(other, Set):
- raise ValueError("other must be a Set instance")
- for item in other.items:
- if item in self.items:
- return False
- return True
diff --git a/.venv/lib/python3.12/site-packages/dns/tokenizer.py b/.venv/lib/python3.12/site-packages/dns/tokenizer.py
deleted file mode 100644
index 454cac4..0000000
--- a/.venv/lib/python3.12/site-packages/dns/tokenizer.py
+++ /dev/null
@@ -1,708 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""Tokenize DNS zone file format"""
-
-import io
-import sys
-from typing import Any, List, Optional, Tuple
-
-import dns.exception
-import dns.name
-import dns.ttl
-
-_DELIMITERS = {" ", "\t", "\n", ";", "(", ")", '"'}
-_QUOTING_DELIMITERS = {'"'}
-
-EOF = 0
-EOL = 1
-WHITESPACE = 2
-IDENTIFIER = 3
-QUOTED_STRING = 4
-COMMENT = 5
-DELIMITER = 6
-
-
-class UngetBufferFull(dns.exception.DNSException):
- """An attempt was made to unget a token when the unget buffer was full."""
-
-
-class Token:
- """A DNS zone file format token.
-
- ttype: The token type
- value: The token value
- has_escape: Does the token value contain escapes?
- """
-
- def __init__(
- self,
- ttype: int,
- value: Any = "",
- has_escape: bool = False,
- comment: Optional[str] = None,
- ):
- """Initialize a token instance."""
-
- self.ttype = ttype
- self.value = value
- self.has_escape = has_escape
- self.comment = comment
-
- def is_eof(self) -> bool:
- return self.ttype == EOF
-
- def is_eol(self) -> bool:
- return self.ttype == EOL
-
- def is_whitespace(self) -> bool:
- return self.ttype == WHITESPACE
-
- def is_identifier(self) -> bool:
- return self.ttype == IDENTIFIER
-
- def is_quoted_string(self) -> bool:
- return self.ttype == QUOTED_STRING
-
- def is_comment(self) -> bool:
- return self.ttype == COMMENT
-
- def is_delimiter(self) -> bool: # pragma: no cover (we don't return delimiters yet)
- return self.ttype == DELIMITER
-
- def is_eol_or_eof(self) -> bool:
- return self.ttype == EOL or self.ttype == EOF
-
- def __eq__(self, other):
- if not isinstance(other, Token):
- return False
- return self.ttype == other.ttype and self.value == other.value
-
- def __ne__(self, other):
- if not isinstance(other, Token):
- return True
- return self.ttype != other.ttype or self.value != other.value
-
- def __str__(self):
- return '%d "%s"' % (self.ttype, self.value)
-
- def unescape(self) -> "Token":
- if not self.has_escape:
- return self
- unescaped = ""
- l = len(self.value)
- i = 0
- while i < l:
- c = self.value[i]
- i += 1
- if c == "\\":
- if i >= l: # pragma: no cover (can't happen via get())
- raise dns.exception.UnexpectedEnd
- c = self.value[i]
- i += 1
- if c.isdigit():
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c2 = self.value[i]
- i += 1
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c3 = self.value[i]
- i += 1
- if not (c2.isdigit() and c3.isdigit()):
- raise dns.exception.SyntaxError
- codepoint = int(c) * 100 + int(c2) * 10 + int(c3)
- if codepoint > 255:
- raise dns.exception.SyntaxError
- c = chr(codepoint)
- unescaped += c
- return Token(self.ttype, unescaped)
-
- def unescape_to_bytes(self) -> "Token":
- # We used to use unescape() for TXT-like records, but this
- # caused problems as we'd process DNS escapes into Unicode code
- # points instead of byte values, and then a to_text() of the
- # processed data would not equal the original input. For
- # example, \226 in the TXT record would have a to_text() of
- # \195\162 because we applied UTF-8 encoding to Unicode code
- # point 226.
- #
- # We now apply escapes while converting directly to bytes,
- # avoiding this double encoding.
- #
- # This code also handles cases where the unicode input has
- # non-ASCII code-points in it by converting it to UTF-8. TXT
- # records aren't defined for Unicode, but this is the best we
- # can do to preserve meaning. For example,
- #
- # foo\u200bbar
- #
- # (where \u200b is Unicode code point 0x200b) will be treated
- # as if the input had been the UTF-8 encoding of that string,
- # namely:
- #
- # foo\226\128\139bar
- #
- unescaped = b""
- l = len(self.value)
- i = 0
- while i < l:
- c = self.value[i]
- i += 1
- if c == "\\":
- if i >= l: # pragma: no cover (can't happen via get())
- raise dns.exception.UnexpectedEnd
- c = self.value[i]
- i += 1
- if c.isdigit():
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c2 = self.value[i]
- i += 1
- if i >= l:
- raise dns.exception.UnexpectedEnd
- c3 = self.value[i]
- i += 1
- if not (c2.isdigit() and c3.isdigit()):
- raise dns.exception.SyntaxError
- codepoint = int(c) * 100 + int(c2) * 10 + int(c3)
- if codepoint > 255:
- raise dns.exception.SyntaxError
- unescaped += b"%c" % (codepoint)
- else:
- # Note that as mentioned above, if c is a Unicode
- # code point outside of the ASCII range, then this
- # += is converting that code point to its UTF-8
- # encoding and appending multiple bytes to
- # unescaped.
- unescaped += c.encode()
- else:
- unescaped += c.encode()
- return Token(self.ttype, bytes(unescaped))
-
-
-class Tokenizer:
- """A DNS zone file format tokenizer.
-
- A token object is basically a (type, value) tuple. The valid
- types are EOF, EOL, WHITESPACE, IDENTIFIER, QUOTED_STRING,
- COMMENT, and DELIMITER.
-
- file: The file to tokenize
-
- ungotten_char: The most recently ungotten character, or None.
-
- ungotten_token: The most recently ungotten token, or None.
-
- multiline: The current multiline level. This value is increased
- by one every time a '(' delimiter is read, and decreased by one every time
- a ')' delimiter is read.
-
- quoting: This variable is true if the tokenizer is currently
- reading a quoted string.
-
- eof: This variable is true if the tokenizer has encountered EOF.
-
- delimiters: The current delimiter dictionary.
-
- line_number: The current line number
-
- filename: A filename that will be returned by the where() method.
-
- idna_codec: A dns.name.IDNACodec, specifies the IDNA
- encoder/decoder. If None, the default IDNA 2003
- encoder/decoder is used.
- """
-
- def __init__(
- self,
- f: Any = sys.stdin,
- filename: Optional[str] = None,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- ):
- """Initialize a tokenizer instance.
-
- f: The file to tokenize. The default is sys.stdin.
- This parameter may also be a string, in which case the tokenizer
- will take its input from the contents of the string.
-
- filename: the name of the filename that the where() method
- will return.
-
- idna_codec: A dns.name.IDNACodec, specifies the IDNA
- encoder/decoder. If None, the default IDNA 2003
- encoder/decoder is used.
- """
-
- if isinstance(f, str):
- f = io.StringIO(f)
- if filename is None:
- filename = ""
- elif isinstance(f, bytes):
- f = io.StringIO(f.decode())
- if filename is None:
- filename = ""
- else:
- if filename is None:
- if f is sys.stdin:
- filename = ""
- else:
- filename = ""
- self.file = f
- self.ungotten_char: Optional[str] = None
- self.ungotten_token: Optional[Token] = None
- self.multiline = 0
- self.quoting = False
- self.eof = False
- self.delimiters = _DELIMITERS
- self.line_number = 1
- assert filename is not None
- self.filename = filename
- if idna_codec is None:
- self.idna_codec: dns.name.IDNACodec = dns.name.IDNA_2003
- else:
- self.idna_codec = idna_codec
-
- def _get_char(self) -> str:
- """Read a character from input."""
-
- if self.ungotten_char is None:
- if self.eof:
- c = ""
- else:
- c = self.file.read(1)
- if c == "":
- self.eof = True
- elif c == "\n":
- self.line_number += 1
- else:
- c = self.ungotten_char
- self.ungotten_char = None
- return c
-
- def where(self) -> Tuple[str, int]:
- """Return the current location in the input.
-
- Returns a (string, int) tuple. The first item is the filename of
- the input, the second is the current line number.
- """
-
- return (self.filename, self.line_number)
-
- def _unget_char(self, c: str) -> None:
- """Unget a character.
-
- The unget buffer for characters is only one character large; it is
- an error to try to unget a character when the unget buffer is not
- empty.
-
- c: the character to unget
- raises UngetBufferFull: there is already an ungotten char
- """
-
- if self.ungotten_char is not None:
- # this should never happen!
- raise UngetBufferFull # pragma: no cover
- self.ungotten_char = c
-
- def skip_whitespace(self) -> int:
- """Consume input until a non-whitespace character is encountered.
-
- The non-whitespace character is then ungotten, and the number of
- whitespace characters consumed is returned.
-
- If the tokenizer is in multiline mode, then newlines are whitespace.
-
- Returns the number of characters skipped.
- """
-
- skipped = 0
- while True:
- c = self._get_char()
- if c != " " and c != "\t":
- if (c != "\n") or not self.multiline:
- self._unget_char(c)
- return skipped
- skipped += 1
-
- def get(self, want_leading: bool = False, want_comment: bool = False) -> Token:
- """Get the next token.
-
- want_leading: If True, return a WHITESPACE token if the
- first character read is whitespace. The default is False.
-
- want_comment: If True, return a COMMENT token if the
- first token read is a comment. The default is False.
-
- Raises dns.exception.UnexpectedEnd: input ended prematurely
-
- Raises dns.exception.SyntaxError: input was badly formed
-
- Returns a Token.
- """
-
- if self.ungotten_token is not None:
- utoken = self.ungotten_token
- self.ungotten_token = None
- if utoken.is_whitespace():
- if want_leading:
- return utoken
- elif utoken.is_comment():
- if want_comment:
- return utoken
- else:
- return utoken
- skipped = self.skip_whitespace()
- if want_leading and skipped > 0:
- return Token(WHITESPACE, " ")
- token = ""
- ttype = IDENTIFIER
- has_escape = False
- while True:
- c = self._get_char()
- if c == "" or c in self.delimiters:
- if c == "" and self.quoting:
- raise dns.exception.UnexpectedEnd
- if token == "" and ttype != QUOTED_STRING:
- if c == "(":
- self.multiline += 1
- self.skip_whitespace()
- continue
- elif c == ")":
- if self.multiline <= 0:
- raise dns.exception.SyntaxError
- self.multiline -= 1
- self.skip_whitespace()
- continue
- elif c == '"':
- if not self.quoting:
- self.quoting = True
- self.delimiters = _QUOTING_DELIMITERS
- ttype = QUOTED_STRING
- continue
- else:
- self.quoting = False
- self.delimiters = _DELIMITERS
- self.skip_whitespace()
- continue
- elif c == "\n":
- return Token(EOL, "\n")
- elif c == ";":
- while 1:
- c = self._get_char()
- if c == "\n" or c == "":
- break
- token += c
- if want_comment:
- self._unget_char(c)
- return Token(COMMENT, token)
- elif c == "":
- if self.multiline:
- raise dns.exception.SyntaxError(
- "unbalanced parentheses"
- )
- return Token(EOF, comment=token)
- elif self.multiline:
- self.skip_whitespace()
- token = ""
- continue
- else:
- return Token(EOL, "\n", comment=token)
- else:
- # This code exists in case we ever want a
- # delimiter to be returned. It never produces
- # a token currently.
- token = c
- ttype = DELIMITER
- else:
- self._unget_char(c)
- break
- elif self.quoting and c == "\n":
- raise dns.exception.SyntaxError("newline in quoted string")
- elif c == "\\":
- #
- # It's an escape. Put it and the next character into
- # the token; it will be checked later for goodness.
- #
- token += c
- has_escape = True
- c = self._get_char()
- if c == "" or (c == "\n" and not self.quoting):
- raise dns.exception.UnexpectedEnd
- token += c
- if token == "" and ttype != QUOTED_STRING:
- if self.multiline:
- raise dns.exception.SyntaxError("unbalanced parentheses")
- ttype = EOF
- return Token(ttype, token, has_escape)
-
- def unget(self, token: Token) -> None:
- """Unget a token.
-
- The unget buffer for tokens is only one token large; it is
- an error to try to unget a token when the unget buffer is not
- empty.
-
- token: the token to unget
-
- Raises UngetBufferFull: there is already an ungotten token
- """
-
- if self.ungotten_token is not None:
- raise UngetBufferFull
- self.ungotten_token = token
-
- def next(self):
- """Return the next item in an iteration.
-
- Returns a Token.
- """
-
- token = self.get()
- if token.is_eof():
- raise StopIteration
- return token
-
- __next__ = next
-
- def __iter__(self):
- return self
-
- # Helpers
-
- def get_int(self, base: int = 10) -> int:
- """Read the next token and interpret it as an unsigned integer.
-
- Raises dns.exception.SyntaxError if not an unsigned integer.
-
- Returns an int.
- """
-
- token = self.get().unescape()
- if not token.is_identifier():
- raise dns.exception.SyntaxError("expecting an identifier")
- if not token.value.isdigit():
- raise dns.exception.SyntaxError("expecting an integer")
- return int(token.value, base)
-
- def get_uint8(self) -> int:
- """Read the next token and interpret it as an 8-bit unsigned
- integer.
-
- Raises dns.exception.SyntaxError if not an 8-bit unsigned integer.
-
- Returns an int.
- """
-
- value = self.get_int()
- if value < 0 or value > 255:
- raise dns.exception.SyntaxError(
- "%d is not an unsigned 8-bit integer" % value
- )
- return value
-
- def get_uint16(self, base: int = 10) -> int:
- """Read the next token and interpret it as a 16-bit unsigned
- integer.
-
- Raises dns.exception.SyntaxError if not a 16-bit unsigned integer.
-
- Returns an int.
- """
-
- value = self.get_int(base=base)
- if value < 0 or value > 65535:
- if base == 8:
- raise dns.exception.SyntaxError(
- "%o is not an octal unsigned 16-bit integer" % value
- )
- else:
- raise dns.exception.SyntaxError(
- "%d is not an unsigned 16-bit integer" % value
- )
- return value
-
- def get_uint32(self, base: int = 10) -> int:
- """Read the next token and interpret it as a 32-bit unsigned
- integer.
-
- Raises dns.exception.SyntaxError if not a 32-bit unsigned integer.
-
- Returns an int.
- """
-
- value = self.get_int(base=base)
- if value < 0 or value > 4294967295:
- raise dns.exception.SyntaxError(
- "%d is not an unsigned 32-bit integer" % value
- )
- return value
-
- def get_uint48(self, base: int = 10) -> int:
- """Read the next token and interpret it as a 48-bit unsigned
- integer.
-
- Raises dns.exception.SyntaxError if not a 48-bit unsigned integer.
-
- Returns an int.
- """
-
- value = self.get_int(base=base)
- if value < 0 or value > 281474976710655:
- raise dns.exception.SyntaxError(
- "%d is not an unsigned 48-bit integer" % value
- )
- return value
-
- def get_string(self, max_length: Optional[int] = None) -> str:
- """Read the next token and interpret it as a string.
-
- Raises dns.exception.SyntaxError if not a string.
- Raises dns.exception.SyntaxError if token value length
- exceeds max_length (if specified).
-
- Returns a string.
- """
-
- token = self.get().unescape()
- if not (token.is_identifier() or token.is_quoted_string()):
- raise dns.exception.SyntaxError("expecting a string")
- if max_length and len(token.value) > max_length:
- raise dns.exception.SyntaxError("string too long")
- return token.value
-
- def get_identifier(self) -> str:
- """Read the next token, which should be an identifier.
-
- Raises dns.exception.SyntaxError if not an identifier.
-
- Returns a string.
- """
-
- token = self.get().unescape()
- if not token.is_identifier():
- raise dns.exception.SyntaxError("expecting an identifier")
- return token.value
-
- def get_remaining(self, max_tokens: Optional[int] = None) -> List[Token]:
- """Return the remaining tokens on the line, until an EOL or EOF is seen.
-
- max_tokens: If not None, stop after this number of tokens.
-
- Returns a list of tokens.
- """
-
- tokens = []
- while True:
- token = self.get()
- if token.is_eol_or_eof():
- self.unget(token)
- break
- tokens.append(token)
- if len(tokens) == max_tokens:
- break
- return tokens
-
- def concatenate_remaining_identifiers(self, allow_empty: bool = False) -> str:
- """Read the remaining tokens on the line, which should be identifiers.
-
- Raises dns.exception.SyntaxError if there are no remaining tokens,
- unless `allow_empty=True` is given.
-
- Raises dns.exception.SyntaxError if a token is seen that is not an
- identifier.
-
- Returns a string containing a concatenation of the remaining
- identifiers.
- """
- s = ""
- while True:
- token = self.get().unescape()
- if token.is_eol_or_eof():
- self.unget(token)
- break
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- s += token.value
- if not (allow_empty or s):
- raise dns.exception.SyntaxError("expecting another identifier")
- return s
-
- def as_name(
- self,
- token: Token,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = False,
- relativize_to: Optional[dns.name.Name] = None,
- ) -> dns.name.Name:
- """Try to interpret the token as a DNS name.
-
- Raises dns.exception.SyntaxError if not a name.
-
- Returns a dns.name.Name.
- """
- if not token.is_identifier():
- raise dns.exception.SyntaxError("expecting an identifier")
- name = dns.name.from_text(token.value, origin, self.idna_codec)
- return name.choose_relativity(relativize_to or origin, relativize)
-
- def get_name(
- self,
- origin: Optional[dns.name.Name] = None,
- relativize: bool = False,
- relativize_to: Optional[dns.name.Name] = None,
- ) -> dns.name.Name:
- """Read the next token and interpret it as a DNS name.
-
- Raises dns.exception.SyntaxError if not a name.
-
- Returns a dns.name.Name.
- """
-
- token = self.get()
- return self.as_name(token, origin, relativize, relativize_to)
-
- def get_eol_as_token(self) -> Token:
- """Read the next token and raise an exception if it isn't EOL or
- EOF.
-
- Returns a string.
- """
-
- token = self.get()
- if not token.is_eol_or_eof():
- raise dns.exception.SyntaxError(
- 'expected EOL or EOF, got %d "%s"' % (token.ttype, token.value)
- )
- return token
-
- def get_eol(self) -> str:
- return self.get_eol_as_token().value
-
- def get_ttl(self) -> int:
- """Read the next token and interpret it as a DNS TTL.
-
- Raises dns.exception.SyntaxError or dns.ttl.BadTTL if not an
- identifier or badly formed.
-
- Returns an int.
- """
-
- token = self.get().unescape()
- if not token.is_identifier():
- raise dns.exception.SyntaxError("expecting an identifier")
- return dns.ttl.from_text(token.value)
diff --git a/.venv/lib/python3.12/site-packages/dns/transaction.py b/.venv/lib/python3.12/site-packages/dns/transaction.py
deleted file mode 100644
index 84e54f7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/transaction.py
+++ /dev/null
@@ -1,651 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import collections
-from typing import Any, Callable, Iterator, List, Optional, Tuple, Union
-
-import dns.exception
-import dns.name
-import dns.node
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.rrset
-import dns.serial
-import dns.ttl
-
-
-class TransactionManager:
- def reader(self) -> "Transaction":
- """Begin a read-only transaction."""
- raise NotImplementedError # pragma: no cover
-
- def writer(self, replacement: bool = False) -> "Transaction":
- """Begin a writable transaction.
-
- *replacement*, a ``bool``. If `True`, the content of the
- transaction completely replaces any prior content. If False,
- the default, then the content of the transaction updates the
- existing content.
- """
- raise NotImplementedError # pragma: no cover
-
- def origin_information(
- self,
- ) -> Tuple[Optional[dns.name.Name], bool, Optional[dns.name.Name]]:
- """Returns a tuple
-
- (absolute_origin, relativize, effective_origin)
-
- giving the absolute name of the default origin for any
- relative domain names, the "effective origin", and whether
- names should be relativized. The "effective origin" is the
- absolute origin if relativize is False, and the empty name if
- relativize is true. (The effective origin is provided even
- though it can be computed from the absolute_origin and
- relativize setting because it avoids a lot of code
- duplication.)
-
- If the returned names are `None`, then no origin information is
- available.
-
- This information is used by code working with transactions to
- allow it to coordinate relativization. The transaction code
- itself takes what it gets (i.e. does not change name
- relativity).
-
- """
- raise NotImplementedError # pragma: no cover
-
- def get_class(self) -> dns.rdataclass.RdataClass:
- """The class of the transaction manager."""
- raise NotImplementedError # pragma: no cover
-
- def from_wire_origin(self) -> Optional[dns.name.Name]:
- """Origin to use in from_wire() calls."""
- (absolute_origin, relativize, _) = self.origin_information()
- if relativize:
- return absolute_origin
- else:
- return None
-
-
-class DeleteNotExact(dns.exception.DNSException):
- """Existing data did not match data specified by an exact delete."""
-
-
-class ReadOnly(dns.exception.DNSException):
- """Tried to write to a read-only transaction."""
-
-
-class AlreadyEnded(dns.exception.DNSException):
- """Tried to use an already-ended transaction."""
-
-
-def _ensure_immutable_rdataset(rdataset):
- if rdataset is None or isinstance(rdataset, dns.rdataset.ImmutableRdataset):
- return rdataset
- return dns.rdataset.ImmutableRdataset(rdataset)
-
-
-def _ensure_immutable_node(node):
- if node is None or node.is_immutable():
- return node
- return dns.node.ImmutableNode(node)
-
-
-CheckPutRdatasetType = Callable[
- ["Transaction", dns.name.Name, dns.rdataset.Rdataset], None
-]
-CheckDeleteRdatasetType = Callable[
- ["Transaction", dns.name.Name, dns.rdatatype.RdataType, dns.rdatatype.RdataType],
- None,
-]
-CheckDeleteNameType = Callable[["Transaction", dns.name.Name], None]
-
-
-class Transaction:
- def __init__(
- self,
- manager: TransactionManager,
- replacement: bool = False,
- read_only: bool = False,
- ):
- self.manager = manager
- self.replacement = replacement
- self.read_only = read_only
- self._ended = False
- self._check_put_rdataset: List[CheckPutRdatasetType] = []
- self._check_delete_rdataset: List[CheckDeleteRdatasetType] = []
- self._check_delete_name: List[CheckDeleteNameType] = []
-
- #
- # This is the high level API
- #
- # Note that we currently use non-immutable types in the return type signature to
- # avoid covariance problems, e.g. if the caller has a List[Rdataset], mypy will be
- # unhappy if we return an ImmutableRdataset.
-
- def get(
- self,
- name: Optional[Union[dns.name.Name, str]],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> dns.rdataset.Rdataset:
- """Return the rdataset associated with *name*, *rdtype*, and *covers*,
- or `None` if not found.
-
- Note that the returned rdataset is immutable.
- """
- self._check_ended()
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- rdataset = self._get_rdataset(name, rdtype, covers)
- return _ensure_immutable_rdataset(rdataset)
-
- def get_node(self, name: dns.name.Name) -> Optional[dns.node.Node]:
- """Return the node at *name*, if any.
-
- Returns an immutable node or ``None``.
- """
- return _ensure_immutable_node(self._get_node(name))
-
- def _check_read_only(self) -> None:
- if self.read_only:
- raise ReadOnly
-
- def add(self, *args: Any) -> None:
- """Add records.
-
- The arguments may be:
-
- - rrset
-
- - name, rdataset...
-
- - name, ttl, rdata...
- """
- self._check_ended()
- self._check_read_only()
- self._add(False, args)
-
- def replace(self, *args: Any) -> None:
- """Replace the existing rdataset at the name with the specified
- rdataset, or add the specified rdataset if there was no existing
- rdataset.
-
- The arguments may be:
-
- - rrset
-
- - name, rdataset...
-
- - name, ttl, rdata...
-
- Note that if you want to replace the entire node, you should do
- a delete of the name followed by one or more calls to add() or
- replace().
- """
- self._check_ended()
- self._check_read_only()
- self._add(True, args)
-
- def delete(self, *args: Any) -> None:
- """Delete records.
-
- It is not an error if some of the records are not in the existing
- set.
-
- The arguments may be:
-
- - rrset
-
- - name
-
- - name, rdatatype, [covers]
-
- - name, rdataset...
-
- - name, rdata...
- """
- self._check_ended()
- self._check_read_only()
- self._delete(False, args)
-
- def delete_exact(self, *args: Any) -> None:
- """Delete records.
-
- The arguments may be:
-
- - rrset
-
- - name
-
- - name, rdatatype, [covers]
-
- - name, rdataset...
-
- - name, rdata...
-
- Raises dns.transaction.DeleteNotExact if some of the records
- are not in the existing set.
-
- """
- self._check_ended()
- self._check_read_only()
- self._delete(True, args)
-
- def name_exists(self, name: Union[dns.name.Name, str]) -> bool:
- """Does the specified name exist?"""
- self._check_ended()
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- return self._name_exists(name)
-
- def update_serial(
- self,
- value: int = 1,
- relative: bool = True,
- name: dns.name.Name = dns.name.empty,
- ) -> None:
- """Update the serial number.
-
- *value*, an `int`, is an increment if *relative* is `True`, or the
- actual value to set if *relative* is `False`.
-
- Raises `KeyError` if there is no SOA rdataset at *name*.
-
- Raises `ValueError` if *value* is negative or if the increment is
- so large that it would cause the new serial to be less than the
- prior value.
- """
- self._check_ended()
- if value < 0:
- raise ValueError("negative update_serial() value")
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- rdataset = self._get_rdataset(name, dns.rdatatype.SOA, dns.rdatatype.NONE)
- if rdataset is None or len(rdataset) == 0:
- raise KeyError
- if relative:
- serial = dns.serial.Serial(rdataset[0].serial) + value
- else:
- serial = dns.serial.Serial(value)
- serial = serial.value # convert back to int
- if serial == 0:
- serial = 1
- rdata = rdataset[0].replace(serial=serial)
- new_rdataset = dns.rdataset.from_rdata(rdataset.ttl, rdata)
- self.replace(name, new_rdataset)
-
- def __iter__(self):
- self._check_ended()
- return self._iterate_rdatasets()
-
- def changed(self) -> bool:
- """Has this transaction changed anything?
-
- For read-only transactions, the result is always `False`.
-
- For writable transactions, the result is `True` if at some time
- during the life of the transaction, the content was changed.
- """
- self._check_ended()
- return self._changed()
-
- def commit(self) -> None:
- """Commit the transaction.
-
- Normally transactions are used as context managers and commit
- or rollback automatically, but it may be done explicitly if needed.
- A ``dns.transaction.Ended`` exception will be raised if you try
- to use a transaction after it has been committed or rolled back.
-
- Raises an exception if the commit fails (in which case the transaction
- is also rolled back.
- """
- self._end(True)
-
- def rollback(self) -> None:
- """Rollback the transaction.
-
- Normally transactions are used as context managers and commit
- or rollback automatically, but it may be done explicitly if needed.
- A ``dns.transaction.AlreadyEnded`` exception will be raised if you try
- to use a transaction after it has been committed or rolled back.
-
- Rollback cannot otherwise fail.
- """
- self._end(False)
-
- def check_put_rdataset(self, check: CheckPutRdatasetType) -> None:
- """Call *check* before putting (storing) an rdataset.
-
- The function is called with the transaction, the name, and the rdataset.
-
- The check function may safely make non-mutating transaction method
- calls, but behavior is undefined if mutating transaction methods are
- called. The check function should raise an exception if it objects to
- the put, and otherwise should return ``None``.
- """
- self._check_put_rdataset.append(check)
-
- def check_delete_rdataset(self, check: CheckDeleteRdatasetType) -> None:
- """Call *check* before deleting an rdataset.
-
- The function is called with the transaction, the name, the rdatatype,
- and the covered rdatatype.
-
- The check function may safely make non-mutating transaction method
- calls, but behavior is undefined if mutating transaction methods are
- called. The check function should raise an exception if it objects to
- the put, and otherwise should return ``None``.
- """
- self._check_delete_rdataset.append(check)
-
- def check_delete_name(self, check: CheckDeleteNameType) -> None:
- """Call *check* before putting (storing) an rdataset.
-
- The function is called with the transaction and the name.
-
- The check function may safely make non-mutating transaction method
- calls, but behavior is undefined if mutating transaction methods are
- called. The check function should raise an exception if it objects to
- the put, and otherwise should return ``None``.
- """
- self._check_delete_name.append(check)
-
- def iterate_rdatasets(
- self,
- ) -> Iterator[Tuple[dns.name.Name, dns.rdataset.Rdataset]]:
- """Iterate all the rdatasets in the transaction, returning
- (`dns.name.Name`, `dns.rdataset.Rdataset`) tuples.
-
- Note that as is usual with python iterators, adding or removing items
- while iterating will invalidate the iterator and may raise `RuntimeError`
- or fail to iterate over all entries."""
- self._check_ended()
- return self._iterate_rdatasets()
-
- def iterate_names(self) -> Iterator[dns.name.Name]:
- """Iterate all the names in the transaction.
-
- Note that as is usual with python iterators, adding or removing names
- while iterating will invalidate the iterator and may raise `RuntimeError`
- or fail to iterate over all entries."""
- self._check_ended()
- return self._iterate_names()
-
- #
- # Helper methods
- #
-
- def _raise_if_not_empty(self, method, args):
- if len(args) != 0:
- raise TypeError(f"extra parameters to {method}")
-
- def _rdataset_from_args(self, method, deleting, args):
- try:
- arg = args.popleft()
- if isinstance(arg, dns.rrset.RRset):
- rdataset = arg.to_rdataset()
- elif isinstance(arg, dns.rdataset.Rdataset):
- rdataset = arg
- else:
- if deleting:
- ttl = 0
- else:
- if isinstance(arg, int):
- ttl = arg
- if ttl > dns.ttl.MAX_TTL:
- raise ValueError(f"{method}: TTL value too big")
- else:
- raise TypeError(f"{method}: expected a TTL")
- arg = args.popleft()
- if isinstance(arg, dns.rdata.Rdata):
- rdataset = dns.rdataset.from_rdata(ttl, arg)
- else:
- raise TypeError(f"{method}: expected an Rdata")
- return rdataset
- except IndexError:
- if deleting:
- return None
- else:
- # reraise
- raise TypeError(f"{method}: expected more arguments")
-
- def _add(self, replace, args):
- try:
- args = collections.deque(args)
- if replace:
- method = "replace()"
- else:
- method = "add()"
- arg = args.popleft()
- if isinstance(arg, str):
- arg = dns.name.from_text(arg, None)
- if isinstance(arg, dns.name.Name):
- name = arg
- rdataset = self._rdataset_from_args(method, False, args)
- elif isinstance(arg, dns.rrset.RRset):
- rrset = arg
- name = rrset.name
- # rrsets are also rdatasets, but they don't print the
- # same and can't be stored in nodes, so convert.
- rdataset = rrset.to_rdataset()
- else:
- raise TypeError(
- f"{method} requires a name or RRset as the first argument"
- )
- if rdataset.rdclass != self.manager.get_class():
- raise ValueError(f"{method} has objects of wrong RdataClass")
- if rdataset.rdtype == dns.rdatatype.SOA:
- (_, _, origin) = self._origin_information()
- if name != origin:
- raise ValueError(f"{method} has non-origin SOA")
- self._raise_if_not_empty(method, args)
- if not replace:
- existing = self._get_rdataset(name, rdataset.rdtype, rdataset.covers)
- if existing is not None:
- if isinstance(existing, dns.rdataset.ImmutableRdataset):
- trds = dns.rdataset.Rdataset(
- existing.rdclass, existing.rdtype, existing.covers
- )
- trds.update(existing)
- existing = trds
- rdataset = existing.union(rdataset)
- self._checked_put_rdataset(name, rdataset)
- except IndexError:
- raise TypeError(f"not enough parameters to {method}")
-
- def _delete(self, exact, args):
- try:
- args = collections.deque(args)
- if exact:
- method = "delete_exact()"
- else:
- method = "delete()"
- arg = args.popleft()
- if isinstance(arg, str):
- arg = dns.name.from_text(arg, None)
- if isinstance(arg, dns.name.Name):
- name = arg
- if len(args) > 0 and (
- isinstance(args[0], int) or isinstance(args[0], str)
- ):
- # deleting by type and (optionally) covers
- rdtype = dns.rdatatype.RdataType.make(args.popleft())
- if len(args) > 0:
- covers = dns.rdatatype.RdataType.make(args.popleft())
- else:
- covers = dns.rdatatype.NONE
- self._raise_if_not_empty(method, args)
- existing = self._get_rdataset(name, rdtype, covers)
- if existing is None:
- if exact:
- raise DeleteNotExact(f"{method}: missing rdataset")
- else:
- self._delete_rdataset(name, rdtype, covers)
- return
- else:
- rdataset = self._rdataset_from_args(method, True, args)
- elif isinstance(arg, dns.rrset.RRset):
- rdataset = arg # rrsets are also rdatasets
- name = rdataset.name
- else:
- raise TypeError(
- f"{method} requires a name or RRset as the first argument"
- )
- self._raise_if_not_empty(method, args)
- if rdataset:
- if rdataset.rdclass != self.manager.get_class():
- raise ValueError(f"{method} has objects of wrong RdataClass")
- existing = self._get_rdataset(name, rdataset.rdtype, rdataset.covers)
- if existing is not None:
- if exact:
- intersection = existing.intersection(rdataset)
- if intersection != rdataset:
- raise DeleteNotExact(f"{method}: missing rdatas")
- rdataset = existing.difference(rdataset)
- if len(rdataset) == 0:
- self._checked_delete_rdataset(
- name, rdataset.rdtype, rdataset.covers
- )
- else:
- self._checked_put_rdataset(name, rdataset)
- elif exact:
- raise DeleteNotExact(f"{method}: missing rdataset")
- else:
- if exact and not self._name_exists(name):
- raise DeleteNotExact(f"{method}: name not known")
- self._checked_delete_name(name)
- except IndexError:
- raise TypeError(f"not enough parameters to {method}")
-
- def _check_ended(self):
- if self._ended:
- raise AlreadyEnded
-
- def _end(self, commit):
- self._check_ended()
- if self._ended:
- raise AlreadyEnded
- try:
- self._end_transaction(commit)
- finally:
- self._ended = True
-
- def _checked_put_rdataset(self, name, rdataset):
- for check in self._check_put_rdataset:
- check(self, name, rdataset)
- self._put_rdataset(name, rdataset)
-
- def _checked_delete_rdataset(self, name, rdtype, covers):
- for check in self._check_delete_rdataset:
- check(self, name, rdtype, covers)
- self._delete_rdataset(name, rdtype, covers)
-
- def _checked_delete_name(self, name):
- for check in self._check_delete_name:
- check(self, name)
- self._delete_name(name)
-
- #
- # Transactions are context managers.
- #
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- if not self._ended:
- if exc_type is None:
- self.commit()
- else:
- self.rollback()
- return False
-
- #
- # This is the low level API, which must be implemented by subclasses
- # of Transaction.
- #
-
- def _get_rdataset(self, name, rdtype, covers):
- """Return the rdataset associated with *name*, *rdtype*, and *covers*,
- or `None` if not found.
- """
- raise NotImplementedError # pragma: no cover
-
- def _put_rdataset(self, name, rdataset):
- """Store the rdataset."""
- raise NotImplementedError # pragma: no cover
-
- def _delete_name(self, name):
- """Delete all data associated with *name*.
-
- It is not an error if the name does not exist.
- """
- raise NotImplementedError # pragma: no cover
-
- def _delete_rdataset(self, name, rdtype, covers):
- """Delete all data associated with *name*, *rdtype*, and *covers*.
-
- It is not an error if the rdataset does not exist.
- """
- raise NotImplementedError # pragma: no cover
-
- def _name_exists(self, name):
- """Does name exist?
-
- Returns a bool.
- """
- raise NotImplementedError # pragma: no cover
-
- def _changed(self):
- """Has this transaction changed anything?"""
- raise NotImplementedError # pragma: no cover
-
- def _end_transaction(self, commit):
- """End the transaction.
-
- *commit*, a bool. If ``True``, commit the transaction, otherwise
- roll it back.
-
- If committing and the commit fails, then roll back and raise an
- exception.
- """
- raise NotImplementedError # pragma: no cover
-
- def _set_origin(self, origin):
- """Set the origin.
-
- This method is called when reading a possibly relativized
- source, and an origin setting operation occurs (e.g. $ORIGIN
- in a zone file).
- """
- raise NotImplementedError # pragma: no cover
-
- def _iterate_rdatasets(self):
- """Return an iterator that yields (name, rdataset) tuples."""
- raise NotImplementedError # pragma: no cover
-
- def _iterate_names(self):
- """Return an iterator that yields a name."""
- raise NotImplementedError # pragma: no cover
-
- def _get_node(self, name):
- """Return the node at *name*, if any.
-
- Returns a node or ``None``.
- """
- raise NotImplementedError # pragma: no cover
-
- #
- # Low-level API with a default implementation, in case a subclass needs
- # to override.
- #
-
- def _origin_information(self):
- # This is only used by _add()
- return self.manager.origin_information()
diff --git a/.venv/lib/python3.12/site-packages/dns/tsig.py b/.venv/lib/python3.12/site-packages/dns/tsig.py
deleted file mode 100644
index 780852e..0000000
--- a/.venv/lib/python3.12/site-packages/dns/tsig.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2001-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS TSIG support."""
-
-import base64
-import hashlib
-import hmac
-import struct
-
-import dns.exception
-import dns.name
-import dns.rcode
-import dns.rdataclass
-
-
-class BadTime(dns.exception.DNSException):
- """The current time is not within the TSIG's validity time."""
-
-
-class BadSignature(dns.exception.DNSException):
- """The TSIG signature fails to verify."""
-
-
-class BadKey(dns.exception.DNSException):
- """The TSIG record owner name does not match the key."""
-
-
-class BadAlgorithm(dns.exception.DNSException):
- """The TSIG algorithm does not match the key."""
-
-
-class PeerError(dns.exception.DNSException):
- """Base class for all TSIG errors generated by the remote peer"""
-
-
-class PeerBadKey(PeerError):
- """The peer didn't know the key we used"""
-
-
-class PeerBadSignature(PeerError):
- """The peer didn't like the signature we sent"""
-
-
-class PeerBadTime(PeerError):
- """The peer didn't like the time we sent"""
-
-
-class PeerBadTruncation(PeerError):
- """The peer didn't like amount of truncation in the TSIG we sent"""
-
-
-# TSIG Algorithms
-
-HMAC_MD5 = dns.name.from_text("HMAC-MD5.SIG-ALG.REG.INT")
-HMAC_SHA1 = dns.name.from_text("hmac-sha1")
-HMAC_SHA224 = dns.name.from_text("hmac-sha224")
-HMAC_SHA256 = dns.name.from_text("hmac-sha256")
-HMAC_SHA256_128 = dns.name.from_text("hmac-sha256-128")
-HMAC_SHA384 = dns.name.from_text("hmac-sha384")
-HMAC_SHA384_192 = dns.name.from_text("hmac-sha384-192")
-HMAC_SHA512 = dns.name.from_text("hmac-sha512")
-HMAC_SHA512_256 = dns.name.from_text("hmac-sha512-256")
-GSS_TSIG = dns.name.from_text("gss-tsig")
-
-default_algorithm = HMAC_SHA256
-
-mac_sizes = {
- HMAC_SHA1: 20,
- HMAC_SHA224: 28,
- HMAC_SHA256: 32,
- HMAC_SHA256_128: 16,
- HMAC_SHA384: 48,
- HMAC_SHA384_192: 24,
- HMAC_SHA512: 64,
- HMAC_SHA512_256: 32,
- HMAC_MD5: 16,
- GSS_TSIG: 128, # This is what we assume to be the worst case!
-}
-
-
-class GSSTSig:
- """
- GSS-TSIG TSIG implementation. This uses the GSS-API context established
- in the TKEY message handshake to sign messages using GSS-API message
- integrity codes, per the RFC.
-
- In order to avoid a direct GSSAPI dependency, the keyring holds a ref
- to the GSSAPI object required, rather than the key itself.
- """
-
- def __init__(self, gssapi_context):
- self.gssapi_context = gssapi_context
- self.data = b""
- self.name = "gss-tsig"
-
- def update(self, data):
- self.data += data
-
- def sign(self):
- # defer to the GSSAPI function to sign
- return self.gssapi_context.get_signature(self.data)
-
- def verify(self, expected):
- try:
- # defer to the GSSAPI function to verify
- return self.gssapi_context.verify_signature(self.data, expected)
- except Exception:
- # note the usage of a bare exception
- raise BadSignature
-
-
-class GSSTSigAdapter:
- def __init__(self, keyring):
- self.keyring = keyring
-
- def __call__(self, message, keyname):
- if keyname in self.keyring:
- key = self.keyring[keyname]
- if isinstance(key, Key) and key.algorithm == GSS_TSIG:
- if message:
- GSSTSigAdapter.parse_tkey_and_step(key, message, keyname)
- return key
- else:
- return None
-
- @classmethod
- def parse_tkey_and_step(cls, key, message, keyname):
- # if the message is a TKEY type, absorb the key material
- # into the context using step(); this is used to allow the
- # client to complete the GSSAPI negotiation before attempting
- # to verify the signed response to a TKEY message exchange
- try:
- rrset = message.find_rrset(
- message.answer, keyname, dns.rdataclass.ANY, dns.rdatatype.TKEY
- )
- if rrset:
- token = rrset[0].key
- gssapi_context = key.secret
- return gssapi_context.step(token)
- except KeyError:
- pass
-
-
-class HMACTSig:
- """
- HMAC TSIG implementation. This uses the HMAC python module to handle the
- sign/verify operations.
- """
-
- _hashes = {
- HMAC_SHA1: hashlib.sha1,
- HMAC_SHA224: hashlib.sha224,
- HMAC_SHA256: hashlib.sha256,
- HMAC_SHA256_128: (hashlib.sha256, 128),
- HMAC_SHA384: hashlib.sha384,
- HMAC_SHA384_192: (hashlib.sha384, 192),
- HMAC_SHA512: hashlib.sha512,
- HMAC_SHA512_256: (hashlib.sha512, 256),
- HMAC_MD5: hashlib.md5,
- }
-
- def __init__(self, key, algorithm):
- try:
- hashinfo = self._hashes[algorithm]
- except KeyError:
- raise NotImplementedError(f"TSIG algorithm {algorithm} is not supported")
-
- # create the HMAC context
- if isinstance(hashinfo, tuple):
- self.hmac_context = hmac.new(key, digestmod=hashinfo[0])
- self.size = hashinfo[1]
- else:
- self.hmac_context = hmac.new(key, digestmod=hashinfo)
- self.size = None
- self.name = self.hmac_context.name
- if self.size:
- self.name += f"-{self.size}"
-
- def update(self, data):
- return self.hmac_context.update(data)
-
- def sign(self):
- # defer to the HMAC digest() function for that digestmod
- digest = self.hmac_context.digest()
- if self.size:
- digest = digest[: (self.size // 8)]
- return digest
-
- def verify(self, expected):
- # re-digest and compare the results
- mac = self.sign()
- if not hmac.compare_digest(mac, expected):
- raise BadSignature
-
-
-def _digest(wire, key, rdata, time=None, request_mac=None, ctx=None, multi=None):
- """Return a context containing the TSIG rdata for the input parameters
- @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object
- @raises ValueError: I{other_data} is too long
- @raises NotImplementedError: I{algorithm} is not supported
- """
-
- first = not (ctx and multi)
- if first:
- ctx = get_context(key)
- if request_mac:
- ctx.update(struct.pack("!H", len(request_mac)))
- ctx.update(request_mac)
- ctx.update(struct.pack("!H", rdata.original_id))
- ctx.update(wire[2:])
- if first:
- ctx.update(key.name.to_digestable())
- ctx.update(struct.pack("!H", dns.rdataclass.ANY))
- ctx.update(struct.pack("!I", 0))
- if time is None:
- time = rdata.time_signed
- upper_time = (time >> 32) & 0xFFFF
- lower_time = time & 0xFFFFFFFF
- time_encoded = struct.pack("!HIH", upper_time, lower_time, rdata.fudge)
- other_len = len(rdata.other)
- if other_len > 65535:
- raise ValueError("TSIG Other Data is > 65535 bytes")
- if first:
- ctx.update(key.algorithm.to_digestable() + time_encoded)
- ctx.update(struct.pack("!HH", rdata.error, other_len) + rdata.other)
- else:
- ctx.update(time_encoded)
- return ctx
-
-
-def _maybe_start_digest(key, mac, multi):
- """If this is the first message in a multi-message sequence,
- start a new context.
- @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object
- """
- if multi:
- ctx = get_context(key)
- ctx.update(struct.pack("!H", len(mac)))
- ctx.update(mac)
- return ctx
- else:
- return None
-
-
-def sign(wire, key, rdata, time=None, request_mac=None, ctx=None, multi=False):
- """Return a (tsig_rdata, mac, ctx) tuple containing the HMAC TSIG rdata
- for the input parameters, the HMAC MAC calculated by applying the
- TSIG signature algorithm, and the TSIG digest context.
- @rtype: (string, dns.tsig.HMACTSig or dns.tsig.GSSTSig object)
- @raises ValueError: I{other_data} is too long
- @raises NotImplementedError: I{algorithm} is not supported
- """
-
- ctx = _digest(wire, key, rdata, time, request_mac, ctx, multi)
- mac = ctx.sign()
- tsig = rdata.replace(time_signed=time, mac=mac)
-
- return (tsig, _maybe_start_digest(key, mac, multi))
-
-
-def validate(
- wire, key, owner, rdata, now, request_mac, tsig_start, ctx=None, multi=False
-):
- """Validate the specified TSIG rdata against the other input parameters.
-
- @raises FormError: The TSIG is badly formed.
- @raises BadTime: There is too much time skew between the client and the
- server.
- @raises BadSignature: The TSIG signature did not validate
- @rtype: dns.tsig.HMACTSig or dns.tsig.GSSTSig object"""
-
- (adcount,) = struct.unpack("!H", wire[10:12])
- if adcount == 0:
- raise dns.exception.FormError
- adcount -= 1
- new_wire = wire[0:10] + struct.pack("!H", adcount) + wire[12:tsig_start]
- if rdata.error != 0:
- if rdata.error == dns.rcode.BADSIG:
- raise PeerBadSignature
- elif rdata.error == dns.rcode.BADKEY:
- raise PeerBadKey
- elif rdata.error == dns.rcode.BADTIME:
- raise PeerBadTime
- elif rdata.error == dns.rcode.BADTRUNC:
- raise PeerBadTruncation
- else:
- raise PeerError("unknown TSIG error code %d" % rdata.error)
- if abs(rdata.time_signed - now) > rdata.fudge:
- raise BadTime
- if key.name != owner:
- raise BadKey
- if key.algorithm != rdata.algorithm:
- raise BadAlgorithm
- ctx = _digest(new_wire, key, rdata, None, request_mac, ctx, multi)
- ctx.verify(rdata.mac)
- return _maybe_start_digest(key, rdata.mac, multi)
-
-
-def get_context(key):
- """Returns an HMAC context for the specified key.
-
- @rtype: HMAC context
- @raises NotImplementedError: I{algorithm} is not supported
- """
-
- if key.algorithm == GSS_TSIG:
- return GSSTSig(key.secret)
- else:
- return HMACTSig(key.secret, key.algorithm)
-
-
-class Key:
- def __init__(self, name, secret, algorithm=default_algorithm):
- if isinstance(name, str):
- name = dns.name.from_text(name)
- self.name = name
- if isinstance(secret, str):
- secret = base64.decodebytes(secret.encode())
- self.secret = secret
- if isinstance(algorithm, str):
- algorithm = dns.name.from_text(algorithm)
- self.algorithm = algorithm
-
- def __eq__(self, other):
- return (
- isinstance(other, Key)
- and self.name == other.name
- and self.secret == other.secret
- and self.algorithm == other.algorithm
- )
-
- def __repr__(self):
- r = f""
- return r
diff --git a/.venv/lib/python3.12/site-packages/dns/tsigkeyring.py b/.venv/lib/python3.12/site-packages/dns/tsigkeyring.py
deleted file mode 100644
index 1010a79..0000000
--- a/.venv/lib/python3.12/site-packages/dns/tsigkeyring.py
+++ /dev/null
@@ -1,68 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""A place to store TSIG keys."""
-
-import base64
-from typing import Any, Dict
-
-import dns.name
-import dns.tsig
-
-
-def from_text(textring: Dict[str, Any]) -> Dict[dns.name.Name, dns.tsig.Key]:
- """Convert a dictionary containing (textual DNS name, base64 secret)
- pairs into a binary keyring which has (dns.name.Name, bytes) pairs, or
- a dictionary containing (textual DNS name, (algorithm, base64 secret))
- pairs into a binary keyring which has (dns.name.Name, dns.tsig.Key) pairs.
- @rtype: dict"""
-
- keyring = {}
- for name, value in textring.items():
- kname = dns.name.from_text(name)
- if isinstance(value, str):
- keyring[kname] = dns.tsig.Key(kname, value).secret
- else:
- (algorithm, secret) = value
- keyring[kname] = dns.tsig.Key(kname, secret, algorithm)
- return keyring
-
-
-def to_text(keyring: Dict[dns.name.Name, Any]) -> Dict[str, Any]:
- """Convert a dictionary containing (dns.name.Name, dns.tsig.Key) pairs
- into a text keyring which has (textual DNS name, (textual algorithm,
- base64 secret)) pairs, or a dictionary containing (dns.name.Name, bytes)
- pairs into a text keyring which has (textual DNS name, base64 secret) pairs.
- @rtype: dict"""
-
- textring = {}
-
- def b64encode(secret):
- return base64.encodebytes(secret).decode().rstrip()
-
- for name, key in keyring.items():
- tname = name.to_text()
- if isinstance(key, bytes):
- textring[tname] = b64encode(key)
- else:
- if isinstance(key.secret, bytes):
- text_secret = b64encode(key.secret)
- else:
- text_secret = str(key.secret)
-
- textring[tname] = (key.algorithm.to_text(), text_secret)
- return textring
diff --git a/.venv/lib/python3.12/site-packages/dns/ttl.py b/.venv/lib/python3.12/site-packages/dns/ttl.py
deleted file mode 100644
index 264b033..0000000
--- a/.venv/lib/python3.12/site-packages/dns/ttl.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS TTL conversion."""
-
-from typing import Union
-
-import dns.exception
-
-# Technically TTLs are supposed to be between 0 and 2**31 - 1, with values
-# greater than that interpreted as 0, but we do not impose this policy here
-# as values > 2**31 - 1 occur in real world data.
-#
-# We leave it to applications to impose tighter bounds if desired.
-MAX_TTL = 2**32 - 1
-
-
-class BadTTL(dns.exception.SyntaxError):
- """DNS TTL value is not well-formed."""
-
-
-def from_text(text: str) -> int:
- """Convert the text form of a TTL to an integer.
-
- The BIND 8 units syntax for TTLs (e.g. '1w6d4h3m10s') is supported.
-
- *text*, a ``str``, the textual TTL.
-
- Raises ``dns.ttl.BadTTL`` if the TTL is not well-formed.
-
- Returns an ``int``.
- """
-
- if text.isdigit():
- total = int(text)
- elif len(text) == 0:
- raise BadTTL
- else:
- total = 0
- current = 0
- need_digit = True
- for c in text:
- if c.isdigit():
- current *= 10
- current += int(c)
- need_digit = False
- else:
- if need_digit:
- raise BadTTL
- c = c.lower()
- if c == "w":
- total += current * 604800
- elif c == "d":
- total += current * 86400
- elif c == "h":
- total += current * 3600
- elif c == "m":
- total += current * 60
- elif c == "s":
- total += current
- else:
- raise BadTTL("unknown unit '%s'" % c)
- current = 0
- need_digit = True
- if not current == 0:
- raise BadTTL("trailing integer")
- if total < 0 or total > MAX_TTL:
- raise BadTTL("TTL should be between 0 and 2**32 - 1 (inclusive)")
- return total
-
-
-def make(value: Union[int, str]) -> int:
- if isinstance(value, int):
- return value
- elif isinstance(value, str):
- return dns.ttl.from_text(value)
- else:
- raise ValueError("cannot convert value to TTL")
diff --git a/.venv/lib/python3.12/site-packages/dns/update.py b/.venv/lib/python3.12/site-packages/dns/update.py
deleted file mode 100644
index bf1157a..0000000
--- a/.venv/lib/python3.12/site-packages/dns/update.py
+++ /dev/null
@@ -1,386 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Dynamic Update Support"""
-
-from typing import Any, List, Optional, Union
-
-import dns.message
-import dns.name
-import dns.opcode
-import dns.rdata
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.tsig
-
-
-class UpdateSection(dns.enum.IntEnum):
- """Update sections"""
-
- ZONE = 0
- PREREQ = 1
- UPDATE = 2
- ADDITIONAL = 3
-
- @classmethod
- def _maximum(cls):
- return 3
-
-
-class UpdateMessage(dns.message.Message): # lgtm[py/missing-equals]
- # ignore the mypy error here as we mean to use a different enum
- _section_enum = UpdateSection # type: ignore
-
- def __init__(
- self,
- zone: Optional[Union[dns.name.Name, str]] = None,
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- keyring: Optional[Any] = None,
- keyname: Optional[dns.name.Name] = None,
- keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm,
- id: Optional[int] = None,
- ):
- """Initialize a new DNS Update object.
-
- See the documentation of the Message class for a complete
- description of the keyring dictionary.
-
- *zone*, a ``dns.name.Name``, ``str``, or ``None``, the zone
- which is being updated. ``None`` should only be used by dnspython's
- message constructors, as a zone is required for the convenience
- methods like ``add()``, ``replace()``, etc.
-
- *rdclass*, an ``int`` or ``str``, the class of the zone.
-
- The *keyring*, *keyname*, and *keyalgorithm* parameters are passed to
- ``use_tsig()``; see its documentation for details.
- """
- super().__init__(id=id)
- self.flags |= dns.opcode.to_flags(dns.opcode.UPDATE)
- if isinstance(zone, str):
- zone = dns.name.from_text(zone)
- self.origin = zone
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- self.zone_rdclass = rdclass
- if self.origin:
- self.find_rrset(
- self.zone,
- self.origin,
- rdclass,
- dns.rdatatype.SOA,
- create=True,
- force_unique=True,
- )
- if keyring is not None:
- self.use_tsig(keyring, keyname, algorithm=keyalgorithm)
-
- @property
- def zone(self) -> List[dns.rrset.RRset]:
- """The zone section."""
- return self.sections[0]
-
- @zone.setter
- def zone(self, v):
- self.sections[0] = v
-
- @property
- def prerequisite(self) -> List[dns.rrset.RRset]:
- """The prerequisite section."""
- return self.sections[1]
-
- @prerequisite.setter
- def prerequisite(self, v):
- self.sections[1] = v
-
- @property
- def update(self) -> List[dns.rrset.RRset]:
- """The update section."""
- return self.sections[2]
-
- @update.setter
- def update(self, v):
- self.sections[2] = v
-
- def _add_rr(self, name, ttl, rd, deleting=None, section=None):
- """Add a single RR to the update section."""
-
- if section is None:
- section = self.update
- covers = rd.covers()
- rrset = self.find_rrset(
- section, name, self.zone_rdclass, rd.rdtype, covers, deleting, True, True
- )
- rrset.add(rd, ttl)
-
- def _add(self, replace, section, name, *args):
- """Add records.
-
- *replace* is the replacement mode. If ``False``,
- RRs are added to an existing RRset; if ``True``, the RRset
- is replaced with the specified contents. The second
- argument is the section to add to. The third argument
- is always a name. The other arguments can be:
-
- - rdataset...
-
- - ttl, rdata...
-
- - ttl, rdtype, string...
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- if isinstance(args[0], dns.rdataset.Rdataset):
- for rds in args:
- if replace:
- self.delete(name, rds.rdtype)
- for rd in rds:
- self._add_rr(name, rds.ttl, rd, section=section)
- else:
- args = list(args)
- ttl = int(args.pop(0))
- if isinstance(args[0], dns.rdata.Rdata):
- if replace:
- self.delete(name, args[0].rdtype)
- for rd in args:
- self._add_rr(name, ttl, rd, section=section)
- else:
- rdtype = dns.rdatatype.RdataType.make(args.pop(0))
- if replace:
- self.delete(name, rdtype)
- for s in args:
- rd = dns.rdata.from_text(self.zone_rdclass, rdtype, s, self.origin)
- self._add_rr(name, ttl, rd, section=section)
-
- def add(self, name: Union[dns.name.Name, str], *args: Any) -> None:
- """Add records.
-
- The first argument is always a name. The other
- arguments can be:
-
- - rdataset...
-
- - ttl, rdata...
-
- - ttl, rdtype, string...
- """
-
- self._add(False, self.update, name, *args)
-
- def delete(self, name: Union[dns.name.Name, str], *args: Any) -> None:
- """Delete records.
-
- The first argument is always a name. The other
- arguments can be:
-
- - *empty*
-
- - rdataset...
-
- - rdata...
-
- - rdtype, [string...]
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- if len(args) == 0:
- self.find_rrset(
- self.update,
- name,
- dns.rdataclass.ANY,
- dns.rdatatype.ANY,
- dns.rdatatype.NONE,
- dns.rdataclass.ANY,
- True,
- True,
- )
- elif isinstance(args[0], dns.rdataset.Rdataset):
- for rds in args:
- for rd in rds:
- self._add_rr(name, 0, rd, dns.rdataclass.NONE)
- else:
- largs = list(args)
- if isinstance(largs[0], dns.rdata.Rdata):
- for rd in largs:
- self._add_rr(name, 0, rd, dns.rdataclass.NONE)
- else:
- rdtype = dns.rdatatype.RdataType.make(largs.pop(0))
- if len(largs) == 0:
- self.find_rrset(
- self.update,
- name,
- self.zone_rdclass,
- rdtype,
- dns.rdatatype.NONE,
- dns.rdataclass.ANY,
- True,
- True,
- )
- else:
- for s in largs:
- rd = dns.rdata.from_text(
- self.zone_rdclass,
- rdtype,
- s, # type: ignore[arg-type]
- self.origin,
- )
- self._add_rr(name, 0, rd, dns.rdataclass.NONE)
-
- def replace(self, name: Union[dns.name.Name, str], *args: Any) -> None:
- """Replace records.
-
- The first argument is always a name. The other
- arguments can be:
-
- - rdataset...
-
- - ttl, rdata...
-
- - ttl, rdtype, string...
-
- Note that if you want to replace the entire node, you should do
- a delete of the name followed by one or more calls to add.
- """
-
- self._add(True, self.update, name, *args)
-
- def present(self, name: Union[dns.name.Name, str], *args: Any) -> None:
- """Require that an owner name (and optionally an rdata type,
- or specific rdataset) exists as a prerequisite to the
- execution of the update.
-
- The first argument is always a name.
- The other arguments can be:
-
- - rdataset...
-
- - rdata...
-
- - rdtype, string...
- """
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- if len(args) == 0:
- self.find_rrset(
- self.prerequisite,
- name,
- dns.rdataclass.ANY,
- dns.rdatatype.ANY,
- dns.rdatatype.NONE,
- None,
- True,
- True,
- )
- elif (
- isinstance(args[0], dns.rdataset.Rdataset)
- or isinstance(args[0], dns.rdata.Rdata)
- or len(args) > 1
- ):
- if not isinstance(args[0], dns.rdataset.Rdataset):
- # Add a 0 TTL
- largs = list(args)
- largs.insert(0, 0) # type: ignore[arg-type]
- self._add(False, self.prerequisite, name, *largs)
- else:
- self._add(False, self.prerequisite, name, *args)
- else:
- rdtype = dns.rdatatype.RdataType.make(args[0])
- self.find_rrset(
- self.prerequisite,
- name,
- dns.rdataclass.ANY,
- rdtype,
- dns.rdatatype.NONE,
- None,
- True,
- True,
- )
-
- def absent(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Optional[Union[dns.rdatatype.RdataType, str]] = None,
- ) -> None:
- """Require that an owner name (and optionally an rdata type) does
- not exist as a prerequisite to the execution of the update."""
-
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- if rdtype is None:
- self.find_rrset(
- self.prerequisite,
- name,
- dns.rdataclass.NONE,
- dns.rdatatype.ANY,
- dns.rdatatype.NONE,
- None,
- True,
- True,
- )
- else:
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- self.find_rrset(
- self.prerequisite,
- name,
- dns.rdataclass.NONE,
- rdtype,
- dns.rdatatype.NONE,
- None,
- True,
- True,
- )
-
- def _get_one_rr_per_rrset(self, value):
- # Updates are always one_rr_per_rrset
- return True
-
- def _parse_rr_header(self, section, name, rdclass, rdtype):
- deleting = None
- empty = False
- if section == UpdateSection.ZONE:
- if (
- dns.rdataclass.is_metaclass(rdclass)
- or rdtype != dns.rdatatype.SOA
- or self.zone
- ):
- raise dns.exception.FormError
- else:
- if not self.zone:
- raise dns.exception.FormError
- if rdclass in (dns.rdataclass.ANY, dns.rdataclass.NONE):
- deleting = rdclass
- rdclass = self.zone[0].rdclass
- empty = (
- deleting == dns.rdataclass.ANY or section == UpdateSection.PREREQ
- )
- return (rdclass, rdtype, deleting, empty)
-
-
-# backwards compatibility
-Update = UpdateMessage
-
-### BEGIN generated UpdateSection constants
-
-ZONE = UpdateSection.ZONE
-PREREQ = UpdateSection.PREREQ
-UPDATE = UpdateSection.UPDATE
-ADDITIONAL = UpdateSection.ADDITIONAL
-
-### END generated UpdateSection constants
diff --git a/.venv/lib/python3.12/site-packages/dns/version.py b/.venv/lib/python3.12/site-packages/dns/version.py
deleted file mode 100644
index 251f258..0000000
--- a/.venv/lib/python3.12/site-packages/dns/version.py
+++ /dev/null
@@ -1,58 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""dnspython release version information."""
-
-#: MAJOR
-MAJOR = 2
-#: MINOR
-MINOR = 6
-#: MICRO
-MICRO = 1
-#: RELEASELEVEL
-RELEASELEVEL = 0x0F
-#: SERIAL
-SERIAL = 0
-
-if RELEASELEVEL == 0x0F: # pragma: no cover lgtm[py/unreachable-statement]
- #: version
- version = "%d.%d.%d" % (MAJOR, MINOR, MICRO) # lgtm[py/unreachable-statement]
-elif RELEASELEVEL == 0x00: # pragma: no cover lgtm[py/unreachable-statement]
- version = "%d.%d.%ddev%d" % (
- MAJOR,
- MINOR,
- MICRO,
- SERIAL,
- ) # lgtm[py/unreachable-statement]
-elif RELEASELEVEL == 0x0C: # pragma: no cover lgtm[py/unreachable-statement]
- version = "%d.%d.%drc%d" % (
- MAJOR,
- MINOR,
- MICRO,
- SERIAL,
- ) # lgtm[py/unreachable-statement]
-else: # pragma: no cover lgtm[py/unreachable-statement]
- version = "%d.%d.%d%x%d" % (
- MAJOR,
- MINOR,
- MICRO,
- RELEASELEVEL,
- SERIAL,
- ) # lgtm[py/unreachable-statement]
-
-#: hexversion
-hexversion = MAJOR << 24 | MINOR << 16 | MICRO << 8 | RELEASELEVEL << 4 | SERIAL
diff --git a/.venv/lib/python3.12/site-packages/dns/versioned.py b/.venv/lib/python3.12/site-packages/dns/versioned.py
deleted file mode 100644
index fd78e67..0000000
--- a/.venv/lib/python3.12/site-packages/dns/versioned.py
+++ /dev/null
@@ -1,318 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-"""DNS Versioned Zones."""
-
-import collections
-import threading
-from typing import Callable, Deque, Optional, Set, Union
-
-import dns.exception
-import dns.immutable
-import dns.name
-import dns.node
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.rdtypes.ANY.SOA
-import dns.zone
-
-
-class UseTransaction(dns.exception.DNSException):
- """To alter a versioned zone, use a transaction."""
-
-
-# Backwards compatibility
-Node = dns.zone.VersionedNode
-ImmutableNode = dns.zone.ImmutableVersionedNode
-Version = dns.zone.Version
-WritableVersion = dns.zone.WritableVersion
-ImmutableVersion = dns.zone.ImmutableVersion
-Transaction = dns.zone.Transaction
-
-
-class Zone(dns.zone.Zone): # lgtm[py/missing-equals]
- __slots__ = [
- "_versions",
- "_versions_lock",
- "_write_txn",
- "_write_waiters",
- "_write_event",
- "_pruning_policy",
- "_readers",
- ]
-
- node_factory = Node
-
- def __init__(
- self,
- origin: Optional[Union[dns.name.Name, str]],
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- relativize: bool = True,
- pruning_policy: Optional[Callable[["Zone", Version], Optional[bool]]] = None,
- ):
- """Initialize a versioned zone object.
-
- *origin* is the origin of the zone. It may be a ``dns.name.Name``,
- a ``str``, or ``None``. If ``None``, then the zone's origin will
- be set by the first ``$ORIGIN`` line in a zone file.
-
- *rdclass*, an ``int``, the zone's rdata class; the default is class IN.
-
- *relativize*, a ``bool``, determine's whether domain names are
- relativized to the zone's origin. The default is ``True``.
-
- *pruning policy*, a function taking a ``Zone`` and a ``Version`` and returning
- a ``bool``, or ``None``. Should the version be pruned? If ``None``,
- the default policy, which retains one version is used.
- """
- super().__init__(origin, rdclass, relativize)
- self._versions: Deque[Version] = collections.deque()
- self._version_lock = threading.Lock()
- if pruning_policy is None:
- self._pruning_policy = self._default_pruning_policy
- else:
- self._pruning_policy = pruning_policy
- self._write_txn: Optional[Transaction] = None
- self._write_event: Optional[threading.Event] = None
- self._write_waiters: Deque[threading.Event] = collections.deque()
- self._readers: Set[Transaction] = set()
- self._commit_version_unlocked(
- None, WritableVersion(self, replacement=True), origin
- )
-
- def reader(
- self, id: Optional[int] = None, serial: Optional[int] = None
- ) -> Transaction: # pylint: disable=arguments-differ
- if id is not None and serial is not None:
- raise ValueError("cannot specify both id and serial")
- with self._version_lock:
- if id is not None:
- version = None
- for v in reversed(self._versions):
- if v.id == id:
- version = v
- break
- if version is None:
- raise KeyError("version not found")
- elif serial is not None:
- if self.relativize:
- oname = dns.name.empty
- else:
- assert self.origin is not None
- oname = self.origin
- version = None
- for v in reversed(self._versions):
- n = v.nodes.get(oname)
- if n:
- rds = n.get_rdataset(self.rdclass, dns.rdatatype.SOA)
- if rds and rds[0].serial == serial:
- version = v
- break
- if version is None:
- raise KeyError("serial not found")
- else:
- version = self._versions[-1]
- txn = Transaction(self, False, version)
- self._readers.add(txn)
- return txn
-
- def writer(self, replacement: bool = False) -> Transaction:
- event = None
- while True:
- with self._version_lock:
- # Checking event == self._write_event ensures that either
- # no one was waiting before we got lucky and found no write
- # txn, or we were the one who was waiting and got woken up.
- # This prevents "taking cuts" when creating a write txn.
- if self._write_txn is None and event == self._write_event:
- # Creating the transaction defers version setup
- # (i.e. copying the nodes dictionary) until we
- # give up the lock, so that we hold the lock as
- # short a time as possible. This is why we call
- # _setup_version() below.
- self._write_txn = Transaction(
- self, replacement, make_immutable=True
- )
- # give up our exclusive right to make a Transaction
- self._write_event = None
- break
- # Someone else is writing already, so we will have to
- # wait, but we want to do the actual wait outside the
- # lock.
- event = threading.Event()
- self._write_waiters.append(event)
- # wait (note we gave up the lock!)
- #
- # We only wake one sleeper at a time, so it's important
- # that no event waiter can exit this method (e.g. via
- # cancellation) without returning a transaction or waking
- # someone else up.
- #
- # This is not a problem with Threading module threads as
- # they cannot be canceled, but could be an issue with trio
- # tasks when we do the async version of writer().
- # I.e. we'd need to do something like:
- #
- # try:
- # event.wait()
- # except trio.Cancelled:
- # with self._version_lock:
- # self._maybe_wakeup_one_waiter_unlocked()
- # raise
- #
- event.wait()
- # Do the deferred version setup.
- self._write_txn._setup_version()
- return self._write_txn
-
- def _maybe_wakeup_one_waiter_unlocked(self):
- if len(self._write_waiters) > 0:
- self._write_event = self._write_waiters.popleft()
- self._write_event.set()
-
- # pylint: disable=unused-argument
- def _default_pruning_policy(self, zone, version):
- return True
-
- # pylint: enable=unused-argument
-
- def _prune_versions_unlocked(self):
- assert len(self._versions) > 0
- # Don't ever prune a version greater than or equal to one that
- # a reader has open. This pins versions in memory while the
- # reader is open, and importantly lets the reader open a txn on
- # a successor version (e.g. if generating an IXFR).
- #
- # Note our definition of least_kept also ensures we do not try to
- # delete the greatest version.
- if len(self._readers) > 0:
- least_kept = min(txn.version.id for txn in self._readers)
- else:
- least_kept = self._versions[-1].id
- while self._versions[0].id < least_kept and self._pruning_policy(
- self, self._versions[0]
- ):
- self._versions.popleft()
-
- def set_max_versions(self, max_versions: Optional[int]) -> None:
- """Set a pruning policy that retains up to the specified number
- of versions
- """
- if max_versions is not None and max_versions < 1:
- raise ValueError("max versions must be at least 1")
- if max_versions is None:
-
- def policy(zone, _): # pylint: disable=unused-argument
- return False
-
- else:
-
- def policy(zone, _):
- return len(zone._versions) > max_versions
-
- self.set_pruning_policy(policy)
-
- def set_pruning_policy(
- self, policy: Optional[Callable[["Zone", Version], Optional[bool]]]
- ) -> None:
- """Set the pruning policy for the zone.
-
- The *policy* function takes a `Version` and returns `True` if
- the version should be pruned, and `False` otherwise. `None`
- may also be specified for policy, in which case the default policy
- is used.
-
- Pruning checking proceeds from the least version and the first
- time the function returns `False`, the checking stops. I.e. the
- retained versions are always a consecutive sequence.
- """
- if policy is None:
- policy = self._default_pruning_policy
- with self._version_lock:
- self._pruning_policy = policy
- self._prune_versions_unlocked()
-
- def _end_read(self, txn):
- with self._version_lock:
- self._readers.remove(txn)
- self._prune_versions_unlocked()
-
- def _end_write_unlocked(self, txn):
- assert self._write_txn == txn
- self._write_txn = None
- self._maybe_wakeup_one_waiter_unlocked()
-
- def _end_write(self, txn):
- with self._version_lock:
- self._end_write_unlocked(txn)
-
- def _commit_version_unlocked(self, txn, version, origin):
- self._versions.append(version)
- self._prune_versions_unlocked()
- self.nodes = version.nodes
- if self.origin is None:
- self.origin = origin
- # txn can be None in __init__ when we make the empty version.
- if txn is not None:
- self._end_write_unlocked(txn)
-
- def _commit_version(self, txn, version, origin):
- with self._version_lock:
- self._commit_version_unlocked(txn, version, origin)
-
- def _get_next_version_id(self):
- if len(self._versions) > 0:
- id = self._versions[-1].id + 1
- else:
- id = 1
- return id
-
- def find_node(
- self, name: Union[dns.name.Name, str], create: bool = False
- ) -> dns.node.Node:
- if create:
- raise UseTransaction
- return super().find_node(name)
-
- def delete_node(self, name: Union[dns.name.Name, str]) -> None:
- raise UseTransaction
-
- def find_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- create: bool = False,
- ) -> dns.rdataset.Rdataset:
- if create:
- raise UseTransaction
- rdataset = super().find_rdataset(name, rdtype, covers)
- return dns.rdataset.ImmutableRdataset(rdataset)
-
- def get_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- create: bool = False,
- ) -> Optional[dns.rdataset.Rdataset]:
- if create:
- raise UseTransaction
- rdataset = super().get_rdataset(name, rdtype, covers)
- if rdataset is not None:
- return dns.rdataset.ImmutableRdataset(rdataset)
- else:
- return None
-
- def delete_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> None:
- raise UseTransaction
-
- def replace_rdataset(
- self, name: Union[dns.name.Name, str], replacement: dns.rdataset.Rdataset
- ) -> None:
- raise UseTransaction
diff --git a/.venv/lib/python3.12/site-packages/dns/win32util.py b/.venv/lib/python3.12/site-packages/dns/win32util.py
deleted file mode 100644
index aaa7e93..0000000
--- a/.venv/lib/python3.12/site-packages/dns/win32util.py
+++ /dev/null
@@ -1,252 +0,0 @@
-import sys
-
-import dns._features
-
-if sys.platform == "win32":
- from typing import Any
-
- import dns.name
-
- _prefer_wmi = True
-
- import winreg # pylint: disable=import-error
-
- # Keep pylint quiet on non-windows.
- try:
- WindowsError is None # pylint: disable=used-before-assignment
- except KeyError:
- WindowsError = Exception
-
- if dns._features.have("wmi"):
- import threading
-
- import pythoncom # pylint: disable=import-error
- import wmi # pylint: disable=import-error
-
- _have_wmi = True
- else:
- _have_wmi = False
-
- def _config_domain(domain):
- # Sometimes DHCP servers add a '.' prefix to the default domain, and
- # Windows just stores such values in the registry (see #687).
- # Check for this and fix it.
- if domain.startswith("."):
- domain = domain[1:]
- return dns.name.from_text(domain)
-
- class DnsInfo:
- def __init__(self):
- self.domain = None
- self.nameservers = []
- self.search = []
-
- if _have_wmi:
-
- class _WMIGetter(threading.Thread):
- def __init__(self):
- super().__init__()
- self.info = DnsInfo()
-
- def run(self):
- pythoncom.CoInitialize()
- try:
- system = wmi.WMI()
- for interface in system.Win32_NetworkAdapterConfiguration():
- if interface.IPEnabled and interface.DNSServerSearchOrder:
- self.info.nameservers = list(interface.DNSServerSearchOrder)
- if interface.DNSDomain:
- self.info.domain = _config_domain(interface.DNSDomain)
- if interface.DNSDomainSuffixSearchOrder:
- self.info.search = [
- _config_domain(x)
- for x in interface.DNSDomainSuffixSearchOrder
- ]
- break
- finally:
- pythoncom.CoUninitialize()
-
- def get(self):
- # We always run in a separate thread to avoid any issues with
- # the COM threading model.
- self.start()
- self.join()
- return self.info
-
- else:
-
- class _WMIGetter: # type: ignore
- pass
-
- class _RegistryGetter:
- def __init__(self):
- self.info = DnsInfo()
-
- def _determine_split_char(self, entry):
- #
- # The windows registry irritatingly changes the list element
- # delimiter in between ' ' and ',' (and vice-versa) in various
- # versions of windows.
- #
- if entry.find(" ") >= 0:
- split_char = " "
- elif entry.find(",") >= 0:
- split_char = ","
- else:
- # probably a singleton; treat as a space-separated list.
- split_char = " "
- return split_char
-
- def _config_nameservers(self, nameservers):
- split_char = self._determine_split_char(nameservers)
- ns_list = nameservers.split(split_char)
- for ns in ns_list:
- if ns not in self.info.nameservers:
- self.info.nameservers.append(ns)
-
- def _config_search(self, search):
- split_char = self._determine_split_char(search)
- search_list = search.split(split_char)
- for s in search_list:
- s = _config_domain(s)
- if s not in self.info.search:
- self.info.search.append(s)
-
- def _config_fromkey(self, key, always_try_domain):
- try:
- servers, _ = winreg.QueryValueEx(key, "NameServer")
- except WindowsError:
- servers = None
- if servers:
- self._config_nameservers(servers)
- if servers or always_try_domain:
- try:
- dom, _ = winreg.QueryValueEx(key, "Domain")
- if dom:
- self.info.domain = _config_domain(dom)
- except WindowsError:
- pass
- else:
- try:
- servers, _ = winreg.QueryValueEx(key, "DhcpNameServer")
- except WindowsError:
- servers = None
- if servers:
- self._config_nameservers(servers)
- try:
- dom, _ = winreg.QueryValueEx(key, "DhcpDomain")
- if dom:
- self.info.domain = _config_domain(dom)
- except WindowsError:
- pass
- try:
- search, _ = winreg.QueryValueEx(key, "SearchList")
- except WindowsError:
- search = None
- if search is None:
- try:
- search, _ = winreg.QueryValueEx(key, "DhcpSearchList")
- except WindowsError:
- search = None
- if search:
- self._config_search(search)
-
- def _is_nic_enabled(self, lm, guid):
- # Look in the Windows Registry to determine whether the network
- # interface corresponding to the given guid is enabled.
- #
- # (Code contributed by Paul Marks, thanks!)
- #
- try:
- # This hard-coded location seems to be consistent, at least
- # from Windows 2000 through Vista.
- connection_key = winreg.OpenKey(
- lm,
- r"SYSTEM\CurrentControlSet\Control\Network"
- r"\{4D36E972-E325-11CE-BFC1-08002BE10318}"
- r"\%s\Connection" % guid,
- )
-
- try:
- # The PnpInstanceID points to a key inside Enum
- (pnp_id, ttype) = winreg.QueryValueEx(
- connection_key, "PnpInstanceID"
- )
-
- if ttype != winreg.REG_SZ:
- raise ValueError # pragma: no cover
-
- device_key = winreg.OpenKey(
- lm, r"SYSTEM\CurrentControlSet\Enum\%s" % pnp_id
- )
-
- try:
- # Get ConfigFlags for this device
- (flags, ttype) = winreg.QueryValueEx(device_key, "ConfigFlags")
-
- if ttype != winreg.REG_DWORD:
- raise ValueError # pragma: no cover
-
- # Based on experimentation, bit 0x1 indicates that the
- # device is disabled.
- #
- # XXXRTH I suspect we really want to & with 0x03 so
- # that CONFIGFLAGS_REMOVED devices are also ignored,
- # but we're shifting to WMI as ConfigFlags is not
- # supposed to be used.
- return not flags & 0x1
-
- finally:
- device_key.Close()
- finally:
- connection_key.Close()
- except Exception: # pragma: no cover
- return False
-
- def get(self):
- """Extract resolver configuration from the Windows registry."""
-
- lm = winreg.ConnectRegistry(None, winreg.HKEY_LOCAL_MACHINE)
- try:
- tcp_params = winreg.OpenKey(
- lm, r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters"
- )
- try:
- self._config_fromkey(tcp_params, True)
- finally:
- tcp_params.Close()
- interfaces = winreg.OpenKey(
- lm,
- r"SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces",
- )
- try:
- i = 0
- while True:
- try:
- guid = winreg.EnumKey(interfaces, i)
- i += 1
- key = winreg.OpenKey(interfaces, guid)
- try:
- if not self._is_nic_enabled(lm, guid):
- continue
- self._config_fromkey(key, False)
- finally:
- key.Close()
- except EnvironmentError:
- break
- finally:
- interfaces.Close()
- finally:
- lm.Close()
- return self.info
-
- _getter_class: Any
- if _have_wmi and _prefer_wmi:
- _getter_class = _WMIGetter
- else:
- _getter_class = _RegistryGetter
-
- def get_dns_info():
- """Extract resolver configuration."""
- getter = _getter_class()
- return getter.get()
diff --git a/.venv/lib/python3.12/site-packages/dns/wire.py b/.venv/lib/python3.12/site-packages/dns/wire.py
deleted file mode 100644
index 9f9b157..0000000
--- a/.venv/lib/python3.12/site-packages/dns/wire.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-import contextlib
-import struct
-from typing import Iterator, Optional, Tuple
-
-import dns.exception
-import dns.name
-
-
-class Parser:
- def __init__(self, wire: bytes, current: int = 0):
- self.wire = wire
- self.current = 0
- self.end = len(self.wire)
- if current:
- self.seek(current)
- self.furthest = current
-
- def remaining(self) -> int:
- return self.end - self.current
-
- def get_bytes(self, size: int) -> bytes:
- assert size >= 0
- if size > self.remaining():
- raise dns.exception.FormError
- output = self.wire[self.current : self.current + size]
- self.current += size
- self.furthest = max(self.furthest, self.current)
- return output
-
- def get_counted_bytes(self, length_size: int = 1) -> bytes:
- length = int.from_bytes(self.get_bytes(length_size), "big")
- return self.get_bytes(length)
-
- def get_remaining(self) -> bytes:
- return self.get_bytes(self.remaining())
-
- def get_uint8(self) -> int:
- return struct.unpack("!B", self.get_bytes(1))[0]
-
- def get_uint16(self) -> int:
- return struct.unpack("!H", self.get_bytes(2))[0]
-
- def get_uint32(self) -> int:
- return struct.unpack("!I", self.get_bytes(4))[0]
-
- def get_uint48(self) -> int:
- return int.from_bytes(self.get_bytes(6), "big")
-
- def get_struct(self, format: str) -> Tuple:
- return struct.unpack(format, self.get_bytes(struct.calcsize(format)))
-
- def get_name(self, origin: Optional["dns.name.Name"] = None) -> "dns.name.Name":
- name = dns.name.from_wire_parser(self)
- if origin:
- name = name.relativize(origin)
- return name
-
- def seek(self, where: int) -> None:
- # Note that seeking to the end is OK! (If you try to read
- # after such a seek, you'll get an exception as expected.)
- if where < 0 or where > self.end:
- raise dns.exception.FormError
- self.current = where
-
- @contextlib.contextmanager
- def restrict_to(self, size: int) -> Iterator:
- assert size >= 0
- if size > self.remaining():
- raise dns.exception.FormError
- saved_end = self.end
- try:
- self.end = self.current + size
- yield
- # We make this check here and not in the finally as we
- # don't want to raise if we're already raising for some
- # other reason.
- if self.current != self.end:
- raise dns.exception.FormError
- finally:
- self.end = saved_end
-
- @contextlib.contextmanager
- def restore_furthest(self) -> Iterator:
- try:
- yield None
- finally:
- self.current = self.furthest
diff --git a/.venv/lib/python3.12/site-packages/dns/xfr.py b/.venv/lib/python3.12/site-packages/dns/xfr.py
deleted file mode 100644
index dd247d3..0000000
--- a/.venv/lib/python3.12/site-packages/dns/xfr.py
+++ /dev/null
@@ -1,343 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2017 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-from typing import Any, List, Optional, Tuple, Union
-
-import dns.exception
-import dns.message
-import dns.name
-import dns.rcode
-import dns.rdataset
-import dns.rdatatype
-import dns.serial
-import dns.transaction
-import dns.tsig
-import dns.zone
-
-
-class TransferError(dns.exception.DNSException):
- """A zone transfer response got a non-zero rcode."""
-
- def __init__(self, rcode):
- message = "Zone transfer error: %s" % dns.rcode.to_text(rcode)
- super().__init__(message)
- self.rcode = rcode
-
-
-class SerialWentBackwards(dns.exception.FormError):
- """The current serial number is less than the serial we know."""
-
-
-class UseTCP(dns.exception.DNSException):
- """This IXFR cannot be completed with UDP."""
-
-
-class Inbound:
- """
- State machine for zone transfers.
- """
-
- def __init__(
- self,
- txn_manager: dns.transaction.TransactionManager,
- rdtype: dns.rdatatype.RdataType = dns.rdatatype.AXFR,
- serial: Optional[int] = None,
- is_udp: bool = False,
- ):
- """Initialize an inbound zone transfer.
-
- *txn_manager* is a :py:class:`dns.transaction.TransactionManager`.
-
- *rdtype* can be `dns.rdatatype.AXFR` or `dns.rdatatype.IXFR`
-
- *serial* is the base serial number for IXFRs, and is required in
- that case.
-
- *is_udp*, a ``bool`` indidicates if UDP is being used for this
- XFR.
- """
- self.txn_manager = txn_manager
- self.txn: Optional[dns.transaction.Transaction] = None
- self.rdtype = rdtype
- if rdtype == dns.rdatatype.IXFR:
- if serial is None:
- raise ValueError("a starting serial must be supplied for IXFRs")
- elif is_udp:
- raise ValueError("is_udp specified for AXFR")
- self.serial = serial
- self.is_udp = is_udp
- (_, _, self.origin) = txn_manager.origin_information()
- self.soa_rdataset: Optional[dns.rdataset.Rdataset] = None
- self.done = False
- self.expecting_SOA = False
- self.delete_mode = False
-
- def process_message(self, message: dns.message.Message) -> bool:
- """Process one message in the transfer.
-
- The message should have the same relativization as was specified when
- the `dns.xfr.Inbound` was created. The message should also have been
- created with `one_rr_per_rrset=True` because order matters.
-
- Returns `True` if the transfer is complete, and `False` otherwise.
- """
- if self.txn is None:
- replacement = self.rdtype == dns.rdatatype.AXFR
- self.txn = self.txn_manager.writer(replacement)
- rcode = message.rcode()
- if rcode != dns.rcode.NOERROR:
- raise TransferError(rcode)
- #
- # We don't require a question section, but if it is present is
- # should be correct.
- #
- if len(message.question) > 0:
- if message.question[0].name != self.origin:
- raise dns.exception.FormError("wrong question name")
- if message.question[0].rdtype != self.rdtype:
- raise dns.exception.FormError("wrong question rdatatype")
- answer_index = 0
- if self.soa_rdataset is None:
- #
- # This is the first message. We're expecting an SOA at
- # the origin.
- #
- if not message.answer or message.answer[0].name != self.origin:
- raise dns.exception.FormError("No answer or RRset not for zone origin")
- rrset = message.answer[0]
- rdataset = rrset
- if rdataset.rdtype != dns.rdatatype.SOA:
- raise dns.exception.FormError("first RRset is not an SOA")
- answer_index = 1
- self.soa_rdataset = rdataset.copy()
- if self.rdtype == dns.rdatatype.IXFR:
- if self.soa_rdataset[0].serial == self.serial:
- #
- # We're already up-to-date.
- #
- self.done = True
- elif dns.serial.Serial(self.soa_rdataset[0].serial) < self.serial:
- # It went backwards!
- raise SerialWentBackwards
- else:
- if self.is_udp and len(message.answer[answer_index:]) == 0:
- #
- # There are no more records, so this is the
- # "truncated" response. Say to use TCP
- #
- raise UseTCP
- #
- # Note we're expecting another SOA so we can detect
- # if this IXFR response is an AXFR-style response.
- #
- self.expecting_SOA = True
- #
- # Process the answer section (other than the initial SOA in
- # the first message).
- #
- for rrset in message.answer[answer_index:]:
- name = rrset.name
- rdataset = rrset
- if self.done:
- raise dns.exception.FormError("answers after final SOA")
- assert self.txn is not None # for mypy
- if rdataset.rdtype == dns.rdatatype.SOA and name == self.origin:
- #
- # Every time we see an origin SOA delete_mode inverts
- #
- if self.rdtype == dns.rdatatype.IXFR:
- self.delete_mode = not self.delete_mode
- #
- # If this SOA Rdataset is equal to the first we saw
- # then we're finished. If this is an IXFR we also
- # check that we're seeing the record in the expected
- # part of the response.
- #
- if rdataset == self.soa_rdataset and (
- self.rdtype == dns.rdatatype.AXFR
- or (self.rdtype == dns.rdatatype.IXFR and self.delete_mode)
- ):
- #
- # This is the final SOA
- #
- if self.expecting_SOA:
- # We got an empty IXFR sequence!
- raise dns.exception.FormError("empty IXFR sequence")
- if (
- self.rdtype == dns.rdatatype.IXFR
- and self.serial != rdataset[0].serial
- ):
- raise dns.exception.FormError("unexpected end of IXFR sequence")
- self.txn.replace(name, rdataset)
- self.txn.commit()
- self.txn = None
- self.done = True
- else:
- #
- # This is not the final SOA
- #
- self.expecting_SOA = False
- if self.rdtype == dns.rdatatype.IXFR:
- if self.delete_mode:
- # This is the start of an IXFR deletion set
- if rdataset[0].serial != self.serial:
- raise dns.exception.FormError(
- "IXFR base serial mismatch"
- )
- else:
- # This is the start of an IXFR addition set
- self.serial = rdataset[0].serial
- self.txn.replace(name, rdataset)
- else:
- # We saw a non-final SOA for the origin in an AXFR.
- raise dns.exception.FormError("unexpected origin SOA in AXFR")
- continue
- if self.expecting_SOA:
- #
- # We made an IXFR request and are expecting another
- # SOA RR, but saw something else, so this must be an
- # AXFR response.
- #
- self.rdtype = dns.rdatatype.AXFR
- self.expecting_SOA = False
- self.delete_mode = False
- self.txn.rollback()
- self.txn = self.txn_manager.writer(True)
- #
- # Note we are falling through into the code below
- # so whatever rdataset this was gets written.
- #
- # Add or remove the data
- if self.delete_mode:
- self.txn.delete_exact(name, rdataset)
- else:
- self.txn.add(name, rdataset)
- if self.is_udp and not self.done:
- #
- # This is a UDP IXFR and we didn't get to done, and we didn't
- # get the proper "truncated" response
- #
- raise dns.exception.FormError("unexpected end of UDP IXFR")
- return self.done
-
- #
- # Inbounds are context managers.
- #
-
- def __enter__(self):
- return self
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- if self.txn:
- self.txn.rollback()
- return False
-
-
-def make_query(
- txn_manager: dns.transaction.TransactionManager,
- serial: Optional[int] = 0,
- use_edns: Optional[Union[int, bool]] = None,
- ednsflags: Optional[int] = None,
- payload: Optional[int] = None,
- request_payload: Optional[int] = None,
- options: Optional[List[dns.edns.Option]] = None,
- keyring: Any = None,
- keyname: Optional[dns.name.Name] = None,
- keyalgorithm: Union[dns.name.Name, str] = dns.tsig.default_algorithm,
-) -> Tuple[dns.message.QueryMessage, Optional[int]]:
- """Make an AXFR or IXFR query.
-
- *txn_manager* is a ``dns.transaction.TransactionManager``, typically a
- ``dns.zone.Zone``.
-
- *serial* is an ``int`` or ``None``. If 0, then IXFR will be
- attempted using the most recent serial number from the
- *txn_manager*; it is the caller's responsibility to ensure there
- are no write transactions active that could invalidate the
- retrieved serial. If a serial cannot be determined, AXFR will be
- forced. Other integer values are the starting serial to use.
- ``None`` forces an AXFR.
-
- Please see the documentation for :py:func:`dns.message.make_query` and
- :py:func:`dns.message.Message.use_tsig` for details on the other parameters
- to this function.
-
- Returns a `(query, serial)` tuple.
- """
- (zone_origin, _, origin) = txn_manager.origin_information()
- if zone_origin is None:
- raise ValueError("no zone origin")
- if serial is None:
- rdtype = dns.rdatatype.AXFR
- elif not isinstance(serial, int):
- raise ValueError("serial is not an integer")
- elif serial == 0:
- with txn_manager.reader() as txn:
- rdataset = txn.get(origin, "SOA")
- if rdataset:
- serial = rdataset[0].serial
- rdtype = dns.rdatatype.IXFR
- else:
- serial = None
- rdtype = dns.rdatatype.AXFR
- elif serial > 0 and serial < 4294967296:
- rdtype = dns.rdatatype.IXFR
- else:
- raise ValueError("serial out-of-range")
- rdclass = txn_manager.get_class()
- q = dns.message.make_query(
- zone_origin,
- rdtype,
- rdclass,
- use_edns,
- False,
- ednsflags,
- payload,
- request_payload,
- options,
- )
- if serial is not None:
- rdata = dns.rdata.from_text(rdclass, "SOA", f". . {serial} 0 0 0 0")
- rrset = q.find_rrset(
- q.authority, zone_origin, rdclass, dns.rdatatype.SOA, create=True
- )
- rrset.add(rdata, 0)
- if keyring is not None:
- q.use_tsig(keyring, keyname, algorithm=keyalgorithm)
- return (q, serial)
-
-
-def extract_serial_from_query(query: dns.message.Message) -> Optional[int]:
- """Extract the SOA serial number from query if it is an IXFR and return
- it, otherwise return None.
-
- *query* is a dns.message.QueryMessage that is an IXFR or AXFR request.
-
- Raises if the query is not an IXFR or AXFR, or if an IXFR doesn't have
- an appropriate SOA RRset in the authority section.
- """
- if not isinstance(query, dns.message.QueryMessage):
- raise ValueError("query not a QueryMessage")
- question = query.question[0]
- if question.rdtype == dns.rdatatype.AXFR:
- return None
- elif question.rdtype != dns.rdatatype.IXFR:
- raise ValueError("query is not an AXFR or IXFR")
- soa = query.find_rrset(
- query.authority, question.name, question.rdclass, dns.rdatatype.SOA
- )
- return soa[0].serial
diff --git a/.venv/lib/python3.12/site-packages/dns/zone.py b/.venv/lib/python3.12/site-packages/dns/zone.py
deleted file mode 100644
index 844919e..0000000
--- a/.venv/lib/python3.12/site-packages/dns/zone.py
+++ /dev/null
@@ -1,1434 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Zones."""
-
-import contextlib
-import io
-import os
-import struct
-from typing import (
- Any,
- Callable,
- Iterable,
- Iterator,
- List,
- MutableMapping,
- Optional,
- Set,
- Tuple,
- Union,
-)
-
-import dns.exception
-import dns.grange
-import dns.immutable
-import dns.name
-import dns.node
-import dns.rdata
-import dns.rdataclass
-import dns.rdataset
-import dns.rdatatype
-import dns.rdtypes.ANY.SOA
-import dns.rdtypes.ANY.ZONEMD
-import dns.rrset
-import dns.tokenizer
-import dns.transaction
-import dns.ttl
-import dns.zonefile
-from dns.zonetypes import DigestHashAlgorithm, DigestScheme, _digest_hashers
-
-
-class BadZone(dns.exception.DNSException):
- """The DNS zone is malformed."""
-
-
-class NoSOA(BadZone):
- """The DNS zone has no SOA RR at its origin."""
-
-
-class NoNS(BadZone):
- """The DNS zone has no NS RRset at its origin."""
-
-
-class UnknownOrigin(BadZone):
- """The DNS zone's origin is unknown."""
-
-
-class UnsupportedDigestScheme(dns.exception.DNSException):
- """The zone digest's scheme is unsupported."""
-
-
-class UnsupportedDigestHashAlgorithm(dns.exception.DNSException):
- """The zone digest's origin is unsupported."""
-
-
-class NoDigest(dns.exception.DNSException):
- """The DNS zone has no ZONEMD RRset at its origin."""
-
-
-class DigestVerificationFailure(dns.exception.DNSException):
- """The ZONEMD digest failed to verify."""
-
-
-def _validate_name(
- name: dns.name.Name,
- origin: Optional[dns.name.Name],
- relativize: bool,
-) -> dns.name.Name:
- # This name validation code is shared by Zone and Version
- if origin is None:
- # This should probably never happen as other code (e.g.
- # _rr_line) will notice the lack of an origin before us, but
- # we check just in case!
- raise KeyError("no zone origin is defined")
- if name.is_absolute():
- if not name.is_subdomain(origin):
- raise KeyError("name parameter must be a subdomain of the zone origin")
- if relativize:
- name = name.relativize(origin)
- else:
- # We have a relative name. Make sure that the derelativized name is
- # not too long.
- try:
- abs_name = name.derelativize(origin)
- except dns.name.NameTooLong:
- # We map dns.name.NameTooLong to KeyError to be consistent with
- # the other exceptions above.
- raise KeyError("relative name too long for zone")
- if not relativize:
- # We have a relative name in a non-relative zone, so use the
- # derelativized name.
- name = abs_name
- return name
-
-
-class Zone(dns.transaction.TransactionManager):
- """A DNS zone.
-
- A ``Zone`` is a mapping from names to nodes. The zone object may be
- treated like a Python dictionary, e.g. ``zone[name]`` will retrieve
- the node associated with that name. The *name* may be a
- ``dns.name.Name object``, or it may be a string. In either case,
- if the name is relative it is treated as relative to the origin of
- the zone.
- """
-
- node_factory: Callable[[], dns.node.Node] = dns.node.Node
- map_factory: Callable[[], MutableMapping[dns.name.Name, dns.node.Node]] = dict
- writable_version_factory: Optional[Callable[[], "WritableVersion"]] = None
- immutable_version_factory: Optional[Callable[[], "ImmutableVersion"]] = None
-
- __slots__ = ["rdclass", "origin", "nodes", "relativize"]
-
- def __init__(
- self,
- origin: Optional[Union[dns.name.Name, str]],
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- relativize: bool = True,
- ):
- """Initialize a zone object.
-
- *origin* is the origin of the zone. It may be a ``dns.name.Name``,
- a ``str``, or ``None``. If ``None``, then the zone's origin will
- be set by the first ``$ORIGIN`` line in a zone file.
-
- *rdclass*, an ``int``, the zone's rdata class; the default is class IN.
-
- *relativize*, a ``bool``, determine's whether domain names are
- relativized to the zone's origin. The default is ``True``.
- """
-
- if origin is not None:
- if isinstance(origin, str):
- origin = dns.name.from_text(origin)
- elif not isinstance(origin, dns.name.Name):
- raise ValueError("origin parameter must be convertible to a DNS name")
- if not origin.is_absolute():
- raise ValueError("origin parameter must be an absolute name")
- self.origin = origin
- self.rdclass = rdclass
- self.nodes: MutableMapping[dns.name.Name, dns.node.Node] = self.map_factory()
- self.relativize = relativize
-
- def __eq__(self, other):
- """Two zones are equal if they have the same origin, class, and
- nodes.
-
- Returns a ``bool``.
- """
-
- if not isinstance(other, Zone):
- return False
- if (
- self.rdclass != other.rdclass
- or self.origin != other.origin
- or self.nodes != other.nodes
- ):
- return False
- return True
-
- def __ne__(self, other):
- """Are two zones not equal?
-
- Returns a ``bool``.
- """
-
- return not self.__eq__(other)
-
- def _validate_name(self, name: Union[dns.name.Name, str]) -> dns.name.Name:
- # Note that any changes in this method should have corresponding changes
- # made in the Version _validate_name() method.
- if isinstance(name, str):
- name = dns.name.from_text(name, None)
- elif not isinstance(name, dns.name.Name):
- raise KeyError("name parameter must be convertible to a DNS name")
- return _validate_name(name, self.origin, self.relativize)
-
- def __getitem__(self, key):
- key = self._validate_name(key)
- return self.nodes[key]
-
- def __setitem__(self, key, value):
- key = self._validate_name(key)
- self.nodes[key] = value
-
- def __delitem__(self, key):
- key = self._validate_name(key)
- del self.nodes[key]
-
- def __iter__(self):
- return self.nodes.__iter__()
-
- def keys(self):
- return self.nodes.keys()
-
- def values(self):
- return self.nodes.values()
-
- def items(self):
- return self.nodes.items()
-
- def get(self, key):
- key = self._validate_name(key)
- return self.nodes.get(key)
-
- def __contains__(self, key):
- key = self._validate_name(key)
- return key in self.nodes
-
- def find_node(
- self, name: Union[dns.name.Name, str], create: bool = False
- ) -> dns.node.Node:
- """Find a node in the zone, possibly creating it.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Raises ``KeyError`` if the name is not known and create was
- not specified, or if the name was not a subdomain of the origin.
-
- Returns a ``dns.node.Node``.
- """
-
- name = self._validate_name(name)
- node = self.nodes.get(name)
- if node is None:
- if not create:
- raise KeyError
- node = self.node_factory()
- self.nodes[name] = node
- return node
-
- def get_node(
- self, name: Union[dns.name.Name, str], create: bool = False
- ) -> Optional[dns.node.Node]:
- """Get a node in the zone, possibly creating it.
-
- This method is like ``find_node()``, except it returns None instead
- of raising an exception if the node does not exist and creation
- has not been requested.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Returns a ``dns.node.Node`` or ``None``.
- """
-
- try:
- node = self.find_node(name, create)
- except KeyError:
- node = None
- return node
-
- def delete_node(self, name: Union[dns.name.Name, str]) -> None:
- """Delete the specified node if it exists.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- It is not an error if the node does not exist.
- """
-
- name = self._validate_name(name)
- if name in self.nodes:
- del self.nodes[name]
-
- def find_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- create: bool = False,
- ) -> dns.rdataset.Rdataset:
- """Look for an rdataset with the specified name and type in the zone,
- and return an rdataset encapsulating it.
-
- The rdataset returned is not a copy; changes to it will change
- the zone.
-
- KeyError is raised if the name or type are not found.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdatatype.RdataType`` or ``str`` the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Raises ``KeyError`` if the name is not known and create was
- not specified, or if the name was not a subdomain of the origin.
-
- Returns a ``dns.rdataset.Rdataset``.
- """
-
- name = self._validate_name(name)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- node = self.find_node(name, create)
- return node.find_rdataset(self.rdclass, rdtype, covers, create)
-
- def get_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- create: bool = False,
- ) -> Optional[dns.rdataset.Rdataset]:
- """Look for an rdataset with the specified name and type in the zone.
-
- This method is like ``find_rdataset()``, except it returns None instead
- of raising an exception if the rdataset does not exist and creation
- has not been requested.
-
- The rdataset returned is not a copy; changes to it will change
- the zone.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Raises ``KeyError`` if the name is not known and create was
- not specified, or if the name was not a subdomain of the origin.
-
- Returns a ``dns.rdataset.Rdataset`` or ``None``.
- """
-
- try:
- rdataset = self.find_rdataset(name, rdtype, covers, create)
- except KeyError:
- rdataset = None
- return rdataset
-
- def delete_rdataset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> None:
- """Delete the rdataset matching *rdtype* and *covers*, if it
- exists at the node specified by *name*.
-
- It is not an error if the node does not exist, or if there is no matching
- rdataset at the node.
-
- If the node has no rdatasets after the deletion, it will itself be deleted.
-
- *name*: the name of the node to find. The value may be a ``dns.name.Name`` or a
- ``str``. If absolute, the name must be a subdomain of the zone's origin. If
- ``zone.relativize`` is ``True``, then the name will be relativized.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdatatype.RdataType`` or ``str`` or ``None``, the covered
- type. Usually this value is ``dns.rdatatype.NONE``, but if the rdtype is
- ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``, then the covers value will be
- the rdata type the SIG/RRSIG covers. The library treats the SIG and RRSIG types
- as if they were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA). This
- makes RRSIGs much easier to work with than if RRSIGs covering different rdata
- types were aggregated into a single RRSIG rdataset.
- """
-
- name = self._validate_name(name)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- node = self.get_node(name)
- if node is not None:
- node.delete_rdataset(self.rdclass, rdtype, covers)
- if len(node) == 0:
- self.delete_node(name)
-
- def replace_rdataset(
- self, name: Union[dns.name.Name, str], replacement: dns.rdataset.Rdataset
- ) -> None:
- """Replace an rdataset at name.
-
- It is not an error if there is no rdataset matching I{replacement}.
-
- Ownership of the *replacement* object is transferred to the zone;
- in other words, this method does not store a copy of *replacement*
- at the node, it stores *replacement* itself.
-
- If the node does not exist, it is created.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *replacement*, a ``dns.rdataset.Rdataset``, the replacement rdataset.
- """
-
- if replacement.rdclass != self.rdclass:
- raise ValueError("replacement.rdclass != zone.rdclass")
- node = self.find_node(name, True)
- node.replace_rdataset(replacement)
-
- def find_rrset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> dns.rrset.RRset:
- """Look for an rdataset with the specified name and type in the zone,
- and return an RRset encapsulating it.
-
- This method is less efficient than the similar
- ``find_rdataset()`` because it creates an RRset instead of
- returning the matching rdataset. It may be more convenient
- for some uses since it returns an object which binds the owner
- name to the rdataset.
-
- This method may not be used to create new nodes or rdatasets;
- use ``find_rdataset`` instead.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *rdtype*, a ``dns.rdatatype.RdataType`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdatatype.RdataType`` or ``str``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Raises ``KeyError`` if the name is not known and create was
- not specified, or if the name was not a subdomain of the origin.
-
- Returns a ``dns.rrset.RRset`` or ``None``.
- """
-
- vname = self._validate_name(name)
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- rdataset = self.nodes[vname].find_rdataset(self.rdclass, rdtype, covers)
- rrset = dns.rrset.RRset(vname, self.rdclass, rdtype, covers)
- rrset.update(rdataset)
- return rrset
-
- def get_rrset(
- self,
- name: Union[dns.name.Name, str],
- rdtype: Union[dns.rdatatype.RdataType, str],
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> Optional[dns.rrset.RRset]:
- """Look for an rdataset with the specified name and type in the zone,
- and return an RRset encapsulating it.
-
- This method is less efficient than the similar ``get_rdataset()``
- because it creates an RRset instead of returning the matching
- rdataset. It may be more convenient for some uses since it
- returns an object which binds the owner name to the rdataset.
-
- This method may not be used to create new nodes or rdatasets;
- use ``get_rdataset()`` instead.
-
- *name*: the name of the node to find.
- The value may be a ``dns.name.Name`` or a ``str``. If absolute, the
- name must be a subdomain of the zone's origin. If ``zone.relativize``
- is ``True``, then the name will be relativized.
-
- *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
-
- *create*, a ``bool``. If true, the node will be created if it does
- not exist.
-
- Returns a ``dns.rrset.RRset`` or ``None``.
- """
-
- try:
- rrset = self.find_rrset(name, rdtype, covers)
- except KeyError:
- rrset = None
- return rrset
-
- def iterate_rdatasets(
- self,
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.ANY,
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> Iterator[Tuple[dns.name.Name, dns.rdataset.Rdataset]]:
- """Return a generator which yields (name, rdataset) tuples for
- all rdatasets in the zone which have the specified *rdtype*
- and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default,
- then all rdatasets will be matched.
-
- *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
- """
-
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- for name, node in self.items():
- for rds in node:
- if rdtype == dns.rdatatype.ANY or (
- rds.rdtype == rdtype and rds.covers == covers
- ):
- yield (name, rds)
-
- def iterate_rdatas(
- self,
- rdtype: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.ANY,
- covers: Union[dns.rdatatype.RdataType, str] = dns.rdatatype.NONE,
- ) -> Iterator[Tuple[dns.name.Name, int, dns.rdata.Rdata]]:
- """Return a generator which yields (name, ttl, rdata) tuples for
- all rdatas in the zone which have the specified *rdtype*
- and *covers*. If *rdtype* is ``dns.rdatatype.ANY``, the default,
- then all rdatas will be matched.
-
- *rdtype*, a ``dns.rdataset.Rdataset`` or ``str``, the rdata type desired.
-
- *covers*, a ``dns.rdataset.Rdataset`` or ``str``, the covered type.
- Usually this value is ``dns.rdatatype.NONE``, but if the
- rdtype is ``dns.rdatatype.SIG`` or ``dns.rdatatype.RRSIG``,
- then the covers value will be the rdata type the SIG/RRSIG
- covers. The library treats the SIG and RRSIG types as if they
- were a family of types, e.g. RRSIG(A), RRSIG(NS), RRSIG(SOA).
- This makes RRSIGs much easier to work with than if RRSIGs
- covering different rdata types were aggregated into a single
- RRSIG rdataset.
- """
-
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- covers = dns.rdatatype.RdataType.make(covers)
- for name, node in self.items():
- for rds in node:
- if rdtype == dns.rdatatype.ANY or (
- rds.rdtype == rdtype and rds.covers == covers
- ):
- for rdata in rds:
- yield (name, rds.ttl, rdata)
-
- def to_file(
- self,
- f: Any,
- sorted: bool = True,
- relativize: bool = True,
- nl: Optional[str] = None,
- want_comments: bool = False,
- want_origin: bool = False,
- ) -> None:
- """Write a zone to a file.
-
- *f*, a file or `str`. If *f* is a string, it is treated
- as the name of a file to open.
-
- *sorted*, a ``bool``. If True, the default, then the file
- will be written with the names sorted in DNSSEC order from
- least to greatest. Otherwise the names will be written in
- whatever order they happen to have in the zone's dictionary.
-
- *relativize*, a ``bool``. If True, the default, then domain
- names in the output will be relativized to the zone's origin
- if possible.
-
- *nl*, a ``str`` or None. The end of line string. If not
- ``None``, the output will use the platform's native
- end-of-line marker (i.e. LF on POSIX, CRLF on Windows).
-
- *want_comments*, a ``bool``. If ``True``, emit end-of-line comments
- as part of writing the file. If ``False``, the default, do not
- emit them.
-
- *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at
- the start of the file. If ``False``, the default, do not emit
- one.
- """
-
- if isinstance(f, str):
- cm: contextlib.AbstractContextManager = open(f, "wb")
- else:
- cm = contextlib.nullcontext(f)
- with cm as f:
- # must be in this way, f.encoding may contain None, or even
- # attribute may not be there
- file_enc = getattr(f, "encoding", None)
- if file_enc is None:
- file_enc = "utf-8"
-
- if nl is None:
- # binary mode, '\n' is not enough
- nl_b = os.linesep.encode(file_enc)
- nl = "\n"
- elif isinstance(nl, str):
- nl_b = nl.encode(file_enc)
- else:
- nl_b = nl
- nl = nl.decode()
-
- if want_origin:
- assert self.origin is not None
- l = "$ORIGIN " + self.origin.to_text()
- l_b = l.encode(file_enc)
- try:
- f.write(l_b)
- f.write(nl_b)
- except TypeError: # textual mode
- f.write(l)
- f.write(nl)
-
- if sorted:
- names = list(self.keys())
- names.sort()
- else:
- names = self.keys()
- for n in names:
- l = self[n].to_text(
- n,
- origin=self.origin,
- relativize=relativize,
- want_comments=want_comments,
- )
- l_b = l.encode(file_enc)
-
- try:
- f.write(l_b)
- f.write(nl_b)
- except TypeError: # textual mode
- f.write(l)
- f.write(nl)
-
- def to_text(
- self,
- sorted: bool = True,
- relativize: bool = True,
- nl: Optional[str] = None,
- want_comments: bool = False,
- want_origin: bool = False,
- ) -> str:
- """Return a zone's text as though it were written to a file.
-
- *sorted*, a ``bool``. If True, the default, then the file
- will be written with the names sorted in DNSSEC order from
- least to greatest. Otherwise the names will be written in
- whatever order they happen to have in the zone's dictionary.
-
- *relativize*, a ``bool``. If True, the default, then domain
- names in the output will be relativized to the zone's origin
- if possible.
-
- *nl*, a ``str`` or None. The end of line string. If not
- ``None``, the output will use the platform's native
- end-of-line marker (i.e. LF on POSIX, CRLF on Windows).
-
- *want_comments*, a ``bool``. If ``True``, emit end-of-line comments
- as part of writing the file. If ``False``, the default, do not
- emit them.
-
- *want_origin*, a ``bool``. If ``True``, emit a $ORIGIN line at
- the start of the output. If ``False``, the default, do not emit
- one.
-
- Returns a ``str``.
- """
- temp_buffer = io.StringIO()
- self.to_file(temp_buffer, sorted, relativize, nl, want_comments, want_origin)
- return_value = temp_buffer.getvalue()
- temp_buffer.close()
- return return_value
-
- def check_origin(self) -> None:
- """Do some simple checking of the zone's origin.
-
- Raises ``dns.zone.NoSOA`` if there is no SOA RRset.
-
- Raises ``dns.zone.NoNS`` if there is no NS RRset.
-
- Raises ``KeyError`` if there is no origin node.
- """
- if self.relativize:
- name = dns.name.empty
- else:
- assert self.origin is not None
- name = self.origin
- if self.get_rdataset(name, dns.rdatatype.SOA) is None:
- raise NoSOA
- if self.get_rdataset(name, dns.rdatatype.NS) is None:
- raise NoNS
-
- def get_soa(
- self, txn: Optional[dns.transaction.Transaction] = None
- ) -> dns.rdtypes.ANY.SOA.SOA:
- """Get the zone SOA rdata.
-
- Raises ``dns.zone.NoSOA`` if there is no SOA RRset.
-
- Returns a ``dns.rdtypes.ANY.SOA.SOA`` Rdata.
- """
- if self.relativize:
- origin_name = dns.name.empty
- else:
- if self.origin is None:
- # get_soa() has been called very early, and there must not be
- # an SOA if there is no origin.
- raise NoSOA
- origin_name = self.origin
- soa: Optional[dns.rdataset.Rdataset]
- if txn:
- soa = txn.get(origin_name, dns.rdatatype.SOA)
- else:
- soa = self.get_rdataset(origin_name, dns.rdatatype.SOA)
- if soa is None:
- raise NoSOA
- return soa[0]
-
- def _compute_digest(
- self,
- hash_algorithm: DigestHashAlgorithm,
- scheme: DigestScheme = DigestScheme.SIMPLE,
- ) -> bytes:
- hashinfo = _digest_hashers.get(hash_algorithm)
- if not hashinfo:
- raise UnsupportedDigestHashAlgorithm
- if scheme != DigestScheme.SIMPLE:
- raise UnsupportedDigestScheme
-
- if self.relativize:
- origin_name = dns.name.empty
- else:
- assert self.origin is not None
- origin_name = self.origin
- hasher = hashinfo()
- for name, node in sorted(self.items()):
- rrnamebuf = name.to_digestable(self.origin)
- for rdataset in sorted(node, key=lambda rds: (rds.rdtype, rds.covers)):
- if name == origin_name and dns.rdatatype.ZONEMD in (
- rdataset.rdtype,
- rdataset.covers,
- ):
- continue
- rrfixed = struct.pack(
- "!HHI", rdataset.rdtype, rdataset.rdclass, rdataset.ttl
- )
- rdatas = [rdata.to_digestable(self.origin) for rdata in rdataset]
- for rdata in sorted(rdatas):
- rrlen = struct.pack("!H", len(rdata))
- hasher.update(rrnamebuf + rrfixed + rrlen + rdata)
- return hasher.digest()
-
- def compute_digest(
- self,
- hash_algorithm: DigestHashAlgorithm,
- scheme: DigestScheme = DigestScheme.SIMPLE,
- ) -> dns.rdtypes.ANY.ZONEMD.ZONEMD:
- serial = self.get_soa().serial
- digest = self._compute_digest(hash_algorithm, scheme)
- return dns.rdtypes.ANY.ZONEMD.ZONEMD(
- self.rdclass, dns.rdatatype.ZONEMD, serial, scheme, hash_algorithm, digest
- )
-
- def verify_digest(
- self, zonemd: Optional[dns.rdtypes.ANY.ZONEMD.ZONEMD] = None
- ) -> None:
- digests: Union[dns.rdataset.Rdataset, List[dns.rdtypes.ANY.ZONEMD.ZONEMD]]
- if zonemd:
- digests = [zonemd]
- else:
- assert self.origin is not None
- rds = self.get_rdataset(self.origin, dns.rdatatype.ZONEMD)
- if rds is None:
- raise NoDigest
- digests = rds
- for digest in digests:
- try:
- computed = self._compute_digest(digest.hash_algorithm, digest.scheme)
- if computed == digest.digest:
- return
- except Exception:
- pass
- raise DigestVerificationFailure
-
- # TransactionManager methods
-
- def reader(self) -> "Transaction":
- return Transaction(self, False, Version(self, 1, self.nodes, self.origin))
-
- def writer(self, replacement: bool = False) -> "Transaction":
- txn = Transaction(self, replacement)
- txn._setup_version()
- return txn
-
- def origin_information(
- self,
- ) -> Tuple[Optional[dns.name.Name], bool, Optional[dns.name.Name]]:
- effective: Optional[dns.name.Name]
- if self.relativize:
- effective = dns.name.empty
- else:
- effective = self.origin
- return (self.origin, self.relativize, effective)
-
- def get_class(self):
- return self.rdclass
-
- # Transaction methods
-
- def _end_read(self, txn):
- pass
-
- def _end_write(self, txn):
- pass
-
- def _commit_version(self, _, version, origin):
- self.nodes = version.nodes
- if self.origin is None:
- self.origin = origin
-
- def _get_next_version_id(self):
- # Versions are ephemeral and all have id 1
- return 1
-
-
-# These classes used to be in dns.versioned, but have moved here so we can use
-# the copy-on-write transaction mechanism for both kinds of zones. In a
-# regular zone, the version only exists during the transaction, and the nodes
-# are regular dns.node.Nodes.
-
-# A node with a version id.
-
-
-class VersionedNode(dns.node.Node): # lgtm[py/missing-equals]
- __slots__ = ["id"]
-
- def __init__(self):
- super().__init__()
- # A proper id will get set by the Version
- self.id = 0
-
-
-@dns.immutable.immutable
-class ImmutableVersionedNode(VersionedNode):
- def __init__(self, node):
- super().__init__()
- self.id = node.id
- self.rdatasets = tuple(
- [dns.rdataset.ImmutableRdataset(rds) for rds in node.rdatasets]
- )
-
- def find_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> dns.rdataset.Rdataset:
- if create:
- raise TypeError("immutable")
- return super().find_rdataset(rdclass, rdtype, covers, False)
-
- def get_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- create: bool = False,
- ) -> Optional[dns.rdataset.Rdataset]:
- if create:
- raise TypeError("immutable")
- return super().get_rdataset(rdclass, rdtype, covers, False)
-
- def delete_rdataset(
- self,
- rdclass: dns.rdataclass.RdataClass,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType = dns.rdatatype.NONE,
- ) -> None:
- raise TypeError("immutable")
-
- def replace_rdataset(self, replacement: dns.rdataset.Rdataset) -> None:
- raise TypeError("immutable")
-
- def is_immutable(self) -> bool:
- return True
-
-
-class Version:
- def __init__(
- self,
- zone: Zone,
- id: int,
- nodes: Optional[MutableMapping[dns.name.Name, dns.node.Node]] = None,
- origin: Optional[dns.name.Name] = None,
- ):
- self.zone = zone
- self.id = id
- if nodes is not None:
- self.nodes = nodes
- else:
- self.nodes = zone.map_factory()
- self.origin = origin
-
- def _validate_name(self, name: dns.name.Name) -> dns.name.Name:
- return _validate_name(name, self.origin, self.zone.relativize)
-
- def get_node(self, name: dns.name.Name) -> Optional[dns.node.Node]:
- name = self._validate_name(name)
- return self.nodes.get(name)
-
- def get_rdataset(
- self,
- name: dns.name.Name,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType,
- ) -> Optional[dns.rdataset.Rdataset]:
- node = self.get_node(name)
- if node is None:
- return None
- return node.get_rdataset(self.zone.rdclass, rdtype, covers)
-
- def keys(self):
- return self.nodes.keys()
-
- def items(self):
- return self.nodes.items()
-
-
-class WritableVersion(Version):
- def __init__(self, zone: Zone, replacement: bool = False):
- # The zone._versions_lock must be held by our caller in a versioned
- # zone.
- id = zone._get_next_version_id()
- super().__init__(zone, id)
- if not replacement:
- # We copy the map, because that gives us a simple and thread-safe
- # way of doing versions, and we have a garbage collector to help
- # us. We only make new node objects if we actually change the
- # node.
- self.nodes.update(zone.nodes)
- # We have to copy the zone origin as it may be None in the first
- # version, and we don't want to mutate the zone until we commit.
- self.origin = zone.origin
- self.changed: Set[dns.name.Name] = set()
-
- def _maybe_cow(self, name: dns.name.Name) -> dns.node.Node:
- name = self._validate_name(name)
- node = self.nodes.get(name)
- if node is None or name not in self.changed:
- new_node = self.zone.node_factory()
- if hasattr(new_node, "id"):
- # We keep doing this for backwards compatibility, as earlier
- # code used new_node.id != self.id for the "do we need to CoW?"
- # test. Now we use the changed set as this works with both
- # regular zones and versioned zones.
- #
- # We ignore the mypy error as this is safe but it doesn't see it.
- new_node.id = self.id # type: ignore
- if node is not None:
- # moo! copy on write!
- new_node.rdatasets.extend(node.rdatasets)
- self.nodes[name] = new_node
- self.changed.add(name)
- return new_node
- else:
- return node
-
- def delete_node(self, name: dns.name.Name) -> None:
- name = self._validate_name(name)
- if name in self.nodes:
- del self.nodes[name]
- self.changed.add(name)
-
- def put_rdataset(
- self, name: dns.name.Name, rdataset: dns.rdataset.Rdataset
- ) -> None:
- node = self._maybe_cow(name)
- node.replace_rdataset(rdataset)
-
- def delete_rdataset(
- self,
- name: dns.name.Name,
- rdtype: dns.rdatatype.RdataType,
- covers: dns.rdatatype.RdataType,
- ) -> None:
- node = self._maybe_cow(name)
- node.delete_rdataset(self.zone.rdclass, rdtype, covers)
- if len(node) == 0:
- del self.nodes[name]
-
-
-@dns.immutable.immutable
-class ImmutableVersion(Version):
- def __init__(self, version: WritableVersion):
- # We tell super() that it's a replacement as we don't want it
- # to copy the nodes, as we're about to do that with an
- # immutable Dict.
- super().__init__(version.zone, True)
- # set the right id!
- self.id = version.id
- # keep the origin
- self.origin = version.origin
- # Make changed nodes immutable
- for name in version.changed:
- node = version.nodes.get(name)
- # it might not exist if we deleted it in the version
- if node:
- version.nodes[name] = ImmutableVersionedNode(node)
- # We're changing the type of the nodes dictionary here on purpose, so
- # we ignore the mypy error.
- self.nodes = dns.immutable.Dict(
- version.nodes, True, self.zone.map_factory
- ) # type: ignore
-
-
-class Transaction(dns.transaction.Transaction):
- def __init__(self, zone, replacement, version=None, make_immutable=False):
- read_only = version is not None
- super().__init__(zone, replacement, read_only)
- self.version = version
- self.make_immutable = make_immutable
-
- @property
- def zone(self):
- return self.manager
-
- def _setup_version(self):
- assert self.version is None
- factory = self.manager.writable_version_factory
- if factory is None:
- factory = WritableVersion
- self.version = factory(self.zone, self.replacement)
-
- def _get_rdataset(self, name, rdtype, covers):
- return self.version.get_rdataset(name, rdtype, covers)
-
- def _put_rdataset(self, name, rdataset):
- assert not self.read_only
- self.version.put_rdataset(name, rdataset)
-
- def _delete_name(self, name):
- assert not self.read_only
- self.version.delete_node(name)
-
- def _delete_rdataset(self, name, rdtype, covers):
- assert not self.read_only
- self.version.delete_rdataset(name, rdtype, covers)
-
- def _name_exists(self, name):
- return self.version.get_node(name) is not None
-
- def _changed(self):
- if self.read_only:
- return False
- else:
- return len(self.version.changed) > 0
-
- def _end_transaction(self, commit):
- if self.read_only:
- self.zone._end_read(self)
- elif commit and len(self.version.changed) > 0:
- if self.make_immutable:
- factory = self.manager.immutable_version_factory
- if factory is None:
- factory = ImmutableVersion
- version = factory(self.version)
- else:
- version = self.version
- self.zone._commit_version(self, version, self.version.origin)
- else:
- # rollback
- self.zone._end_write(self)
-
- def _set_origin(self, origin):
- if self.version.origin is None:
- self.version.origin = origin
-
- def _iterate_rdatasets(self):
- for name, node in self.version.items():
- for rdataset in node:
- yield (name, rdataset)
-
- def _iterate_names(self):
- return self.version.keys()
-
- def _get_node(self, name):
- return self.version.get_node(name)
-
- def _origin_information(self):
- (absolute, relativize, effective) = self.manager.origin_information()
- if absolute is None and self.version.origin is not None:
- # No origin has been committed yet, but we've learned one as part of
- # this txn. Use it.
- absolute = self.version.origin
- if relativize:
- effective = dns.name.empty
- else:
- effective = absolute
- return (absolute, relativize, effective)
-
-
-def _from_text(
- text: Any,
- origin: Optional[Union[dns.name.Name, str]] = None,
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- relativize: bool = True,
- zone_factory: Any = Zone,
- filename: Optional[str] = None,
- allow_include: bool = False,
- check_origin: bool = True,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- allow_directives: Union[bool, Iterable[str]] = True,
-) -> Zone:
- # See the comments for the public APIs from_text() and from_file() for
- # details.
-
- # 'text' can also be a file, but we don't publish that fact
- # since it's an implementation detail. The official file
- # interface is from_file().
-
- if filename is None:
- filename = ""
- zone = zone_factory(origin, rdclass, relativize=relativize)
- with zone.writer(True) as txn:
- tok = dns.tokenizer.Tokenizer(text, filename, idna_codec=idna_codec)
- reader = dns.zonefile.Reader(
- tok,
- rdclass,
- txn,
- allow_include=allow_include,
- allow_directives=allow_directives,
- )
- try:
- reader.read()
- except dns.zonefile.UnknownOrigin:
- # for backwards compatibility
- raise dns.zone.UnknownOrigin
- # Now that we're done reading, do some basic checking of the zone.
- if check_origin:
- zone.check_origin()
- return zone
-
-
-def from_text(
- text: str,
- origin: Optional[Union[dns.name.Name, str]] = None,
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- relativize: bool = True,
- zone_factory: Any = Zone,
- filename: Optional[str] = None,
- allow_include: bool = False,
- check_origin: bool = True,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- allow_directives: Union[bool, Iterable[str]] = True,
-) -> Zone:
- """Build a zone object from a zone file format string.
-
- *text*, a ``str``, the zone file format input.
-
- *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin
- of the zone; if not specified, the first ``$ORIGIN`` statement in the
- zone file will determine the origin of the zone.
-
- *rdclass*, a ``dns.rdataclass.RdataClass``, the zone's rdata class; the default is
- class IN.
-
- *relativize*, a ``bool``, determine's whether domain names are
- relativized to the zone's origin. The default is ``True``.
-
- *zone_factory*, the zone factory to use or ``None``. If ``None``, then
- ``dns.zone.Zone`` will be used. The value may be any class or callable
- that returns a subclass of ``dns.zone.Zone``.
-
- *filename*, a ``str`` or ``None``, the filename to emit when
- describing where an error occurred; the default is ``''``.
-
- *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE``
- directives are permitted. If ``False``, then encoutering a ``$INCLUDE``
- will raise a ``SyntaxError`` exception.
-
- *check_origin*, a ``bool``. If ``True``, the default, then sanity
- checks of the origin node will be made by calling the zone's
- ``check_origin()`` method.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default,
- then directives are permitted, and the *allow_include* parameter controls whether
- ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive
- processing is done and any directive-like text will be treated as a regular owner
- name. If a non-empty iterable, then only the listed directives (including the
- ``$``) are allowed.
-
- Raises ``dns.zone.NoSOA`` if there is no SOA RRset.
-
- Raises ``dns.zone.NoNS`` if there is no NS RRset.
-
- Raises ``KeyError`` if there is no origin node.
-
- Returns a subclass of ``dns.zone.Zone``.
- """
- return _from_text(
- text,
- origin,
- rdclass,
- relativize,
- zone_factory,
- filename,
- allow_include,
- check_origin,
- idna_codec,
- allow_directives,
- )
-
-
-def from_file(
- f: Any,
- origin: Optional[Union[dns.name.Name, str]] = None,
- rdclass: dns.rdataclass.RdataClass = dns.rdataclass.IN,
- relativize: bool = True,
- zone_factory: Any = Zone,
- filename: Optional[str] = None,
- allow_include: bool = True,
- check_origin: bool = True,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- allow_directives: Union[bool, Iterable[str]] = True,
-) -> Zone:
- """Read a zone file and build a zone object.
-
- *f*, a file or ``str``. If *f* is a string, it is treated
- as the name of a file to open.
-
- *origin*, a ``dns.name.Name``, a ``str``, or ``None``. The origin
- of the zone; if not specified, the first ``$ORIGIN`` statement in the
- zone file will determine the origin of the zone.
-
- *rdclass*, an ``int``, the zone's rdata class; the default is class IN.
-
- *relativize*, a ``bool``, determine's whether domain names are
- relativized to the zone's origin. The default is ``True``.
-
- *zone_factory*, the zone factory to use or ``None``. If ``None``, then
- ``dns.zone.Zone`` will be used. The value may be any class or callable
- that returns a subclass of ``dns.zone.Zone``.
-
- *filename*, a ``str`` or ``None``, the filename to emit when
- describing where an error occurred; the default is ``''``.
-
- *allow_include*, a ``bool``. If ``True``, the default, then ``$INCLUDE``
- directives are permitted. If ``False``, then encoutering a ``$INCLUDE``
- will raise a ``SyntaxError`` exception.
-
- *check_origin*, a ``bool``. If ``True``, the default, then sanity
- checks of the origin node will be made by calling the zone's
- ``check_origin()`` method.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used.
-
- *allow_directives*, a ``bool`` or an iterable of `str`. If ``True``, the default,
- then directives are permitted, and the *allow_include* parameter controls whether
- ``$INCLUDE`` is permitted. If ``False`` or an empty iterable, then no directive
- processing is done and any directive-like text will be treated as a regular owner
- name. If a non-empty iterable, then only the listed directives (including the
- ``$``) are allowed.
-
- Raises ``dns.zone.NoSOA`` if there is no SOA RRset.
-
- Raises ``dns.zone.NoNS`` if there is no NS RRset.
-
- Raises ``KeyError`` if there is no origin node.
-
- Returns a subclass of ``dns.zone.Zone``.
- """
-
- if isinstance(f, str):
- if filename is None:
- filename = f
- cm: contextlib.AbstractContextManager = open(f)
- else:
- cm = contextlib.nullcontext(f)
- with cm as f:
- return _from_text(
- f,
- origin,
- rdclass,
- relativize,
- zone_factory,
- filename,
- allow_include,
- check_origin,
- idna_codec,
- allow_directives,
- )
- assert False # make mypy happy lgtm[py/unreachable-statement]
-
-
-def from_xfr(
- xfr: Any,
- zone_factory: Any = Zone,
- relativize: bool = True,
- check_origin: bool = True,
-) -> Zone:
- """Convert the output of a zone transfer generator into a zone object.
-
- *xfr*, a generator of ``dns.message.Message`` objects, typically
- ``dns.query.xfr()``.
-
- *relativize*, a ``bool``, determine's whether domain names are
- relativized to the zone's origin. The default is ``True``.
- It is essential that the relativize setting matches the one specified
- to the generator.
-
- *check_origin*, a ``bool``. If ``True``, the default, then sanity
- checks of the origin node will be made by calling the zone's
- ``check_origin()`` method.
-
- Raises ``dns.zone.NoSOA`` if there is no SOA RRset.
-
- Raises ``dns.zone.NoNS`` if there is no NS RRset.
-
- Raises ``KeyError`` if there is no origin node.
-
- Raises ``ValueError`` if no messages are yielded by the generator.
-
- Returns a subclass of ``dns.zone.Zone``.
- """
-
- z = None
- for r in xfr:
- if z is None:
- if relativize:
- origin = r.origin
- else:
- origin = r.answer[0].name
- rdclass = r.answer[0].rdclass
- z = zone_factory(origin, rdclass, relativize=relativize)
- for rrset in r.answer:
- znode = z.nodes.get(rrset.name)
- if not znode:
- znode = z.node_factory()
- z.nodes[rrset.name] = znode
- zrds = znode.find_rdataset(rrset.rdclass, rrset.rdtype, rrset.covers, True)
- zrds.update_ttl(rrset.ttl)
- for rd in rrset:
- zrds.add(rd)
- if z is None:
- raise ValueError("empty transfer")
- if check_origin:
- z.check_origin()
- return z
diff --git a/.venv/lib/python3.12/site-packages/dns/zonefile.py b/.venv/lib/python3.12/site-packages/dns/zonefile.py
deleted file mode 100644
index af064e7..0000000
--- a/.venv/lib/python3.12/site-packages/dns/zonefile.py
+++ /dev/null
@@ -1,746 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-# Copyright (C) 2003-2007, 2009-2011 Nominum, Inc.
-#
-# Permission to use, copy, modify, and distribute this software and its
-# documentation for any purpose with or without fee is hereby granted,
-# provided that the above copyright notice and this permission notice
-# appear in all copies.
-#
-# THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-# OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
-
-"""DNS Zones."""
-
-import re
-import sys
-from typing import Any, Iterable, List, Optional, Set, Tuple, Union
-
-import dns.exception
-import dns.grange
-import dns.name
-import dns.node
-import dns.rdata
-import dns.rdataclass
-import dns.rdatatype
-import dns.rdtypes.ANY.SOA
-import dns.rrset
-import dns.tokenizer
-import dns.transaction
-import dns.ttl
-
-
-class UnknownOrigin(dns.exception.DNSException):
- """Unknown origin"""
-
-
-class CNAMEAndOtherData(dns.exception.DNSException):
- """A node has a CNAME and other data"""
-
-
-def _check_cname_and_other_data(txn, name, rdataset):
- rdataset_kind = dns.node.NodeKind.classify_rdataset(rdataset)
- node = txn.get_node(name)
- if node is None:
- # empty nodes are neutral.
- return
- node_kind = node.classify()
- if (
- node_kind == dns.node.NodeKind.CNAME
- and rdataset_kind == dns.node.NodeKind.REGULAR
- ):
- raise CNAMEAndOtherData("rdataset type is not compatible with a CNAME node")
- elif (
- node_kind == dns.node.NodeKind.REGULAR
- and rdataset_kind == dns.node.NodeKind.CNAME
- ):
- raise CNAMEAndOtherData(
- "CNAME rdataset is not compatible with a regular data node"
- )
- # Otherwise at least one of the node and the rdataset is neutral, so
- # adding the rdataset is ok
-
-
-SavedStateType = Tuple[
- dns.tokenizer.Tokenizer,
- Optional[dns.name.Name], # current_origin
- Optional[dns.name.Name], # last_name
- Optional[Any], # current_file
- int, # last_ttl
- bool, # last_ttl_known
- int, # default_ttl
- bool,
-] # default_ttl_known
-
-
-def _upper_dollarize(s):
- s = s.upper()
- if not s.startswith("$"):
- s = "$" + s
- return s
-
-
-class Reader:
- """Read a DNS zone file into a transaction."""
-
- def __init__(
- self,
- tok: dns.tokenizer.Tokenizer,
- rdclass: dns.rdataclass.RdataClass,
- txn: dns.transaction.Transaction,
- allow_include: bool = False,
- allow_directives: Union[bool, Iterable[str]] = True,
- force_name: Optional[dns.name.Name] = None,
- force_ttl: Optional[int] = None,
- force_rdclass: Optional[dns.rdataclass.RdataClass] = None,
- force_rdtype: Optional[dns.rdatatype.RdataType] = None,
- default_ttl: Optional[int] = None,
- ):
- self.tok = tok
- (self.zone_origin, self.relativize, _) = txn.manager.origin_information()
- self.current_origin = self.zone_origin
- self.last_ttl = 0
- self.last_ttl_known = False
- if force_ttl is not None:
- default_ttl = force_ttl
- if default_ttl is None:
- self.default_ttl = 0
- self.default_ttl_known = False
- else:
- self.default_ttl = default_ttl
- self.default_ttl_known = True
- self.last_name = self.current_origin
- self.zone_rdclass = rdclass
- self.txn = txn
- self.saved_state: List[SavedStateType] = []
- self.current_file: Optional[Any] = None
- self.allowed_directives: Set[str]
- if allow_directives is True:
- self.allowed_directives = {"$GENERATE", "$ORIGIN", "$TTL"}
- if allow_include:
- self.allowed_directives.add("$INCLUDE")
- elif allow_directives is False:
- # allow_include was ignored in earlier releases if allow_directives was
- # False, so we continue that.
- self.allowed_directives = set()
- else:
- # Note that if directives are explicitly specified, then allow_include
- # is ignored.
- self.allowed_directives = set(_upper_dollarize(d) for d in allow_directives)
- self.force_name = force_name
- self.force_ttl = force_ttl
- self.force_rdclass = force_rdclass
- self.force_rdtype = force_rdtype
- self.txn.check_put_rdataset(_check_cname_and_other_data)
-
- def _eat_line(self):
- while 1:
- token = self.tok.get()
- if token.is_eol_or_eof():
- break
-
- def _get_identifier(self):
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- return token
-
- def _rr_line(self):
- """Process one line from a DNS zone file."""
- token = None
- # Name
- if self.force_name is not None:
- name = self.force_name
- else:
- if self.current_origin is None:
- raise UnknownOrigin
- token = self.tok.get(want_leading=True)
- if not token.is_whitespace():
- self.last_name = self.tok.as_name(token, self.current_origin)
- else:
- token = self.tok.get()
- if token.is_eol_or_eof():
- # treat leading WS followed by EOL/EOF as if they were EOL/EOF.
- return
- self.tok.unget(token)
- name = self.last_name
- if not name.is_subdomain(self.zone_origin):
- self._eat_line()
- return
- if self.relativize:
- name = name.relativize(self.zone_origin)
-
- # TTL
- if self.force_ttl is not None:
- ttl = self.force_ttl
- self.last_ttl = ttl
- self.last_ttl_known = True
- else:
- token = self._get_identifier()
- ttl = None
- try:
- ttl = dns.ttl.from_text(token.value)
- self.last_ttl = ttl
- self.last_ttl_known = True
- token = None
- except dns.ttl.BadTTL:
- self.tok.unget(token)
-
- # Class
- if self.force_rdclass is not None:
- rdclass = self.force_rdclass
- else:
- token = self._get_identifier()
- try:
- rdclass = dns.rdataclass.from_text(token.value)
- except dns.exception.SyntaxError:
- raise
- except Exception:
- rdclass = self.zone_rdclass
- self.tok.unget(token)
- if rdclass != self.zone_rdclass:
- raise dns.exception.SyntaxError("RR class is not zone's class")
-
- if ttl is None:
- # support for syntax
- token = self._get_identifier()
- ttl = None
- try:
- ttl = dns.ttl.from_text(token.value)
- self.last_ttl = ttl
- self.last_ttl_known = True
- token = None
- except dns.ttl.BadTTL:
- if self.default_ttl_known:
- ttl = self.default_ttl
- elif self.last_ttl_known:
- ttl = self.last_ttl
- self.tok.unget(token)
-
- # Type
- if self.force_rdtype is not None:
- rdtype = self.force_rdtype
- else:
- token = self._get_identifier()
- try:
- rdtype = dns.rdatatype.from_text(token.value)
- except Exception:
- raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value)
-
- try:
- rd = dns.rdata.from_text(
- rdclass,
- rdtype,
- self.tok,
- self.current_origin,
- self.relativize,
- self.zone_origin,
- )
- except dns.exception.SyntaxError:
- # Catch and reraise.
- raise
- except Exception:
- # All exceptions that occur in the processing of rdata
- # are treated as syntax errors. This is not strictly
- # correct, but it is correct almost all of the time.
- # We convert them to syntax errors so that we can emit
- # helpful filename:line info.
- (ty, va) = sys.exc_info()[:2]
- raise dns.exception.SyntaxError(
- "caught exception {}: {}".format(str(ty), str(va))
- )
-
- if not self.default_ttl_known and rdtype == dns.rdatatype.SOA:
- # The pre-RFC2308 and pre-BIND9 behavior inherits the zone default
- # TTL from the SOA minttl if no $TTL statement is present before the
- # SOA is parsed.
- self.default_ttl = rd.minimum
- self.default_ttl_known = True
- if ttl is None:
- # if we didn't have a TTL on the SOA, set it!
- ttl = rd.minimum
-
- # TTL check. We had to wait until now to do this as the SOA RR's
- # own TTL can be inferred from its minimum.
- if ttl is None:
- raise dns.exception.SyntaxError("Missing default TTL value")
-
- self.txn.add(name, ttl, rd)
-
- def _parse_modify(self, side: str) -> Tuple[str, str, int, int, str]:
- # Here we catch everything in '{' '}' in a group so we can replace it
- # with ''.
- is_generate1 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+),(.)}).*$")
- is_generate2 = re.compile(r"^.*\$({(\+|-?)(\d+)}).*$")
- is_generate3 = re.compile(r"^.*\$({(\+|-?)(\d+),(\d+)}).*$")
- # Sometimes there are modifiers in the hostname. These come after
- # the dollar sign. They are in the form: ${offset[,width[,base]]}.
- # Make names
- g1 = is_generate1.match(side)
- if g1:
- mod, sign, offset, width, base = g1.groups()
- if sign == "":
- sign = "+"
- g2 = is_generate2.match(side)
- if g2:
- mod, sign, offset = g2.groups()
- if sign == "":
- sign = "+"
- width = 0
- base = "d"
- g3 = is_generate3.match(side)
- if g3:
- mod, sign, offset, width = g3.groups()
- if sign == "":
- sign = "+"
- base = "d"
-
- if not (g1 or g2 or g3):
- mod = ""
- sign = "+"
- offset = 0
- width = 0
- base = "d"
-
- offset = int(offset)
- width = int(width)
-
- if sign not in ["+", "-"]:
- raise dns.exception.SyntaxError("invalid offset sign %s" % sign)
- if base not in ["d", "o", "x", "X", "n", "N"]:
- raise dns.exception.SyntaxError("invalid type %s" % base)
-
- return mod, sign, offset, width, base
-
- def _generate_line(self):
- # range lhs [ttl] [class] type rhs [ comment ]
- """Process one line containing the GENERATE statement from a DNS
- zone file."""
- if self.current_origin is None:
- raise UnknownOrigin
-
- token = self.tok.get()
- # Range (required)
- try:
- start, stop, step = dns.grange.from_text(token.value)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except Exception:
- raise dns.exception.SyntaxError
-
- # lhs (required)
- try:
- lhs = token.value
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except Exception:
- raise dns.exception.SyntaxError
-
- # TTL
- try:
- ttl = dns.ttl.from_text(token.value)
- self.last_ttl = ttl
- self.last_ttl_known = True
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except dns.ttl.BadTTL:
- if not (self.last_ttl_known or self.default_ttl_known):
- raise dns.exception.SyntaxError("Missing default TTL value")
- if self.default_ttl_known:
- ttl = self.default_ttl
- elif self.last_ttl_known:
- ttl = self.last_ttl
- # Class
- try:
- rdclass = dns.rdataclass.from_text(token.value)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except dns.exception.SyntaxError:
- raise dns.exception.SyntaxError
- except Exception:
- rdclass = self.zone_rdclass
- if rdclass != self.zone_rdclass:
- raise dns.exception.SyntaxError("RR class is not zone's class")
- # Type
- try:
- rdtype = dns.rdatatype.from_text(token.value)
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError
- except Exception:
- raise dns.exception.SyntaxError("unknown rdatatype '%s'" % token.value)
-
- # rhs (required)
- rhs = token.value
-
- def _calculate_index(counter: int, offset_sign: str, offset: int) -> int:
- """Calculate the index from the counter and offset."""
- if offset_sign == "-":
- offset *= -1
- return counter + offset
-
- def _format_index(index: int, base: str, width: int) -> str:
- """Format the index with the given base, and zero-fill it
- to the given width."""
- if base in ["d", "o", "x", "X"]:
- return format(index, base).zfill(width)
-
- # base can only be n or N here
- hexa = _format_index(index, "x", width)
- nibbles = ".".join(hexa[::-1])[:width]
- if base == "N":
- nibbles = nibbles.upper()
- return nibbles
-
- lmod, lsign, loffset, lwidth, lbase = self._parse_modify(lhs)
- rmod, rsign, roffset, rwidth, rbase = self._parse_modify(rhs)
- for i in range(start, stop + 1, step):
- # +1 because bind is inclusive and python is exclusive
-
- lindex = _calculate_index(i, lsign, loffset)
- rindex = _calculate_index(i, rsign, roffset)
-
- lzfindex = _format_index(lindex, lbase, lwidth)
- rzfindex = _format_index(rindex, rbase, rwidth)
-
- name = lhs.replace("$%s" % (lmod), lzfindex)
- rdata = rhs.replace("$%s" % (rmod), rzfindex)
-
- self.last_name = dns.name.from_text(
- name, self.current_origin, self.tok.idna_codec
- )
- name = self.last_name
- if not name.is_subdomain(self.zone_origin):
- self._eat_line()
- return
- if self.relativize:
- name = name.relativize(self.zone_origin)
-
- try:
- rd = dns.rdata.from_text(
- rdclass,
- rdtype,
- rdata,
- self.current_origin,
- self.relativize,
- self.zone_origin,
- )
- except dns.exception.SyntaxError:
- # Catch and reraise.
- raise
- except Exception:
- # All exceptions that occur in the processing of rdata
- # are treated as syntax errors. This is not strictly
- # correct, but it is correct almost all of the time.
- # We convert them to syntax errors so that we can emit
- # helpful filename:line info.
- (ty, va) = sys.exc_info()[:2]
- raise dns.exception.SyntaxError(
- "caught exception %s: %s" % (str(ty), str(va))
- )
-
- self.txn.add(name, ttl, rd)
-
- def read(self) -> None:
- """Read a DNS zone file and build a zone object.
-
- @raises dns.zone.NoSOA: No SOA RR was found at the zone origin
- @raises dns.zone.NoNS: No NS RRset was found at the zone origin
- """
-
- try:
- while 1:
- token = self.tok.get(True, True)
- if token.is_eof():
- if self.current_file is not None:
- self.current_file.close()
- if len(self.saved_state) > 0:
- (
- self.tok,
- self.current_origin,
- self.last_name,
- self.current_file,
- self.last_ttl,
- self.last_ttl_known,
- self.default_ttl,
- self.default_ttl_known,
- ) = self.saved_state.pop(-1)
- continue
- break
- elif token.is_eol():
- continue
- elif token.is_comment():
- self.tok.get_eol()
- continue
- elif token.value[0] == "$" and len(self.allowed_directives) > 0:
- # Note that we only run directive processing code if at least
- # one directive is allowed in order to be backwards compatible
- c = token.value.upper()
- if c not in self.allowed_directives:
- raise dns.exception.SyntaxError(
- f"zone file directive '{c}' is not allowed"
- )
- if c == "$TTL":
- token = self.tok.get()
- if not token.is_identifier():
- raise dns.exception.SyntaxError("bad $TTL")
- self.default_ttl = dns.ttl.from_text(token.value)
- self.default_ttl_known = True
- self.tok.get_eol()
- elif c == "$ORIGIN":
- self.current_origin = self.tok.get_name()
- self.tok.get_eol()
- if self.zone_origin is None:
- self.zone_origin = self.current_origin
- self.txn._set_origin(self.current_origin)
- elif c == "$INCLUDE":
- token = self.tok.get()
- filename = token.value
- token = self.tok.get()
- new_origin: Optional[dns.name.Name]
- if token.is_identifier():
- new_origin = dns.name.from_text(
- token.value, self.current_origin, self.tok.idna_codec
- )
- self.tok.get_eol()
- elif not token.is_eol_or_eof():
- raise dns.exception.SyntaxError("bad origin in $INCLUDE")
- else:
- new_origin = self.current_origin
- self.saved_state.append(
- (
- self.tok,
- self.current_origin,
- self.last_name,
- self.current_file,
- self.last_ttl,
- self.last_ttl_known,
- self.default_ttl,
- self.default_ttl_known,
- )
- )
- self.current_file = open(filename, "r")
- self.tok = dns.tokenizer.Tokenizer(self.current_file, filename)
- self.current_origin = new_origin
- elif c == "$GENERATE":
- self._generate_line()
- else:
- raise dns.exception.SyntaxError(
- f"Unknown zone file directive '{c}'"
- )
- continue
- self.tok.unget(token)
- self._rr_line()
- except dns.exception.SyntaxError as detail:
- (filename, line_number) = self.tok.where()
- if detail is None:
- detail = "syntax error"
- ex = dns.exception.SyntaxError(
- "%s:%d: %s" % (filename, line_number, detail)
- )
- tb = sys.exc_info()[2]
- raise ex.with_traceback(tb) from None
-
-
-class RRsetsReaderTransaction(dns.transaction.Transaction):
- def __init__(self, manager, replacement, read_only):
- assert not read_only
- super().__init__(manager, replacement, read_only)
- self.rdatasets = {}
-
- def _get_rdataset(self, name, rdtype, covers):
- return self.rdatasets.get((name, rdtype, covers))
-
- def _get_node(self, name):
- rdatasets = []
- for (rdataset_name, _, _), rdataset in self.rdatasets.items():
- if name == rdataset_name:
- rdatasets.append(rdataset)
- if len(rdatasets) == 0:
- return None
- node = dns.node.Node()
- node.rdatasets = rdatasets
- return node
-
- def _put_rdataset(self, name, rdataset):
- self.rdatasets[(name, rdataset.rdtype, rdataset.covers)] = rdataset
-
- def _delete_name(self, name):
- # First remove any changes involving the name
- remove = []
- for key in self.rdatasets:
- if key[0] == name:
- remove.append(key)
- if len(remove) > 0:
- for key in remove:
- del self.rdatasets[key]
-
- def _delete_rdataset(self, name, rdtype, covers):
- try:
- del self.rdatasets[(name, rdtype, covers)]
- except KeyError:
- pass
-
- def _name_exists(self, name):
- for n, _, _ in self.rdatasets:
- if n == name:
- return True
- return False
-
- def _changed(self):
- return len(self.rdatasets) > 0
-
- def _end_transaction(self, commit):
- if commit and self._changed():
- rrsets = []
- for (name, _, _), rdataset in self.rdatasets.items():
- rrset = dns.rrset.RRset(
- name, rdataset.rdclass, rdataset.rdtype, rdataset.covers
- )
- rrset.update(rdataset)
- rrsets.append(rrset)
- self.manager.set_rrsets(rrsets)
-
- def _set_origin(self, origin):
- pass
-
- def _iterate_rdatasets(self):
- raise NotImplementedError # pragma: no cover
-
- def _iterate_names(self):
- raise NotImplementedError # pragma: no cover
-
-
-class RRSetsReaderManager(dns.transaction.TransactionManager):
- def __init__(
- self, origin=dns.name.root, relativize=False, rdclass=dns.rdataclass.IN
- ):
- self.origin = origin
- self.relativize = relativize
- self.rdclass = rdclass
- self.rrsets = []
-
- def reader(self): # pragma: no cover
- raise NotImplementedError
-
- def writer(self, replacement=False):
- assert replacement is True
- return RRsetsReaderTransaction(self, True, False)
-
- def get_class(self):
- return self.rdclass
-
- def origin_information(self):
- if self.relativize:
- effective = dns.name.empty
- else:
- effective = self.origin
- return (self.origin, self.relativize, effective)
-
- def set_rrsets(self, rrsets):
- self.rrsets = rrsets
-
-
-def read_rrsets(
- text: Any,
- name: Optional[Union[dns.name.Name, str]] = None,
- ttl: Optional[int] = None,
- rdclass: Optional[Union[dns.rdataclass.RdataClass, str]] = dns.rdataclass.IN,
- default_rdclass: Union[dns.rdataclass.RdataClass, str] = dns.rdataclass.IN,
- rdtype: Optional[Union[dns.rdatatype.RdataType, str]] = None,
- default_ttl: Optional[Union[int, str]] = None,
- idna_codec: Optional[dns.name.IDNACodec] = None,
- origin: Optional[Union[dns.name.Name, str]] = dns.name.root,
- relativize: bool = False,
-) -> List[dns.rrset.RRset]:
- """Read one or more rrsets from the specified text, possibly subject
- to restrictions.
-
- *text*, a file object or a string, is the input to process.
-
- *name*, a string, ``dns.name.Name``, or ``None``, is the owner name of
- the rrset. If not ``None``, then the owner name is "forced", and the
- input must not specify an owner name. If ``None``, then any owner names
- are allowed and must be present in the input.
-
- *ttl*, an ``int``, string, or None. If not ``None``, the the TTL is
- forced to be the specified value and the input must not specify a TTL.
- If ``None``, then a TTL may be specified in the input. If it is not
- specified, then the *default_ttl* will be used.
-
- *rdclass*, a ``dns.rdataclass.RdataClass``, string, or ``None``. If
- not ``None``, then the class is forced to the specified value, and the
- input must not specify a class. If ``None``, then the input may specify
- a class that matches *default_rdclass*. Note that it is not possible to
- return rrsets with differing classes; specifying ``None`` for the class
- simply allows the user to optionally type a class as that may be convenient
- when cutting and pasting.
-
- *default_rdclass*, a ``dns.rdataclass.RdataClass`` or string. The class
- of the returned rrsets.
-
- *rdtype*, a ``dns.rdatatype.RdataType``, string, or ``None``. If not
- ``None``, then the type is forced to the specified value, and the
- input must not specify a type. If ``None``, then a type must be present
- for each RR.
-
- *default_ttl*, an ``int``, string, or ``None``. If not ``None``, then if
- the TTL is not forced and is not specified, then this value will be used.
- if ``None``, then if the TTL is not forced an error will occur if the TTL
- is not specified.
-
- *idna_codec*, a ``dns.name.IDNACodec``, specifies the IDNA
- encoder/decoder. If ``None``, the default IDNA 2003 encoder/decoder
- is used. Note that codecs only apply to the owner name; dnspython does
- not do IDNA for names in rdata, as there is no IDNA zonefile format.
-
- *origin*, a string, ``dns.name.Name``, or ``None``, is the origin for any
- relative names in the input, and also the origin to relativize to if
- *relativize* is ``True``.
-
- *relativize*, a bool. If ``True``, names are relativized to the *origin*;
- if ``False`` then any relative names in the input are made absolute by
- appending the *origin*.
- """
- if isinstance(origin, str):
- origin = dns.name.from_text(origin, dns.name.root, idna_codec)
- if isinstance(name, str):
- name = dns.name.from_text(name, origin, idna_codec)
- if isinstance(ttl, str):
- ttl = dns.ttl.from_text(ttl)
- if isinstance(default_ttl, str):
- default_ttl = dns.ttl.from_text(default_ttl)
- if rdclass is not None:
- rdclass = dns.rdataclass.RdataClass.make(rdclass)
- else:
- rdclass = None
- default_rdclass = dns.rdataclass.RdataClass.make(default_rdclass)
- if rdtype is not None:
- rdtype = dns.rdatatype.RdataType.make(rdtype)
- else:
- rdtype = None
- manager = RRSetsReaderManager(origin, relativize, default_rdclass)
- with manager.writer(True) as txn:
- tok = dns.tokenizer.Tokenizer(text, " ", idna_codec=idna_codec)
- reader = Reader(
- tok,
- default_rdclass,
- txn,
- allow_directives=False,
- force_name=name,
- force_ttl=ttl,
- force_rdclass=rdclass,
- force_rdtype=rdtype,
- default_ttl=default_ttl,
- )
- reader.read()
- return manager.rrsets
diff --git a/.venv/lib/python3.12/site-packages/dns/zonetypes.py b/.venv/lib/python3.12/site-packages/dns/zonetypes.py
deleted file mode 100644
index 195ee2e..0000000
--- a/.venv/lib/python3.12/site-packages/dns/zonetypes.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright (C) Dnspython Contributors, see LICENSE for text of ISC license
-
-"""Common zone-related types."""
-
-# This is a separate file to avoid import circularity between dns.zone and
-# the implementation of the ZONEMD type.
-
-import hashlib
-
-import dns.enum
-
-
-class DigestScheme(dns.enum.IntEnum):
- """ZONEMD Scheme"""
-
- SIMPLE = 1
-
- @classmethod
- def _maximum(cls):
- return 255
-
-
-class DigestHashAlgorithm(dns.enum.IntEnum):
- """ZONEMD Hash Algorithm"""
-
- SHA384 = 1
- SHA512 = 2
-
- @classmethod
- def _maximum(cls):
- return 255
-
-
-_digest_hashers = {
- DigestHashAlgorithm.SHA384: hashlib.sha384,
- DigestHashAlgorithm.SHA512: hashlib.sha512,
-}
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/METADATA b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/METADATA
deleted file mode 100644
index 129184e..0000000
--- a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/METADATA
+++ /dev/null
@@ -1,147 +0,0 @@
-Metadata-Version: 2.1
-Name: dnspython
-Version: 2.6.1
-Summary: DNS toolkit
-Project-URL: homepage, https://www.dnspython.org
-Project-URL: repository, https://github.com/rthalley/dnspython.git
-Project-URL: documentation, https://dnspython.readthedocs.io/en/stable/
-Project-URL: issues, https://github.com/rthalley/dnspython/issues
-Author-email: Bob Halley
-License-Expression: ISC
-License-File: LICENSE
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: System Administrators
-Classifier: License :: OSI Approved :: ISC License (ISCL)
-Classifier: Operating System :: Microsoft :: Windows
-Classifier: Operating System :: POSIX
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Topic :: Internet :: Name Service (DNS)
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Requires-Python: >=3.8
-Provides-Extra: dev
-Requires-Dist: black>=23.1.0; extra == 'dev'
-Requires-Dist: coverage>=7.0; extra == 'dev'
-Requires-Dist: flake8>=7; extra == 'dev'
-Requires-Dist: mypy>=1.8; extra == 'dev'
-Requires-Dist: pylint>=3; extra == 'dev'
-Requires-Dist: pytest-cov>=4.1.0; extra == 'dev'
-Requires-Dist: pytest>=7.4; extra == 'dev'
-Requires-Dist: sphinx>=7.2.0; extra == 'dev'
-Requires-Dist: twine>=4.0.0; extra == 'dev'
-Requires-Dist: wheel>=0.42.0; extra == 'dev'
-Provides-Extra: dnssec
-Requires-Dist: cryptography>=41; extra == 'dnssec'
-Provides-Extra: doh
-Requires-Dist: h2>=4.1.0; extra == 'doh'
-Requires-Dist: httpcore>=1.0.0; extra == 'doh'
-Requires-Dist: httpx>=0.26.0; extra == 'doh'
-Provides-Extra: doq
-Requires-Dist: aioquic>=0.9.25; extra == 'doq'
-Provides-Extra: idna
-Requires-Dist: idna>=3.6; extra == 'idna'
-Provides-Extra: trio
-Requires-Dist: trio>=0.23; extra == 'trio'
-Provides-Extra: wmi
-Requires-Dist: wmi>=1.5.1; extra == 'wmi'
-Description-Content-Type: text/markdown
-
-# dnspython
-
-[](https://github.com/rthalley/dnspython/actions/)
-[](https://dnspython.readthedocs.io/en/latest/?badge=latest)
-[](https://badge.fury.io/py/dnspython)
-[](https://opensource.org/licenses/ISC)
-[](https://codecov.io/github/rthalley/dnspython)
-[](https://github.com/psf/black)
-
-## INTRODUCTION
-
-dnspython is a DNS toolkit for Python. It supports almost all record types. It
-can be used for queries, zone transfers, and dynamic updates. It supports TSIG
-authenticated messages and EDNS0.
-
-dnspython provides both high and low level access to DNS. The high level classes
-perform queries for data of a given name, type, and class, and return an answer
-set. The low level classes allow direct manipulation of DNS zones, messages,
-names, and records.
-
-To see a few of the ways dnspython can be used, look in the `examples/`
-directory.
-
-dnspython is a utility to work with DNS, `/etc/hosts` is thus not used. For
-simple forward DNS lookups, it's better to use `socket.getaddrinfo()` or
-`socket.gethostbyname()`.
-
-dnspython originated at Nominum where it was developed
-to facilitate the testing of DNS software.
-
-## ABOUT THIS RELEASE
-
-This is dnspython 2.6.1.
-Please read
-[What's New](https://dnspython.readthedocs.io/en/stable/whatsnew.html) for
-information about the changes in this release.
-
-## INSTALLATION
-
-* Many distributions have dnspython packaged for you, so you should
- check there first.
-* To use a wheel downloaded from PyPi, run:
-
- pip install dnspython
-
-* To install from the source code, go into the top-level of the source code
- and run:
-
-```
- pip install --upgrade pip build
- python -m build
- pip install dist/*.whl
-```
-
-* To install the latest from the master branch, run `pip install git+https://github.com/rthalley/dnspython.git`
-
-Dnspython's default installation does not depend on any modules other than
-those in the Python standard library. To use some features, additional modules
-must be installed. For convenience, pip options are defined for the
-requirements.
-
-If you want to use DNS-over-HTTPS, run
-`pip install dnspython[doh]`.
-
-If you want to use DNSSEC functionality, run
-`pip install dnspython[dnssec]`.
-
-If you want to use internationalized domain names (IDNA)
-functionality, you must run
-`pip install dnspython[idna]`
-
-If you want to use the Trio asynchronous I/O package, run
-`pip install dnspython[trio]`.
-
-If you want to use WMI on Windows to determine the active DNS settings
-instead of the default registry scanning method, run
-`pip install dnspython[wmi]`.
-
-If you want to try the experimental DNS-over-QUIC code, run
-`pip install dnspython[doq]`.
-
-Note that you can install any combination of the above, e.g.:
-`pip install dnspython[doh,dnssec,idna]`
-
-### Notices
-
-Python 2.x support ended with the release of 1.16.0. Dnspython 2.0.0 through
-2.2.x support Python 3.6 and later. For dnspython 2.3.x, the minimum
-supported Python version is 3.7, and for 2.4.x the minimum supported verison is 3.8.
-We plan to align future support with the lifetime of the Python 3 versions.
-
-Documentation has moved to
-[dnspython.readthedocs.io](https://dnspython.readthedocs.io).
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/RECORD b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/RECORD
deleted file mode 100644
index ec1dbb9..0000000
--- a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/RECORD
+++ /dev/null
@@ -1,291 +0,0 @@
-dns/__init__.py,sha256=YJZtDG14Idw5ui3h1nWooSwPM9gsxQgB8M0GBZ3aly0,1663
-dns/__pycache__/__init__.cpython-312.pyc,,
-dns/__pycache__/_asyncbackend.cpython-312.pyc,,
-dns/__pycache__/_asyncio_backend.cpython-312.pyc,,
-dns/__pycache__/_ddr.cpython-312.pyc,,
-dns/__pycache__/_features.cpython-312.pyc,,
-dns/__pycache__/_immutable_ctx.cpython-312.pyc,,
-dns/__pycache__/_trio_backend.cpython-312.pyc,,
-dns/__pycache__/asyncbackend.cpython-312.pyc,,
-dns/__pycache__/asyncquery.cpython-312.pyc,,
-dns/__pycache__/asyncresolver.cpython-312.pyc,,
-dns/__pycache__/dnssec.cpython-312.pyc,,
-dns/__pycache__/dnssectypes.cpython-312.pyc,,
-dns/__pycache__/e164.cpython-312.pyc,,
-dns/__pycache__/edns.cpython-312.pyc,,
-dns/__pycache__/entropy.cpython-312.pyc,,
-dns/__pycache__/enum.cpython-312.pyc,,
-dns/__pycache__/exception.cpython-312.pyc,,
-dns/__pycache__/flags.cpython-312.pyc,,
-dns/__pycache__/grange.cpython-312.pyc,,
-dns/__pycache__/immutable.cpython-312.pyc,,
-dns/__pycache__/inet.cpython-312.pyc,,
-dns/__pycache__/ipv4.cpython-312.pyc,,
-dns/__pycache__/ipv6.cpython-312.pyc,,
-dns/__pycache__/message.cpython-312.pyc,,
-dns/__pycache__/name.cpython-312.pyc,,
-dns/__pycache__/namedict.cpython-312.pyc,,
-dns/__pycache__/nameserver.cpython-312.pyc,,
-dns/__pycache__/node.cpython-312.pyc,,
-dns/__pycache__/opcode.cpython-312.pyc,,
-dns/__pycache__/query.cpython-312.pyc,,
-dns/__pycache__/rcode.cpython-312.pyc,,
-dns/__pycache__/rdata.cpython-312.pyc,,
-dns/__pycache__/rdataclass.cpython-312.pyc,,
-dns/__pycache__/rdataset.cpython-312.pyc,,
-dns/__pycache__/rdatatype.cpython-312.pyc,,
-dns/__pycache__/renderer.cpython-312.pyc,,
-dns/__pycache__/resolver.cpython-312.pyc,,
-dns/__pycache__/reversename.cpython-312.pyc,,
-dns/__pycache__/rrset.cpython-312.pyc,,
-dns/__pycache__/serial.cpython-312.pyc,,
-dns/__pycache__/set.cpython-312.pyc,,
-dns/__pycache__/tokenizer.cpython-312.pyc,,
-dns/__pycache__/transaction.cpython-312.pyc,,
-dns/__pycache__/tsig.cpython-312.pyc,,
-dns/__pycache__/tsigkeyring.cpython-312.pyc,,
-dns/__pycache__/ttl.cpython-312.pyc,,
-dns/__pycache__/update.cpython-312.pyc,,
-dns/__pycache__/version.cpython-312.pyc,,
-dns/__pycache__/versioned.cpython-312.pyc,,
-dns/__pycache__/win32util.cpython-312.pyc,,
-dns/__pycache__/wire.cpython-312.pyc,,
-dns/__pycache__/xfr.cpython-312.pyc,,
-dns/__pycache__/zone.cpython-312.pyc,,
-dns/__pycache__/zonefile.cpython-312.pyc,,
-dns/__pycache__/zonetypes.cpython-312.pyc,,
-dns/_asyncbackend.py,sha256=Ny0kGesm9wbLBnt-0u-tANOKsxcYt2jbMuRoRz_JZUA,2360
-dns/_asyncio_backend.py,sha256=q58xPdqAOLmOYOux8GFRyiH-fSZ7jiwZF-Jg2vHjYSU,8971
-dns/_ddr.py,sha256=rHXKC8kncCTT9N4KBh1flicl79nyDjQ-DDvq30MJ3B8,5247
-dns/_features.py,sha256=MUeyfM_nMYAYkasGfbY7I_15JmwftaZjseuP1L43MT0,2384
-dns/_immutable_ctx.py,sha256=gtoCLMmdHXI23zt5lRSIS3A4Ca3jZJngebdoFFOtiwU,2459
-dns/_trio_backend.py,sha256=Vab_wR2CxDgy2Jz3iM_64FZmP_kMUN9j8LS4eNl-Oig,8269
-dns/asyncbackend.py,sha256=82fXTFls_m7F_ekQbgUGOkoBbs4BI-GBLDZAWNGUvJ0,2796
-dns/asyncquery.py,sha256=Q7u04mbbqCoe9VxsqRcsWTPxgH2Cx49eWWgi2wUyZHU,26850
-dns/asyncresolver.py,sha256=GD86dCyW9YGKs6SggWXwBKEXifW7Qdx4cEAGFKY6fA4,17852
-dns/dnssec.py,sha256=xyYW1cf6eeFNXROrEs1pyY4TgC8jlmUiiootaPbVjjY,40693
-dns/dnssecalgs/__init__.py,sha256=DcnGIbL6m-USPSiLWHSw511awB7dytlljvCOOmzchS0,4279
-dns/dnssecalgs/__pycache__/__init__.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/base.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/cryptography.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/dsa.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/ecdsa.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/eddsa.cpython-312.pyc,,
-dns/dnssecalgs/__pycache__/rsa.cpython-312.pyc,,
-dns/dnssecalgs/base.py,sha256=hsFHFr_eCYeDcI0eU6_WiLlOYL0GR4QJ__sXoMrIAfE,2446
-dns/dnssecalgs/cryptography.py,sha256=3uqMfRm-zCkJPOrxUqlu9CmdxIMy71dVor9eAHi0wZM,2425
-dns/dnssecalgs/dsa.py,sha256=hklh_HkT_ZffQBHQ7t6pKUStTH4x5nXlz8R9RUP72aY,3497
-dns/dnssecalgs/ecdsa.py,sha256=GWrJgEXAK08MCdbLk7LQcD2ajKqW_dbONWXh3wieLzw,3016
-dns/dnssecalgs/eddsa.py,sha256=9lQQZ92f2PiIhhylieInO-19aSTDQiyoY8X2kTkGlcs,1914
-dns/dnssecalgs/rsa.py,sha256=jWkhWKByylIo7Y9gAiiO8t8bowF8IZ0siVjgZpdhLSE,3555
-dns/dnssectypes.py,sha256=CyeuGTS_rM3zXr8wD9qMT9jkzvVfTY2JWckUcogG83E,1799
-dns/e164.py,sha256=EsK8cnOtOx7kQ0DmSwibcwkzp6efMWjbRiTyHZO8Q-M,3978
-dns/edns.py,sha256=d8QWhmRd6qlaGfO-tY6iDQZt9XUiyfJfKdjoGjvwOU4,15263
-dns/entropy.py,sha256=qkG8hXDLzrJS6R5My26iA59c0RhPwJNzuOhOCAZU5Bw,4242
-dns/enum.py,sha256=EepaunPKixTSrascy7iAe9UQEXXxP_MB5Gx4jUpHIhg,3691
-dns/exception.py,sha256=FphWy-JLRG06UUUq2VmUGwdPA1xWja_8YfrcffRFlQs,5957
-dns/flags.py,sha256=cQ3kTFyvcKiWHAxI5AwchNqxVOrsIrgJ6brgrH42Wq8,2750
-dns/grange.py,sha256=HA623Mv2mZDmOK_BZNDDakT0L6EHsMQU9lFFkE8dKr0,2148
-dns/immutable.py,sha256=InrtpKvPxl-74oYbzsyneZwAuX78hUqeG22f2aniZbk,2017
-dns/inet.py,sha256=j6jQs3K_ehVhDv-i4jwCKePr5HpEiSzvOXQ4uhgn1sU,5772
-dns/ipv4.py,sha256=qEUXtlqWDH_blicj6VMvyQhfX7-BF0gB_lWJliV-2FI,2552
-dns/ipv6.py,sha256=EyiF5T8t2oww9-W4ZA5Zk2GGnOjTy_uZ50CI7maed_8,6600
-dns/message.py,sha256=DyUtBHArPX-WGj_AtcngyIXZNpLppLZX-6q9TryL_wI,65993
-dns/name.py,sha256=eaR1wVR0rErnD3EPANquCuyqpbxy5VfFVhMenWlBPDE,42672
-dns/namedict.py,sha256=hJRYpKeQv6Bd2LaUOPV0L_a0eXEIuqgggPXaH4c3Tow,4000
-dns/nameserver.py,sha256=VkYRnX5wQ7RihAD6kYqidI_hb9NgKJSAE0GaYulNpHY,9909
-dns/node.py,sha256=NGZa0AUMq-CNledJ6wn1Rx6TFYc703cH2OraLysoNWM,12663
-dns/opcode.py,sha256=I6JyuFUL0msja_BYm6bzXHfbbfqUod_69Ss4xcv8xWQ,2730
-dns/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-dns/query.py,sha256=vB8C5u6HyjPWrEx9kUdTSg3kxrOoWbPGu7brC0eetIM,54832
-dns/quic/__init__.py,sha256=F6BybmRKnMGc4W8nX7K98PeyXiSwy1FHb_bJeA2lQSw,2202
-dns/quic/__pycache__/__init__.cpython-312.pyc,,
-dns/quic/__pycache__/_asyncio.cpython-312.pyc,,
-dns/quic/__pycache__/_common.cpython-312.pyc,,
-dns/quic/__pycache__/_sync.cpython-312.pyc,,
-dns/quic/__pycache__/_trio.cpython-312.pyc,,
-dns/quic/_asyncio.py,sha256=vv4RR3Ol0Y1ZOj7rPAzXxy1UcWjPvhTGQvVkMidPs-o,8159
-dns/quic/_common.py,sha256=06TfauL2VciPYSfrL4gif1eR1rm-TRkQhS2Puuk5URU,7282
-dns/quic/_sync.py,sha256=kE0PRavzd27GPQ9UgYApXZ6SGSW2LwCt8k6XWUvrbVE,8133
-dns/quic/_trio.py,sha256=9zCCBtDs6GAtY_b8ck-A17QMiLZ0njjhVtfFT5qMP7s,7670
-dns/rcode.py,sha256=N6JjrIQjCdJy0boKIp8Hcky5tm__LSDscpDz3rE_sgU,4156
-dns/rdata.py,sha256=9cXM9Y9MK2hy9w5mYqmP-r7_aKjHosigfNn_SfqfGGw,29456
-dns/rdataclass.py,sha256=TK4W4ywB1L_X7EZqk2Gmwnu7vdQpolQF5DtQWyNk5xo,2984
-dns/rdataset.py,sha256=96gTaEIcYEL348VKtTOMAazXBVNtk7m0Xez0mF1eg4I,16756
-dns/rdatatype.py,sha256=gIdYZ0iHRlgiTEO-ftobUANmaAmjTnNc4JljMaP1OnQ,7339
-dns/rdtypes/ANY/AFSDB.py,sha256=k75wMwreF1DAfDymu4lHh16BUx7ulVP3PLeQBZnkurY,1661
-dns/rdtypes/ANY/AMTRELAY.py,sha256=19jfS61mT1CQT-8vf67ZylhDS9JVRVp4WCbFE-7l0jM,3381
-dns/rdtypes/ANY/AVC.py,sha256=SpsXYzlBirRWN0mGnQe0MdN6H8fvlgXPJX5PjOHnEak,1024
-dns/rdtypes/ANY/CAA.py,sha256=AHh59Is-4WiVWd26yovnPM3hXqKS-yx7IWfXSS0NZhE,2511
-dns/rdtypes/ANY/CDNSKEY.py,sha256=bJAdrBMsFHIJz8TF1AxZoNbdxVWBCRTG-bR_uR_r_G4,1225
-dns/rdtypes/ANY/CDS.py,sha256=Y9nIRUCAabztVLbxm2SXAdYapFemCOUuGh5JqroCDUs,1163
-dns/rdtypes/ANY/CERT.py,sha256=2Cu2LQM6-K4darqhHv1EM_blmpYpnrBIIX1GnL_rxKE,3533
-dns/rdtypes/ANY/CNAME.py,sha256=IHGGq2BDpeKUahTr1pvyBQgm0NGBI_vQ3Vs5mKTXO4w,1206
-dns/rdtypes/ANY/CSYNC.py,sha256=KkZ_rG6PfeL14il97nmJGWWmUGGS5o9nd2EqbJqOuYo,2439
-dns/rdtypes/ANY/DLV.py,sha256=J-pOrw5xXsDoaB9G0r6znlYXJtqtcqhsl1OXs6CPRU4,986
-dns/rdtypes/ANY/DNAME.py,sha256=yqXRtx4dAWwB4YCCv-qW6uaxeGhg2LPQ2uyKwWaMdXs,1150
-dns/rdtypes/ANY/DNSKEY.py,sha256=MD8HUVH5XXeAGOnFWg5aVz_w-2tXYwCeVXmzExhiIeQ,1223
-dns/rdtypes/ANY/DS.py,sha256=_gf8vk1O_uY8QXFjsfUw-bny-fm6e-QpCk3PT0JCyoM,995
-dns/rdtypes/ANY/EUI48.py,sha256=x0BkK0sY_tgzuCwfDYpw6tyuChHjjtbRpAgYhO0Y44o,1151
-dns/rdtypes/ANY/EUI64.py,sha256=1jCff2-SXHJLDnNDnMW8Cd_o-ok0P3x6zKy_bcCU5h4,1161
-dns/rdtypes/ANY/GPOS.py,sha256=pM3i6Tn4qwHWOGOuIuW9FENPlSXT_R4xsNJeGrrABc8,4433
-dns/rdtypes/ANY/HINFO.py,sha256=vYGCHGZmYOhtmxHlvPqrK7m4pBg3MSY5herBsKJTbKQ,2249
-dns/rdtypes/ANY/HIP.py,sha256=Ucrnndu3xDyHFB93AVUA3xW-r61GR50kpRHLyLacvZY,3228
-dns/rdtypes/ANY/ISDN.py,sha256=uymYB-ayZSBob6jQgXe4EefNB8-JMLW6VfxXn7ncwPg,2713
-dns/rdtypes/ANY/L32.py,sha256=TMz2kdGCd0siiQZyiocVDCSnvkOdjhUuYRFyf8o622M,1286
-dns/rdtypes/ANY/L64.py,sha256=sb2BjuPA0PQt67nEyT9rBt759C9e6lH71d3EJHGGnww,1592
-dns/rdtypes/ANY/LOC.py,sha256=hLkzgCxqEhg6fn5Uf-DJigKEIE6oavQ8rLpajp3HDLs,12024
-dns/rdtypes/ANY/LP.py,sha256=wTsKIjtK6vh66qZRLSsiE0k54GO8ieVBGZH8dzVvFnE,1338
-dns/rdtypes/ANY/MX.py,sha256=qQk83idY0-SbRMDmB15JOpJi7cSyiheF-ALUD0Ev19E,995
-dns/rdtypes/ANY/NID.py,sha256=N7Xx4kXf3yVAocTlCXQeJ3BtiQNPFPQVdL1iMuyl5W4,1544
-dns/rdtypes/ANY/NINFO.py,sha256=bdL_-6Bejb2EH-xwR1rfSr_9E3SDXLTAnov7x2924FI,1041
-dns/rdtypes/ANY/NS.py,sha256=ThfaPalUlhbyZyNyvBM3k-7onl3eJKq5wCORrOGtkMM,995
-dns/rdtypes/ANY/NSEC.py,sha256=6uRn1SxNuLRNumeoc76BkpECF8ztuqyaYviLjFe7FkQ,2475
-dns/rdtypes/ANY/NSEC3.py,sha256=696h-Zz30bmcT0n1rqoEtS5wqE6jIgsVGzaw5TfdGJo,4331
-dns/rdtypes/ANY/NSEC3PARAM.py,sha256=08p6NWS4DiLav1wOuPbxUxB9MtY2IPjfOMCtJwzzMuA,2635
-dns/rdtypes/ANY/OPENPGPKEY.py,sha256=Va0FGo_8vm1OeX62N5iDTWukAdLwrjTXIZeQ6oanE78,1851
-dns/rdtypes/ANY/OPT.py,sha256=W36RslT_Psp95OPUC70knumOYjKpaRHvGT27I-NV2qc,2561
-dns/rdtypes/ANY/PTR.py,sha256=5HcR1D77Otyk91vVY4tmqrfZfSxSXWyWvwIW-rIH5gc,997
-dns/rdtypes/ANY/RP.py,sha256=5Dgaava9mbLKr87XgbfKZPrunYPBaN8ejNzpmbW6r4s,2184
-dns/rdtypes/ANY/RRSIG.py,sha256=O8vwzS7ldfaj_x8DypvEGFsDSb7al-D7OEnprA3QQoo,4922
-dns/rdtypes/ANY/RT.py,sha256=2t9q3FZQ28iEyceeU25KU2Ur0T5JxELAu8BTwfOUgVw,1013
-dns/rdtypes/ANY/SMIMEA.py,sha256=6yjHuVDfIEodBU9wxbCGCDZ5cWYwyY6FCk-aq2VNU0s,222
-dns/rdtypes/ANY/SOA.py,sha256=Cn8yrag1YvrvwivQgWg-KXmOCaVQVdFHSkFF77w-CE0,3145
-dns/rdtypes/ANY/SPF.py,sha256=rA3Srs9ECQx-37lqm7Zf7aYmMpp_asv4tGS8_fSQ-CU,1022
-dns/rdtypes/ANY/SSHFP.py,sha256=l6TZH2R0kytiZGWez_g-Lq94o5a2xMuwLKwUwsPMx5w,2530
-dns/rdtypes/ANY/TKEY.py,sha256=HjJMIMl4Qb1Nt1JXS6iAymzd2nv_zdLWTt887PJU_5w,4931
-dns/rdtypes/ANY/TLSA.py,sha256=cytzebS3W7FFr9qeJ9gFSHq_bOwUk9aRVlXWHfnVrRs,218
-dns/rdtypes/ANY/TSIG.py,sha256=4fNQJSNWZXUKZejCciwQuUJtTw2g-YbPmqHrEj_pitg,4750
-dns/rdtypes/ANY/TXT.py,sha256=F1U9gIAhwXIV4UVT7CwOCEn_su6G1nJIdgWJsLktk20,1000
-dns/rdtypes/ANY/URI.py,sha256=dpcS8KwcJ2WJ7BkOp4CZYaUyRuw7U2S9GzvVwKUihQg,2921
-dns/rdtypes/ANY/X25.py,sha256=PxjYTKIuoq44LT2S2JHWOV8BOFD0ASqjq0S5VBeGkFM,1944
-dns/rdtypes/ANY/ZONEMD.py,sha256=JQicv69EvUxh4FCT7eZSLzzU5L5brw_dSM65Um2t5lQ,2393
-dns/rdtypes/ANY/__init__.py,sha256=Pox71HfsEnGGB1PGU44pwrrmjxPLQlA-IbX6nQRoA2M,1497
-dns/rdtypes/ANY/__pycache__/AFSDB.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/AMTRELAY.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/AVC.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CAA.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CDNSKEY.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CDS.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CERT.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CNAME.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/CSYNC.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/DLV.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/DNAME.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/DNSKEY.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/DS.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/EUI48.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/EUI64.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/GPOS.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/HINFO.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/HIP.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/ISDN.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/L32.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/L64.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/LOC.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/LP.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/MX.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NID.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NINFO.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NS.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NSEC.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NSEC3.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/NSEC3PARAM.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/OPENPGPKEY.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/OPT.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/PTR.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/RP.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/RRSIG.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/RT.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/SMIMEA.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/SOA.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/SPF.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/SSHFP.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/TKEY.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/TLSA.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/TSIG.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/TXT.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/URI.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/X25.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/ZONEMD.cpython-312.pyc,,
-dns/rdtypes/ANY/__pycache__/__init__.cpython-312.pyc,,
-dns/rdtypes/CH/A.py,sha256=3S3OhOkSc7_ZsZBVB4GhTS19LPrrZ-yQ8sAp957qEgI,2216
-dns/rdtypes/CH/__init__.py,sha256=GD9YeDKb9VBDo-J5rrChX1MWEGyQXuR9Htnbhg_iYLc,923
-dns/rdtypes/CH/__pycache__/A.cpython-312.pyc,,
-dns/rdtypes/CH/__pycache__/__init__.cpython-312.pyc,,
-dns/rdtypes/IN/A.py,sha256=FfFn3SqbpneL9Ky63COP50V2ZFxqS1ldCKJh39Enwug,1814
-dns/rdtypes/IN/AAAA.py,sha256=AxrOlYy-1TTTWeQypDKeXrDCrdHGor0EKCE4fxzSQGo,1820
-dns/rdtypes/IN/APL.py,sha256=ppyFwn0KYMdyDzphxd0BUhgTmZv0QnDMRLjzQQM793U,5097
-dns/rdtypes/IN/DHCID.py,sha256=zRUh_EOxUPVpJjWY5m7taX8q4Oz5K70785ZtKv5OTCU,1856
-dns/rdtypes/IN/HTTPS.py,sha256=P-IjwcvDQMmtoBgsDHglXF7KgLX73G6jEDqCKsnaGpQ,220
-dns/rdtypes/IN/IPSECKEY.py,sha256=RyIy9K0Yt0uJRjdr6cj5S95ELHHbl--0xV-Qq9O3QQk,3290
-dns/rdtypes/IN/KX.py,sha256=K1JwItL0n5G-YGFCjWeh0C9DyDD8G8VzicsBeQiNAv0,1013
-dns/rdtypes/IN/NAPTR.py,sha256=SaOK-0hIYImwLtb5Hqewi-e49ykJaQiLNvk8ZzNoG7Q,3750
-dns/rdtypes/IN/NSAP.py,sha256=3OUpPOSOxU8fcdi0Oe6Ex2ERXcQ-U3iNf6FftZMtNOw,2165
-dns/rdtypes/IN/NSAP_PTR.py,sha256=iTxlV6fr_Y9lqivLLncSHxEhmFqz5UEElDW3HMBtuCU,1015
-dns/rdtypes/IN/PX.py,sha256=vHDNN2rfLObuUKwpYDIvpPB482BqXlHA-ZQpQn9Sb_E,2756
-dns/rdtypes/IN/SRV.py,sha256=a0zGaUwzvih_a4Q9BViUTFs7NZaCqgl7mls3-KRVHm8,2769
-dns/rdtypes/IN/SVCB.py,sha256=HeFmi2v01F00Hott8FlvQ4R7aPxFmT7RF-gt45R5K_M,218
-dns/rdtypes/IN/WKS.py,sha256=kErSG5AO2qIuot_hkMHnQuZB1_uUzUirNdqBoCp97rk,3652
-dns/rdtypes/IN/__init__.py,sha256=HbI8aw9HWroI6SgEvl8Sx6FdkDswCCXMbSRuJy5o8LQ,1083
-dns/rdtypes/IN/__pycache__/A.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/AAAA.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/APL.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/DHCID.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/HTTPS.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/IPSECKEY.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/KX.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/NAPTR.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/NSAP.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/NSAP_PTR.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/PX.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/SRV.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/SVCB.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/WKS.cpython-312.pyc,,
-dns/rdtypes/IN/__pycache__/__init__.cpython-312.pyc,,
-dns/rdtypes/__init__.py,sha256=NYizfGglJfhqt_GMtSSXf7YQXIEHHCiJ_Y_qaLVeiOI,1073
-dns/rdtypes/__pycache__/__init__.cpython-312.pyc,,
-dns/rdtypes/__pycache__/dnskeybase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/dsbase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/euibase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/mxbase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/nsbase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/svcbbase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/tlsabase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/txtbase.cpython-312.pyc,,
-dns/rdtypes/__pycache__/util.cpython-312.pyc,,
-dns/rdtypes/dnskeybase.py,sha256=FoDllfa9Pz2j2rf45VyUUYUsIt3kjjrwDy6LxrlPb5s,2856
-dns/rdtypes/dsbase.py,sha256=I85Aps1lBsiItdqGpsNY1O8icosfPtkWjiUn1J1lLUQ,3427
-dns/rdtypes/euibase.py,sha256=umN9A3VNw1TziAVtePvUses2jWPcynxINvjgyndPCdQ,2630
-dns/rdtypes/mxbase.py,sha256=DzjbiKoAAgpqbhwMBIFGA081jR5_doqGAq-kLvy2mns,3196
-dns/rdtypes/nsbase.py,sha256=tueXVV6E8lelebOmrmoOPq47eeRvOpsxHVXH4cOFxcs,2323
-dns/rdtypes/svcbbase.py,sha256=TQRT52m8F2NpSJsHUkTFS-hrkyhcIoAodW6bBHED4CY,16674
-dns/rdtypes/tlsabase.py,sha256=pIiWem6sF4IwyyKmyqx5xg55IG0w3K9r502Yx8PdziA,2596
-dns/rdtypes/txtbase.py,sha256=K4v2ulFu0DxPjxyf_Ul7YRjfBpUO-Ay_ChnR_Wx-ywA,3601
-dns/rdtypes/util.py,sha256=6AGQ-k3mLNlx4Ep_FiDABj1WVumUUGs3zQ6X-2iISec,9003
-dns/renderer.py,sha256=5THf1iKql2JPL2sKZt2-b4zqHKfk_vlx0FEfPtMJysY,11254
-dns/resolver.py,sha256=wagpUIu8Oh12O-zk48U30A6VQQOspjfibU4Ls2So-kM,73552
-dns/reversename.py,sha256=zoqXEbMZXm6R13nXbJHgTsf6L2C6uReODj6mqSHrTiE,3828
-dns/rrset.py,sha256=J-oQPEPJuKueLLiz1FN08P-ys9fjHhPWuwpDdrL4UTQ,9170
-dns/serial.py,sha256=-t5rPW-TcJwzBMfIJo7Tl-uDtaYtpqOfCVYx9dMaDCY,3606
-dns/set.py,sha256=Lr1qhyqywoobNkj9sAfdovoFy9vBfkz2eHdTCc7sZRs,9088
-dns/tokenizer.py,sha256=Dcc3lQgEIHCVZBuO6FaKWEojtPSd3EuaUC4vQA-spnk,23583
-dns/transaction.py,sha256=ZlnDT-V4W01J3cS501GaRLVhE9t1jZdnEZxPyZ0Cvg4,22636
-dns/tsig.py,sha256=I-Y-c3WMBX11bVioy5puFly2BhlpptUz82ikahxuh1c,11413
-dns/tsigkeyring.py,sha256=Z0xZemcU3XjZ9HlxBYv2E2PSuIhaFreqLDlD7HcmZDA,2633
-dns/ttl.py,sha256=fWFkw8qfk6saTp7lAPxZOuD3U3TRxVRvIpljQnG-01I,2979
-dns/update.py,sha256=y9d6LOO8xrUaH2UrZhy3ssnx8bJEsxqTArw5V8XqBRs,12243
-dns/version.py,sha256=sRMqE5tzPhXEzz-SEvdN82pP77xF_i1iELxaJN0roDE,1926
-dns/versioned.py,sha256=3YQj8mzGmZEsjnuVJJjcWopVmDKYLhEj4hEGTLEwzco,11765
-dns/win32util.py,sha256=NEjd5RXQU2aV1WsBMoIGZmXyqqKCxS4WYq9HqFQoVig,9107
-dns/wire.py,sha256=vy0SolgECbO1UXB4dnhXhDeFKOJT29nQxXvSfKOgA5s,2830
-dns/xfr.py,sha256=FKkKO-kSpyE1vHU5mnoPIP4YxiCl5gG7E5wOgY_4GO8,13273
-dns/zone.py,sha256=lLAarSxPtpx4Sw29OQ0ifPshD4QauGu8RnPh2dEropA,52086
-dns/zonefile.py,sha256=9pgkO0pV8Js53Oq9ZKOSbpFkGS5r_orU-25tmufGP9M,27929
-dns/zonetypes.py,sha256=HrQNZxZ_gWLWI9dskix71msi9wkYK5pgrBBbPb1T74Y,690
-dnspython-2.6.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-dnspython-2.6.1.dist-info/METADATA,sha256=2GJFv-NqkwIytog5VQe0wPtZKoS016uyYfG76lqftto,5808
-dnspython-2.6.1.dist-info/RECORD,,
-dnspython-2.6.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-dnspython-2.6.1.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
-dnspython-2.6.1.dist-info/licenses/LICENSE,sha256=w-o_9WVLMpwZ07xfdIGvYjw93tSmFFWFSZ-EOtPXQc0,1526
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/REQUESTED b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/WHEEL
deleted file mode 100644
index 5998f3a..0000000
--- a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: hatchling 1.21.1
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/licenses/LICENSE b/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/licenses/LICENSE
deleted file mode 100644
index 390a726..0000000
--- a/.venv/lib/python3.12/site-packages/dnspython-2.6.1.dist-info/licenses/LICENSE
+++ /dev/null
@@ -1,35 +0,0 @@
-ISC License
-
-Copyright (C) Dnspython Contributors
-
-Permission to use, copy, modify, and/or distribute this software for
-any purpose with or without fee is hereby granted, provided that the
-above copyright notice and this permission notice appear in all
-copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
-WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
-WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
-AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
-DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
-PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
-TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-PERFORMANCE OF THIS SOFTWARE.
-
-
-
-Copyright (C) 2001-2017 Nominum, Inc.
-Copyright (C) Google Inc.
-
-Permission to use, copy, modify, and distribute this software and its
-documentation for any purpose with or without fee is hereby granted,
-provided that the above copyright notice and this permission notice
-appear in all copies.
-
-THE SOFTWARE IS PROVIDED "AS IS" AND NOMINUM DISCLAIMS ALL WARRANTIES
-WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
-MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NOMINUM BE LIABLE FOR
-ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
-WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
-ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
-OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
diff --git a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/LICENSE.md b/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/LICENSE.md
deleted file mode 100644
index 19b6b45..0000000
--- a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/LICENSE.md
+++ /dev/null
@@ -1,31 +0,0 @@
-BSD 3-Clause License
-
-Copyright (c) 2013-2024, Kim Davies and contributors.
-All rights reserved.
-
-Redistribution and use in source and binary forms, with or without
-modification, are permitted provided that the following conditions are
-met:
-
-1. Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
-
-2. Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in the
- documentation and/or other materials provided with the distribution.
-
-3. Neither the name of the copyright holder nor the names of its
- contributors may be used to endorse or promote products derived from
- this software without specific prior written permission.
-
-THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
-TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
-PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
-LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
-NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
-SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/METADATA b/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/METADATA
deleted file mode 100644
index b28f6ec..0000000
--- a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/METADATA
+++ /dev/null
@@ -1,243 +0,0 @@
-Metadata-Version: 2.1
-Name: idna
-Version: 3.7
-Summary: Internationalized Domain Names in Applications (IDNA)
-Author-email: Kim Davies
-Requires-Python: >=3.5
-Description-Content-Type: text/x-rst
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Intended Audience :: Developers
-Classifier: Intended Audience :: System Administrators
-Classifier: License :: OSI Approved :: BSD License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.5
-Classifier: Programming Language :: Python :: 3.6
-Classifier: Programming Language :: Python :: 3.7
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: Name Service (DNS)
-Classifier: Topic :: Software Development :: Libraries :: Python Modules
-Classifier: Topic :: Utilities
-Project-URL: Changelog, https://github.com/kjd/idna/blob/master/HISTORY.rst
-Project-URL: Issue tracker, https://github.com/kjd/idna/issues
-Project-URL: Source, https://github.com/kjd/idna
-
-Internationalized Domain Names in Applications (IDNA)
-=====================================================
-
-Support for the Internationalized Domain Names in
-Applications (IDNA) protocol as specified in `RFC 5891
-`_. This is the latest version of
-the protocol and is sometimes referred to as “IDNA 2008”.
-
-This library also provides support for Unicode Technical
-Standard 46, `Unicode IDNA Compatibility Processing
- `_.
-
-This acts as a suitable replacement for the “encodings.idna”
-module that comes with the Python standard library, but which
-only supports the older superseded IDNA specification (`RFC 3490
-`_).
-
-Basic functions are simply executed:
-
-.. code-block:: pycon
-
- >>> import idna
- >>> idna.encode('ドメイン.テスト')
- b'xn--eckwd4c7c.xn--zckzah'
- >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))
- ドメイン.テスト
-
-
-Installation
-------------
-
-This package is available for installation from PyPI:
-
-.. code-block:: bash
-
- $ python3 -m pip install idna
-
-
-Usage
------
-
-For typical usage, the ``encode`` and ``decode`` functions will take a
-domain name argument and perform a conversion to A-labels or U-labels
-respectively.
-
-.. code-block:: pycon
-
- >>> import idna
- >>> idna.encode('ドメイン.テスト')
- b'xn--eckwd4c7c.xn--zckzah'
- >>> print(idna.decode('xn--eckwd4c7c.xn--zckzah'))
- ドメイン.テスト
-
-You may use the codec encoding and decoding methods using the
-``idna.codec`` module:
-
-.. code-block:: pycon
-
- >>> import idna.codec
- >>> print('домен.испытание'.encode('idna2008'))
- b'xn--d1acufc.xn--80akhbyknj4f'
- >>> print(b'xn--d1acufc.xn--80akhbyknj4f'.decode('idna2008'))
- домен.испытание
-
-Conversions can be applied at a per-label basis using the ``ulabel`` or
-``alabel`` functions if necessary:
-
-.. code-block:: pycon
-
- >>> idna.alabel('测试')
- b'xn--0zwm56d'
-
-Compatibility Mapping (UTS #46)
-+++++++++++++++++++++++++++++++
-
-As described in `RFC 5895 `_, the
-IDNA specification does not normalize input from different potential
-ways a user may input a domain name. This functionality, known as
-a “mapping”, is considered by the specification to be a local
-user-interface issue distinct from IDNA conversion functionality.
-
-This library provides one such mapping that was developed by the
-Unicode Consortium. Known as `Unicode IDNA Compatibility Processing
- `_, it provides for both a regular
-mapping for typical applications, as well as a transitional mapping to
-help migrate from older IDNA 2003 applications.
-
-For example, “Königsgäßchen” is not a permissible label as *LATIN
-CAPITAL LETTER K* is not allowed (nor are capital letters in general).
-UTS 46 will convert this into lower case prior to applying the IDNA
-conversion.
-
-.. code-block:: pycon
-
- >>> import idna
- >>> idna.encode('Königsgäßchen')
- ...
- idna.core.InvalidCodepoint: Codepoint U+004B at position 1 of 'Königsgäßchen' not allowed
- >>> idna.encode('Königsgäßchen', uts46=True)
- b'xn--knigsgchen-b4a3dun'
- >>> print(idna.decode('xn--knigsgchen-b4a3dun'))
- königsgäßchen
-
-Transitional processing provides conversions to help transition from
-the older 2003 standard to the current standard. For example, in the
-original IDNA specification, the *LATIN SMALL LETTER SHARP S* (ß) was
-converted into two *LATIN SMALL LETTER S* (ss), whereas in the current
-IDNA specification this conversion is not performed.
-
-.. code-block:: pycon
-
- >>> idna.encode('Königsgäßchen', uts46=True, transitional=True)
- 'xn--knigsgsschen-lcb0w'
-
-Implementers should use transitional processing with caution, only in
-rare cases where conversion from legacy labels to current labels must be
-performed (i.e. IDNA implementations that pre-date 2008). For typical
-applications that just need to convert labels, transitional processing
-is unlikely to be beneficial and could produce unexpected incompatible
-results.
-
-``encodings.idna`` Compatibility
-++++++++++++++++++++++++++++++++
-
-Function calls from the Python built-in ``encodings.idna`` module are
-mapped to their IDNA 2008 equivalents using the ``idna.compat`` module.
-Simply substitute the ``import`` clause in your code to refer to the new
-module name.
-
-Exceptions
-----------
-
-All errors raised during the conversion following the specification
-should raise an exception derived from the ``idna.IDNAError`` base
-class.
-
-More specific exceptions that may be generated as ``idna.IDNABidiError``
-when the error reflects an illegal combination of left-to-right and
-right-to-left characters in a label; ``idna.InvalidCodepoint`` when
-a specific codepoint is an illegal character in an IDN label (i.e.
-INVALID); and ``idna.InvalidCodepointContext`` when the codepoint is
-illegal based on its positional context (i.e. it is CONTEXTO or CONTEXTJ
-but the contextual requirements are not satisfied.)
-
-Building and Diagnostics
-------------------------
-
-The IDNA and UTS 46 functionality relies upon pre-calculated lookup
-tables for performance. These tables are derived from computing against
-eligibility criteria in the respective standards. These tables are
-computed using the command-line script ``tools/idna-data``.
-
-This tool will fetch relevant codepoint data from the Unicode repository
-and perform the required calculations to identify eligibility. There are
-three main modes:
-
-* ``idna-data make-libdata``. Generates ``idnadata.py`` and
- ``uts46data.py``, the pre-calculated lookup tables used for IDNA and
- UTS 46 conversions. Implementers who wish to track this library against
- a different Unicode version may use this tool to manually generate a
- different version of the ``idnadata.py`` and ``uts46data.py`` files.
-
-* ``idna-data make-table``. Generate a table of the IDNA disposition
- (e.g. PVALID, CONTEXTJ, CONTEXTO) in the format found in Appendix
- B.1 of RFC 5892 and the pre-computed tables published by `IANA
- `_.
-
-* ``idna-data U+0061``. Prints debugging output on the various
- properties associated with an individual Unicode codepoint (in this
- case, U+0061), that are used to assess the IDNA and UTS 46 status of a
- codepoint. This is helpful in debugging or analysis.
-
-The tool accepts a number of arguments, described using ``idna-data
--h``. Most notably, the ``--version`` argument allows the specification
-of the version of Unicode to be used in computing the table data. For
-example, ``idna-data --version 9.0.0 make-libdata`` will generate
-library data against Unicode 9.0.0.
-
-
-Additional Notes
-----------------
-
-* **Packages**. The latest tagged release version is published in the
- `Python Package Index `_.
-
-* **Version support**. This library supports Python 3.5 and higher.
- As this library serves as a low-level toolkit for a variety of
- applications, many of which strive for broad compatibility with older
- Python versions, there is no rush to remove older interpreter support.
- Removing support for older versions should be well justified in that the
- maintenance burden has become too high.
-
-* **Python 2**. Python 2 is supported by version 2.x of this library.
- While active development of the version 2.x series has ended, notable
- issues being corrected may be backported to 2.x. Use "idna<3" in your
- requirements file if you need this library for a Python 2 application.
-
-* **Testing**. The library has a test suite based on each rule of the
- IDNA specification, as well as tests that are provided as part of the
- Unicode Technical Standard 46, `Unicode IDNA Compatibility Processing
- `_.
-
-* **Emoji**. It is an occasional request to support emoji domains in
- this library. Encoding of symbols like emoji is expressly prohibited by
- the technical standard IDNA 2008 and emoji domains are broadly phased
- out across the domain industry due to associated security risks. For
- now, applications that need to support these non-compliant labels
- may wish to consider trying the encode/decode operation in this library
- first, and then falling back to using `encodings.idna`. See `the Github
- project `_ for more discussion.
-
diff --git a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/RECORD b/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/RECORD
deleted file mode 100644
index 16e596b..0000000
--- a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/RECORD
+++ /dev/null
@@ -1,22 +0,0 @@
-idna-3.7.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-idna-3.7.dist-info/LICENSE.md,sha256=pZ8LDvNjWHQQmkRhykT_enDVBpboFHZ7-vch1Mmw2w8,1541
-idna-3.7.dist-info/METADATA,sha256=OixCk-dKLZkPy-MfviOmiPvwJ1O2K_8rqCrFjC_uxy4,9888
-idna-3.7.dist-info/RECORD,,
-idna-3.7.dist-info/WHEEL,sha256=EZbGkh7Ie4PoZfRQ8I0ZuP9VklN_TvcZ6DSE5Uar4z4,81
-idna/__init__.py,sha256=KJQN1eQBr8iIK5SKrJ47lXvxG0BJ7Lm38W4zT0v_8lk,849
-idna/__pycache__/__init__.cpython-312.pyc,,
-idna/__pycache__/codec.cpython-312.pyc,,
-idna/__pycache__/compat.cpython-312.pyc,,
-idna/__pycache__/core.cpython-312.pyc,,
-idna/__pycache__/idnadata.cpython-312.pyc,,
-idna/__pycache__/intranges.cpython-312.pyc,,
-idna/__pycache__/package_data.cpython-312.pyc,,
-idna/__pycache__/uts46data.cpython-312.pyc,,
-idna/codec.py,sha256=PS6m-XmdST7Wj7J7ulRMakPDt5EBJyYrT3CPtjh-7t4,3426
-idna/compat.py,sha256=0_sOEUMT4CVw9doD3vyRhX80X19PwqFoUBs7gWsFME4,321
-idna/core.py,sha256=lyhpoe2vulEaB_65xhXmoKgO-xUqFDvcwxu5hpNNO4E,12663
-idna/idnadata.py,sha256=dqRwytzkjIHMBa2R1lYvHDwACenZPt8eGVu1Y8UBE-E,78320
-idna/intranges.py,sha256=YBr4fRYuWH7kTKS2tXlFjM24ZF1Pdvcir-aywniInqg,1881
-idna/package_data.py,sha256=Tkt0KnIeyIlnHddOaz9WSkkislNgokJAuE-p5GorMqo,21
-idna/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-idna/uts46data.py,sha256=1KuksWqLuccPXm2uyRVkhfiFLNIhM_H2m4azCcnOqEU,206503
diff --git a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/WHEEL
deleted file mode 100644
index 3b5e64b..0000000
--- a/.venv/lib/python3.12/site-packages/idna-3.7.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: flit 3.9.0
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/.venv/lib/python3.12/site-packages/idna/__init__.py b/.venv/lib/python3.12/site-packages/idna/__init__.py
deleted file mode 100644
index a40eeaf..0000000
--- a/.venv/lib/python3.12/site-packages/idna/__init__.py
+++ /dev/null
@@ -1,44 +0,0 @@
-from .package_data import __version__
-from .core import (
- IDNABidiError,
- IDNAError,
- InvalidCodepoint,
- InvalidCodepointContext,
- alabel,
- check_bidi,
- check_hyphen_ok,
- check_initial_combiner,
- check_label,
- check_nfc,
- decode,
- encode,
- ulabel,
- uts46_remap,
- valid_contextj,
- valid_contexto,
- valid_label_length,
- valid_string_length,
-)
-from .intranges import intranges_contain
-
-__all__ = [
- "IDNABidiError",
- "IDNAError",
- "InvalidCodepoint",
- "InvalidCodepointContext",
- "alabel",
- "check_bidi",
- "check_hyphen_ok",
- "check_initial_combiner",
- "check_label",
- "check_nfc",
- "decode",
- "encode",
- "intranges_contain",
- "ulabel",
- "uts46_remap",
- "valid_contextj",
- "valid_contexto",
- "valid_label_length",
- "valid_string_length",
-]
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index e938861..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/codec.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/codec.cpython-312.pyc
deleted file mode 100644
index 2a6e984..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/codec.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/compat.cpython-312.pyc
deleted file mode 100644
index 3057b41..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/compat.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/core.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/core.cpython-312.pyc
deleted file mode 100644
index e5b0af2..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/core.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc
deleted file mode 100644
index 1ba2320..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/idnadata.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc
deleted file mode 100644
index 6df38b4..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/intranges.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/package_data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/package_data.cpython-312.pyc
deleted file mode 100644
index 673ad48..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/package_data.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/__pycache__/uts46data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/idna/__pycache__/uts46data.cpython-312.pyc
deleted file mode 100644
index d59306f..0000000
Binary files a/.venv/lib/python3.12/site-packages/idna/__pycache__/uts46data.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/idna/codec.py b/.venv/lib/python3.12/site-packages/idna/codec.py
deleted file mode 100644
index c855a4d..0000000
--- a/.venv/lib/python3.12/site-packages/idna/codec.py
+++ /dev/null
@@ -1,118 +0,0 @@
-from .core import encode, decode, alabel, ulabel, IDNAError
-import codecs
-import re
-from typing import Any, Tuple, Optional
-
-_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
-
-class Codec(codecs.Codec):
-
- def encode(self, data: str, errors: str = 'strict') -> Tuple[bytes, int]:
- if errors != 'strict':
- raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
-
- if not data:
- return b"", 0
-
- return encode(data), len(data)
-
- def decode(self, data: bytes, errors: str = 'strict') -> Tuple[str, int]:
- if errors != 'strict':
- raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
-
- if not data:
- return '', 0
-
- return decode(data), len(data)
-
-class IncrementalEncoder(codecs.BufferedIncrementalEncoder):
- def _buffer_encode(self, data: str, errors: str, final: bool) -> Tuple[bytes, int]:
- if errors != 'strict':
- raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
-
- if not data:
- return b'', 0
-
- labels = _unicode_dots_re.split(data)
- trailing_dot = b''
- if labels:
- if not labels[-1]:
- trailing_dot = b'.'
- del labels[-1]
- elif not final:
- # Keep potentially unfinished label until the next call
- del labels[-1]
- if labels:
- trailing_dot = b'.'
-
- result = []
- size = 0
- for label in labels:
- result.append(alabel(label))
- if size:
- size += 1
- size += len(label)
-
- # Join with U+002E
- result_bytes = b'.'.join(result) + trailing_dot
- size += len(trailing_dot)
- return result_bytes, size
-
-class IncrementalDecoder(codecs.BufferedIncrementalDecoder):
- def _buffer_decode(self, data: Any, errors: str, final: bool) -> Tuple[str, int]:
- if errors != 'strict':
- raise IDNAError('Unsupported error handling \"{}\"'.format(errors))
-
- if not data:
- return ('', 0)
-
- if not isinstance(data, str):
- data = str(data, 'ascii')
-
- labels = _unicode_dots_re.split(data)
- trailing_dot = ''
- if labels:
- if not labels[-1]:
- trailing_dot = '.'
- del labels[-1]
- elif not final:
- # Keep potentially unfinished label until the next call
- del labels[-1]
- if labels:
- trailing_dot = '.'
-
- result = []
- size = 0
- for label in labels:
- result.append(ulabel(label))
- if size:
- size += 1
- size += len(label)
-
- result_str = '.'.join(result) + trailing_dot
- size += len(trailing_dot)
- return (result_str, size)
-
-
-class StreamWriter(Codec, codecs.StreamWriter):
- pass
-
-
-class StreamReader(Codec, codecs.StreamReader):
- pass
-
-
-def search_function(name: str) -> Optional[codecs.CodecInfo]:
- if name != 'idna2008':
- return None
- return codecs.CodecInfo(
- name=name,
- encode=Codec().encode,
- decode=Codec().decode,
- incrementalencoder=IncrementalEncoder,
- incrementaldecoder=IncrementalDecoder,
- streamwriter=StreamWriter,
- streamreader=StreamReader,
- )
-
-codecs.register(search_function)
diff --git a/.venv/lib/python3.12/site-packages/idna/compat.py b/.venv/lib/python3.12/site-packages/idna/compat.py
deleted file mode 100644
index 786e6bd..0000000
--- a/.venv/lib/python3.12/site-packages/idna/compat.py
+++ /dev/null
@@ -1,13 +0,0 @@
-from .core import *
-from .codec import *
-from typing import Any, Union
-
-def ToASCII(label: str) -> bytes:
- return encode(label)
-
-def ToUnicode(label: Union[bytes, bytearray]) -> str:
- return decode(label)
-
-def nameprep(s: Any) -> None:
- raise NotImplementedError('IDNA 2008 does not utilise nameprep protocol')
-
diff --git a/.venv/lib/python3.12/site-packages/idna/core.py b/.venv/lib/python3.12/site-packages/idna/core.py
deleted file mode 100644
index 0dae61a..0000000
--- a/.venv/lib/python3.12/site-packages/idna/core.py
+++ /dev/null
@@ -1,395 +0,0 @@
-from . import idnadata
-import bisect
-import unicodedata
-import re
-from typing import Union, Optional
-from .intranges import intranges_contain
-
-_virama_combining_class = 9
-_alabel_prefix = b'xn--'
-_unicode_dots_re = re.compile('[\u002e\u3002\uff0e\uff61]')
-
-class IDNAError(UnicodeError):
- """ Base exception for all IDNA-encoding related problems """
- pass
-
-
-class IDNABidiError(IDNAError):
- """ Exception when bidirectional requirements are not satisfied """
- pass
-
-
-class InvalidCodepoint(IDNAError):
- """ Exception when a disallowed or unallocated codepoint is used """
- pass
-
-
-class InvalidCodepointContext(IDNAError):
- """ Exception when the codepoint is not valid in the context it is used """
- pass
-
-
-def _combining_class(cp: int) -> int:
- v = unicodedata.combining(chr(cp))
- if v == 0:
- if not unicodedata.name(chr(cp)):
- raise ValueError('Unknown character in unicodedata')
- return v
-
-def _is_script(cp: str, script: str) -> bool:
- return intranges_contain(ord(cp), idnadata.scripts[script])
-
-def _punycode(s: str) -> bytes:
- return s.encode('punycode')
-
-def _unot(s: int) -> str:
- return 'U+{:04X}'.format(s)
-
-
-def valid_label_length(label: Union[bytes, str]) -> bool:
- if len(label) > 63:
- return False
- return True
-
-
-def valid_string_length(label: Union[bytes, str], trailing_dot: bool) -> bool:
- if len(label) > (254 if trailing_dot else 253):
- return False
- return True
-
-
-def check_bidi(label: str, check_ltr: bool = False) -> bool:
- # Bidi rules should only be applied if string contains RTL characters
- bidi_label = False
- for (idx, cp) in enumerate(label, 1):
- direction = unicodedata.bidirectional(cp)
- if direction == '':
- # String likely comes from a newer version of Unicode
- raise IDNABidiError('Unknown directionality in label {} at position {}'.format(repr(label), idx))
- if direction in ['R', 'AL', 'AN']:
- bidi_label = True
- if not bidi_label and not check_ltr:
- return True
-
- # Bidi rule 1
- direction = unicodedata.bidirectional(label[0])
- if direction in ['R', 'AL']:
- rtl = True
- elif direction == 'L':
- rtl = False
- else:
- raise IDNABidiError('First codepoint in label {} must be directionality L, R or AL'.format(repr(label)))
-
- valid_ending = False
- number_type = None # type: Optional[str]
- for (idx, cp) in enumerate(label, 1):
- direction = unicodedata.bidirectional(cp)
-
- if rtl:
- # Bidi rule 2
- if not direction in ['R', 'AL', 'AN', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
- raise IDNABidiError('Invalid direction for codepoint at position {} in a right-to-left label'.format(idx))
- # Bidi rule 3
- if direction in ['R', 'AL', 'EN', 'AN']:
- valid_ending = True
- elif direction != 'NSM':
- valid_ending = False
- # Bidi rule 4
- if direction in ['AN', 'EN']:
- if not number_type:
- number_type = direction
- else:
- if number_type != direction:
- raise IDNABidiError('Can not mix numeral types in a right-to-left label')
- else:
- # Bidi rule 5
- if not direction in ['L', 'EN', 'ES', 'CS', 'ET', 'ON', 'BN', 'NSM']:
- raise IDNABidiError('Invalid direction for codepoint at position {} in a left-to-right label'.format(idx))
- # Bidi rule 6
- if direction in ['L', 'EN']:
- valid_ending = True
- elif direction != 'NSM':
- valid_ending = False
-
- if not valid_ending:
- raise IDNABidiError('Label ends with illegal codepoint directionality')
-
- return True
-
-
-def check_initial_combiner(label: str) -> bool:
- if unicodedata.category(label[0])[0] == 'M':
- raise IDNAError('Label begins with an illegal combining character')
- return True
-
-
-def check_hyphen_ok(label: str) -> bool:
- if label[2:4] == '--':
- raise IDNAError('Label has disallowed hyphens in 3rd and 4th position')
- if label[0] == '-' or label[-1] == '-':
- raise IDNAError('Label must not start or end with a hyphen')
- return True
-
-
-def check_nfc(label: str) -> None:
- if unicodedata.normalize('NFC', label) != label:
- raise IDNAError('Label must be in Normalization Form C')
-
-
-def valid_contextj(label: str, pos: int) -> bool:
- cp_value = ord(label[pos])
-
- if cp_value == 0x200c:
-
- if pos > 0:
- if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
- return True
-
- ok = False
- for i in range(pos-1, -1, -1):
- joining_type = idnadata.joining_types.get(ord(label[i]))
- if joining_type == ord('T'):
- continue
- elif joining_type in [ord('L'), ord('D')]:
- ok = True
- break
- else:
- break
-
- if not ok:
- return False
-
- ok = False
- for i in range(pos+1, len(label)):
- joining_type = idnadata.joining_types.get(ord(label[i]))
- if joining_type == ord('T'):
- continue
- elif joining_type in [ord('R'), ord('D')]:
- ok = True
- break
- else:
- break
- return ok
-
- if cp_value == 0x200d:
-
- if pos > 0:
- if _combining_class(ord(label[pos - 1])) == _virama_combining_class:
- return True
- return False
-
- else:
-
- return False
-
-
-def valid_contexto(label: str, pos: int, exception: bool = False) -> bool:
- cp_value = ord(label[pos])
-
- if cp_value == 0x00b7:
- if 0 < pos < len(label)-1:
- if ord(label[pos - 1]) == 0x006c and ord(label[pos + 1]) == 0x006c:
- return True
- return False
-
- elif cp_value == 0x0375:
- if pos < len(label)-1 and len(label) > 1:
- return _is_script(label[pos + 1], 'Greek')
- return False
-
- elif cp_value == 0x05f3 or cp_value == 0x05f4:
- if pos > 0:
- return _is_script(label[pos - 1], 'Hebrew')
- return False
-
- elif cp_value == 0x30fb:
- for cp in label:
- if cp == '\u30fb':
- continue
- if _is_script(cp, 'Hiragana') or _is_script(cp, 'Katakana') or _is_script(cp, 'Han'):
- return True
- return False
-
- elif 0x660 <= cp_value <= 0x669:
- for cp in label:
- if 0x6f0 <= ord(cp) <= 0x06f9:
- return False
- return True
-
- elif 0x6f0 <= cp_value <= 0x6f9:
- for cp in label:
- if 0x660 <= ord(cp) <= 0x0669:
- return False
- return True
-
- return False
-
-
-def check_label(label: Union[str, bytes, bytearray]) -> None:
- if isinstance(label, (bytes, bytearray)):
- label = label.decode('utf-8')
- if len(label) == 0:
- raise IDNAError('Empty Label')
-
- check_nfc(label)
- check_hyphen_ok(label)
- check_initial_combiner(label)
-
- for (pos, cp) in enumerate(label):
- cp_value = ord(cp)
- if intranges_contain(cp_value, idnadata.codepoint_classes['PVALID']):
- continue
- elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTJ']):
- if not valid_contextj(label, pos):
- raise InvalidCodepointContext('Joiner {} not allowed at position {} in {}'.format(
- _unot(cp_value), pos+1, repr(label)))
- elif intranges_contain(cp_value, idnadata.codepoint_classes['CONTEXTO']):
- if not valid_contexto(label, pos):
- raise InvalidCodepointContext('Codepoint {} not allowed at position {} in {}'.format(_unot(cp_value), pos+1, repr(label)))
- else:
- raise InvalidCodepoint('Codepoint {} at position {} of {} not allowed'.format(_unot(cp_value), pos+1, repr(label)))
-
- check_bidi(label)
-
-
-def alabel(label: str) -> bytes:
- try:
- label_bytes = label.encode('ascii')
- ulabel(label_bytes)
- if not valid_label_length(label_bytes):
- raise IDNAError('Label too long')
- return label_bytes
- except UnicodeEncodeError:
- pass
-
- check_label(label)
- label_bytes = _alabel_prefix + _punycode(label)
-
- if not valid_label_length(label_bytes):
- raise IDNAError('Label too long')
-
- return label_bytes
-
-
-def ulabel(label: Union[str, bytes, bytearray]) -> str:
- if not isinstance(label, (bytes, bytearray)):
- try:
- label_bytes = label.encode('ascii')
- except UnicodeEncodeError:
- check_label(label)
- return label
- else:
- label_bytes = label
-
- label_bytes = label_bytes.lower()
- if label_bytes.startswith(_alabel_prefix):
- label_bytes = label_bytes[len(_alabel_prefix):]
- if not label_bytes:
- raise IDNAError('Malformed A-label, no Punycode eligible content found')
- if label_bytes.decode('ascii')[-1] == '-':
- raise IDNAError('A-label must not end with a hyphen')
- else:
- check_label(label_bytes)
- return label_bytes.decode('ascii')
-
- try:
- label = label_bytes.decode('punycode')
- except UnicodeError:
- raise IDNAError('Invalid A-label')
- check_label(label)
- return label
-
-
-def uts46_remap(domain: str, std3_rules: bool = True, transitional: bool = False) -> str:
- """Re-map the characters in the string according to UTS46 processing."""
- from .uts46data import uts46data
- output = ''
-
- for pos, char in enumerate(domain):
- code_point = ord(char)
- try:
- uts46row = uts46data[code_point if code_point < 256 else
- bisect.bisect_left(uts46data, (code_point, 'Z')) - 1]
- status = uts46row[1]
- replacement = None # type: Optional[str]
- if len(uts46row) == 3:
- replacement = uts46row[2]
- if (status == 'V' or
- (status == 'D' and not transitional) or
- (status == '3' and not std3_rules and replacement is None)):
- output += char
- elif replacement is not None and (status == 'M' or
- (status == '3' and not std3_rules) or
- (status == 'D' and transitional)):
- output += replacement
- elif status != 'I':
- raise IndexError()
- except IndexError:
- raise InvalidCodepoint(
- 'Codepoint {} not allowed at position {} in {}'.format(
- _unot(code_point), pos + 1, repr(domain)))
-
- return unicodedata.normalize('NFC', output)
-
-
-def encode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False, transitional: bool = False) -> bytes:
- if not isinstance(s, str):
- try:
- s = str(s, 'ascii')
- except UnicodeDecodeError:
- raise IDNAError('should pass a unicode string to the function rather than a byte string.')
- if uts46:
- s = uts46_remap(s, std3_rules, transitional)
- trailing_dot = False
- result = []
- if strict:
- labels = s.split('.')
- else:
- labels = _unicode_dots_re.split(s)
- if not labels or labels == ['']:
- raise IDNAError('Empty domain')
- if labels[-1] == '':
- del labels[-1]
- trailing_dot = True
- for label in labels:
- s = alabel(label)
- if s:
- result.append(s)
- else:
- raise IDNAError('Empty label')
- if trailing_dot:
- result.append(b'')
- s = b'.'.join(result)
- if not valid_string_length(s, trailing_dot):
- raise IDNAError('Domain too long')
- return s
-
-
-def decode(s: Union[str, bytes, bytearray], strict: bool = False, uts46: bool = False, std3_rules: bool = False) -> str:
- try:
- if not isinstance(s, str):
- s = str(s, 'ascii')
- except UnicodeDecodeError:
- raise IDNAError('Invalid ASCII in A-label')
- if uts46:
- s = uts46_remap(s, std3_rules, False)
- trailing_dot = False
- result = []
- if not strict:
- labels = _unicode_dots_re.split(s)
- else:
- labels = s.split('.')
- if not labels or labels == ['']:
- raise IDNAError('Empty domain')
- if not labels[-1]:
- del labels[-1]
- trailing_dot = True
- for label in labels:
- s = ulabel(label)
- if s:
- result.append(s)
- else:
- raise IDNAError('Empty label')
- if trailing_dot:
- result.append('')
- return '.'.join(result)
diff --git a/.venv/lib/python3.12/site-packages/idna/idnadata.py b/.venv/lib/python3.12/site-packages/idna/idnadata.py
deleted file mode 100644
index c61dcf9..0000000
--- a/.venv/lib/python3.12/site-packages/idna/idnadata.py
+++ /dev/null
@@ -1,4245 +0,0 @@
-# This file is automatically generated by tools/idna-data
-
-__version__ = '15.1.0'
-scripts = {
- 'Greek': (
- 0x37000000374,
- 0x37500000378,
- 0x37a0000037e,
- 0x37f00000380,
- 0x38400000385,
- 0x38600000387,
- 0x3880000038b,
- 0x38c0000038d,
- 0x38e000003a2,
- 0x3a3000003e2,
- 0x3f000000400,
- 0x1d2600001d2b,
- 0x1d5d00001d62,
- 0x1d6600001d6b,
- 0x1dbf00001dc0,
- 0x1f0000001f16,
- 0x1f1800001f1e,
- 0x1f2000001f46,
- 0x1f4800001f4e,
- 0x1f5000001f58,
- 0x1f5900001f5a,
- 0x1f5b00001f5c,
- 0x1f5d00001f5e,
- 0x1f5f00001f7e,
- 0x1f8000001fb5,
- 0x1fb600001fc5,
- 0x1fc600001fd4,
- 0x1fd600001fdc,
- 0x1fdd00001ff0,
- 0x1ff200001ff5,
- 0x1ff600001fff,
- 0x212600002127,
- 0xab650000ab66,
- 0x101400001018f,
- 0x101a0000101a1,
- 0x1d2000001d246,
- ),
- 'Han': (
- 0x2e8000002e9a,
- 0x2e9b00002ef4,
- 0x2f0000002fd6,
- 0x300500003006,
- 0x300700003008,
- 0x30210000302a,
- 0x30380000303c,
- 0x340000004dc0,
- 0x4e000000a000,
- 0xf9000000fa6e,
- 0xfa700000fada,
- 0x16fe200016fe4,
- 0x16ff000016ff2,
- 0x200000002a6e0,
- 0x2a7000002b73a,
- 0x2b7400002b81e,
- 0x2b8200002cea2,
- 0x2ceb00002ebe1,
- 0x2ebf00002ee5e,
- 0x2f8000002fa1e,
- 0x300000003134b,
- 0x31350000323b0,
- ),
- 'Hebrew': (
- 0x591000005c8,
- 0x5d0000005eb,
- 0x5ef000005f5,
- 0xfb1d0000fb37,
- 0xfb380000fb3d,
- 0xfb3e0000fb3f,
- 0xfb400000fb42,
- 0xfb430000fb45,
- 0xfb460000fb50,
- ),
- 'Hiragana': (
- 0x304100003097,
- 0x309d000030a0,
- 0x1b0010001b120,
- 0x1b1320001b133,
- 0x1b1500001b153,
- 0x1f2000001f201,
- ),
- 'Katakana': (
- 0x30a1000030fb,
- 0x30fd00003100,
- 0x31f000003200,
- 0x32d0000032ff,
- 0x330000003358,
- 0xff660000ff70,
- 0xff710000ff9e,
- 0x1aff00001aff4,
- 0x1aff50001affc,
- 0x1affd0001afff,
- 0x1b0000001b001,
- 0x1b1200001b123,
- 0x1b1550001b156,
- 0x1b1640001b168,
- ),
-}
-joining_types = {
- 0xad: 84,
- 0x300: 84,
- 0x301: 84,
- 0x302: 84,
- 0x303: 84,
- 0x304: 84,
- 0x305: 84,
- 0x306: 84,
- 0x307: 84,
- 0x308: 84,
- 0x309: 84,
- 0x30a: 84,
- 0x30b: 84,
- 0x30c: 84,
- 0x30d: 84,
- 0x30e: 84,
- 0x30f: 84,
- 0x310: 84,
- 0x311: 84,
- 0x312: 84,
- 0x313: 84,
- 0x314: 84,
- 0x315: 84,
- 0x316: 84,
- 0x317: 84,
- 0x318: 84,
- 0x319: 84,
- 0x31a: 84,
- 0x31b: 84,
- 0x31c: 84,
- 0x31d: 84,
- 0x31e: 84,
- 0x31f: 84,
- 0x320: 84,
- 0x321: 84,
- 0x322: 84,
- 0x323: 84,
- 0x324: 84,
- 0x325: 84,
- 0x326: 84,
- 0x327: 84,
- 0x328: 84,
- 0x329: 84,
- 0x32a: 84,
- 0x32b: 84,
- 0x32c: 84,
- 0x32d: 84,
- 0x32e: 84,
- 0x32f: 84,
- 0x330: 84,
- 0x331: 84,
- 0x332: 84,
- 0x333: 84,
- 0x334: 84,
- 0x335: 84,
- 0x336: 84,
- 0x337: 84,
- 0x338: 84,
- 0x339: 84,
- 0x33a: 84,
- 0x33b: 84,
- 0x33c: 84,
- 0x33d: 84,
- 0x33e: 84,
- 0x33f: 84,
- 0x340: 84,
- 0x341: 84,
- 0x342: 84,
- 0x343: 84,
- 0x344: 84,
- 0x345: 84,
- 0x346: 84,
- 0x347: 84,
- 0x348: 84,
- 0x349: 84,
- 0x34a: 84,
- 0x34b: 84,
- 0x34c: 84,
- 0x34d: 84,
- 0x34e: 84,
- 0x34f: 84,
- 0x350: 84,
- 0x351: 84,
- 0x352: 84,
- 0x353: 84,
- 0x354: 84,
- 0x355: 84,
- 0x356: 84,
- 0x357: 84,
- 0x358: 84,
- 0x359: 84,
- 0x35a: 84,
- 0x35b: 84,
- 0x35c: 84,
- 0x35d: 84,
- 0x35e: 84,
- 0x35f: 84,
- 0x360: 84,
- 0x361: 84,
- 0x362: 84,
- 0x363: 84,
- 0x364: 84,
- 0x365: 84,
- 0x366: 84,
- 0x367: 84,
- 0x368: 84,
- 0x369: 84,
- 0x36a: 84,
- 0x36b: 84,
- 0x36c: 84,
- 0x36d: 84,
- 0x36e: 84,
- 0x36f: 84,
- 0x483: 84,
- 0x484: 84,
- 0x485: 84,
- 0x486: 84,
- 0x487: 84,
- 0x488: 84,
- 0x489: 84,
- 0x591: 84,
- 0x592: 84,
- 0x593: 84,
- 0x594: 84,
- 0x595: 84,
- 0x596: 84,
- 0x597: 84,
- 0x598: 84,
- 0x599: 84,
- 0x59a: 84,
- 0x59b: 84,
- 0x59c: 84,
- 0x59d: 84,
- 0x59e: 84,
- 0x59f: 84,
- 0x5a0: 84,
- 0x5a1: 84,
- 0x5a2: 84,
- 0x5a3: 84,
- 0x5a4: 84,
- 0x5a5: 84,
- 0x5a6: 84,
- 0x5a7: 84,
- 0x5a8: 84,
- 0x5a9: 84,
- 0x5aa: 84,
- 0x5ab: 84,
- 0x5ac: 84,
- 0x5ad: 84,
- 0x5ae: 84,
- 0x5af: 84,
- 0x5b0: 84,
- 0x5b1: 84,
- 0x5b2: 84,
- 0x5b3: 84,
- 0x5b4: 84,
- 0x5b5: 84,
- 0x5b6: 84,
- 0x5b7: 84,
- 0x5b8: 84,
- 0x5b9: 84,
- 0x5ba: 84,
- 0x5bb: 84,
- 0x5bc: 84,
- 0x5bd: 84,
- 0x5bf: 84,
- 0x5c1: 84,
- 0x5c2: 84,
- 0x5c4: 84,
- 0x5c5: 84,
- 0x5c7: 84,
- 0x610: 84,
- 0x611: 84,
- 0x612: 84,
- 0x613: 84,
- 0x614: 84,
- 0x615: 84,
- 0x616: 84,
- 0x617: 84,
- 0x618: 84,
- 0x619: 84,
- 0x61a: 84,
- 0x61c: 84,
- 0x620: 68,
- 0x622: 82,
- 0x623: 82,
- 0x624: 82,
- 0x625: 82,
- 0x626: 68,
- 0x627: 82,
- 0x628: 68,
- 0x629: 82,
- 0x62a: 68,
- 0x62b: 68,
- 0x62c: 68,
- 0x62d: 68,
- 0x62e: 68,
- 0x62f: 82,
- 0x630: 82,
- 0x631: 82,
- 0x632: 82,
- 0x633: 68,
- 0x634: 68,
- 0x635: 68,
- 0x636: 68,
- 0x637: 68,
- 0x638: 68,
- 0x639: 68,
- 0x63a: 68,
- 0x63b: 68,
- 0x63c: 68,
- 0x63d: 68,
- 0x63e: 68,
- 0x63f: 68,
- 0x640: 67,
- 0x641: 68,
- 0x642: 68,
- 0x643: 68,
- 0x644: 68,
- 0x645: 68,
- 0x646: 68,
- 0x647: 68,
- 0x648: 82,
- 0x649: 68,
- 0x64a: 68,
- 0x64b: 84,
- 0x64c: 84,
- 0x64d: 84,
- 0x64e: 84,
- 0x64f: 84,
- 0x650: 84,
- 0x651: 84,
- 0x652: 84,
- 0x653: 84,
- 0x654: 84,
- 0x655: 84,
- 0x656: 84,
- 0x657: 84,
- 0x658: 84,
- 0x659: 84,
- 0x65a: 84,
- 0x65b: 84,
- 0x65c: 84,
- 0x65d: 84,
- 0x65e: 84,
- 0x65f: 84,
- 0x66e: 68,
- 0x66f: 68,
- 0x670: 84,
- 0x671: 82,
- 0x672: 82,
- 0x673: 82,
- 0x675: 82,
- 0x676: 82,
- 0x677: 82,
- 0x678: 68,
- 0x679: 68,
- 0x67a: 68,
- 0x67b: 68,
- 0x67c: 68,
- 0x67d: 68,
- 0x67e: 68,
- 0x67f: 68,
- 0x680: 68,
- 0x681: 68,
- 0x682: 68,
- 0x683: 68,
- 0x684: 68,
- 0x685: 68,
- 0x686: 68,
- 0x687: 68,
- 0x688: 82,
- 0x689: 82,
- 0x68a: 82,
- 0x68b: 82,
- 0x68c: 82,
- 0x68d: 82,
- 0x68e: 82,
- 0x68f: 82,
- 0x690: 82,
- 0x691: 82,
- 0x692: 82,
- 0x693: 82,
- 0x694: 82,
- 0x695: 82,
- 0x696: 82,
- 0x697: 82,
- 0x698: 82,
- 0x699: 82,
- 0x69a: 68,
- 0x69b: 68,
- 0x69c: 68,
- 0x69d: 68,
- 0x69e: 68,
- 0x69f: 68,
- 0x6a0: 68,
- 0x6a1: 68,
- 0x6a2: 68,
- 0x6a3: 68,
- 0x6a4: 68,
- 0x6a5: 68,
- 0x6a6: 68,
- 0x6a7: 68,
- 0x6a8: 68,
- 0x6a9: 68,
- 0x6aa: 68,
- 0x6ab: 68,
- 0x6ac: 68,
- 0x6ad: 68,
- 0x6ae: 68,
- 0x6af: 68,
- 0x6b0: 68,
- 0x6b1: 68,
- 0x6b2: 68,
- 0x6b3: 68,
- 0x6b4: 68,
- 0x6b5: 68,
- 0x6b6: 68,
- 0x6b7: 68,
- 0x6b8: 68,
- 0x6b9: 68,
- 0x6ba: 68,
- 0x6bb: 68,
- 0x6bc: 68,
- 0x6bd: 68,
- 0x6be: 68,
- 0x6bf: 68,
- 0x6c0: 82,
- 0x6c1: 68,
- 0x6c2: 68,
- 0x6c3: 82,
- 0x6c4: 82,
- 0x6c5: 82,
- 0x6c6: 82,
- 0x6c7: 82,
- 0x6c8: 82,
- 0x6c9: 82,
- 0x6ca: 82,
- 0x6cb: 82,
- 0x6cc: 68,
- 0x6cd: 82,
- 0x6ce: 68,
- 0x6cf: 82,
- 0x6d0: 68,
- 0x6d1: 68,
- 0x6d2: 82,
- 0x6d3: 82,
- 0x6d5: 82,
- 0x6d6: 84,
- 0x6d7: 84,
- 0x6d8: 84,
- 0x6d9: 84,
- 0x6da: 84,
- 0x6db: 84,
- 0x6dc: 84,
- 0x6df: 84,
- 0x6e0: 84,
- 0x6e1: 84,
- 0x6e2: 84,
- 0x6e3: 84,
- 0x6e4: 84,
- 0x6e7: 84,
- 0x6e8: 84,
- 0x6ea: 84,
- 0x6eb: 84,
- 0x6ec: 84,
- 0x6ed: 84,
- 0x6ee: 82,
- 0x6ef: 82,
- 0x6fa: 68,
- 0x6fb: 68,
- 0x6fc: 68,
- 0x6ff: 68,
- 0x70f: 84,
- 0x710: 82,
- 0x711: 84,
- 0x712: 68,
- 0x713: 68,
- 0x714: 68,
- 0x715: 82,
- 0x716: 82,
- 0x717: 82,
- 0x718: 82,
- 0x719: 82,
- 0x71a: 68,
- 0x71b: 68,
- 0x71c: 68,
- 0x71d: 68,
- 0x71e: 82,
- 0x71f: 68,
- 0x720: 68,
- 0x721: 68,
- 0x722: 68,
- 0x723: 68,
- 0x724: 68,
- 0x725: 68,
- 0x726: 68,
- 0x727: 68,
- 0x728: 82,
- 0x729: 68,
- 0x72a: 82,
- 0x72b: 68,
- 0x72c: 82,
- 0x72d: 68,
- 0x72e: 68,
- 0x72f: 82,
- 0x730: 84,
- 0x731: 84,
- 0x732: 84,
- 0x733: 84,
- 0x734: 84,
- 0x735: 84,
- 0x736: 84,
- 0x737: 84,
- 0x738: 84,
- 0x739: 84,
- 0x73a: 84,
- 0x73b: 84,
- 0x73c: 84,
- 0x73d: 84,
- 0x73e: 84,
- 0x73f: 84,
- 0x740: 84,
- 0x741: 84,
- 0x742: 84,
- 0x743: 84,
- 0x744: 84,
- 0x745: 84,
- 0x746: 84,
- 0x747: 84,
- 0x748: 84,
- 0x749: 84,
- 0x74a: 84,
- 0x74d: 82,
- 0x74e: 68,
- 0x74f: 68,
- 0x750: 68,
- 0x751: 68,
- 0x752: 68,
- 0x753: 68,
- 0x754: 68,
- 0x755: 68,
- 0x756: 68,
- 0x757: 68,
- 0x758: 68,
- 0x759: 82,
- 0x75a: 82,
- 0x75b: 82,
- 0x75c: 68,
- 0x75d: 68,
- 0x75e: 68,
- 0x75f: 68,
- 0x760: 68,
- 0x761: 68,
- 0x762: 68,
- 0x763: 68,
- 0x764: 68,
- 0x765: 68,
- 0x766: 68,
- 0x767: 68,
- 0x768: 68,
- 0x769: 68,
- 0x76a: 68,
- 0x76b: 82,
- 0x76c: 82,
- 0x76d: 68,
- 0x76e: 68,
- 0x76f: 68,
- 0x770: 68,
- 0x771: 82,
- 0x772: 68,
- 0x773: 82,
- 0x774: 82,
- 0x775: 68,
- 0x776: 68,
- 0x777: 68,
- 0x778: 82,
- 0x779: 82,
- 0x77a: 68,
- 0x77b: 68,
- 0x77c: 68,
- 0x77d: 68,
- 0x77e: 68,
- 0x77f: 68,
- 0x7a6: 84,
- 0x7a7: 84,
- 0x7a8: 84,
- 0x7a9: 84,
- 0x7aa: 84,
- 0x7ab: 84,
- 0x7ac: 84,
- 0x7ad: 84,
- 0x7ae: 84,
- 0x7af: 84,
- 0x7b0: 84,
- 0x7ca: 68,
- 0x7cb: 68,
- 0x7cc: 68,
- 0x7cd: 68,
- 0x7ce: 68,
- 0x7cf: 68,
- 0x7d0: 68,
- 0x7d1: 68,
- 0x7d2: 68,
- 0x7d3: 68,
- 0x7d4: 68,
- 0x7d5: 68,
- 0x7d6: 68,
- 0x7d7: 68,
- 0x7d8: 68,
- 0x7d9: 68,
- 0x7da: 68,
- 0x7db: 68,
- 0x7dc: 68,
- 0x7dd: 68,
- 0x7de: 68,
- 0x7df: 68,
- 0x7e0: 68,
- 0x7e1: 68,
- 0x7e2: 68,
- 0x7e3: 68,
- 0x7e4: 68,
- 0x7e5: 68,
- 0x7e6: 68,
- 0x7e7: 68,
- 0x7e8: 68,
- 0x7e9: 68,
- 0x7ea: 68,
- 0x7eb: 84,
- 0x7ec: 84,
- 0x7ed: 84,
- 0x7ee: 84,
- 0x7ef: 84,
- 0x7f0: 84,
- 0x7f1: 84,
- 0x7f2: 84,
- 0x7f3: 84,
- 0x7fa: 67,
- 0x7fd: 84,
- 0x816: 84,
- 0x817: 84,
- 0x818: 84,
- 0x819: 84,
- 0x81b: 84,
- 0x81c: 84,
- 0x81d: 84,
- 0x81e: 84,
- 0x81f: 84,
- 0x820: 84,
- 0x821: 84,
- 0x822: 84,
- 0x823: 84,
- 0x825: 84,
- 0x826: 84,
- 0x827: 84,
- 0x829: 84,
- 0x82a: 84,
- 0x82b: 84,
- 0x82c: 84,
- 0x82d: 84,
- 0x840: 82,
- 0x841: 68,
- 0x842: 68,
- 0x843: 68,
- 0x844: 68,
- 0x845: 68,
- 0x846: 82,
- 0x847: 82,
- 0x848: 68,
- 0x849: 82,
- 0x84a: 68,
- 0x84b: 68,
- 0x84c: 68,
- 0x84d: 68,
- 0x84e: 68,
- 0x84f: 68,
- 0x850: 68,
- 0x851: 68,
- 0x852: 68,
- 0x853: 68,
- 0x854: 82,
- 0x855: 68,
- 0x856: 82,
- 0x857: 82,
- 0x858: 82,
- 0x859: 84,
- 0x85a: 84,
- 0x85b: 84,
- 0x860: 68,
- 0x862: 68,
- 0x863: 68,
- 0x864: 68,
- 0x865: 68,
- 0x867: 82,
- 0x868: 68,
- 0x869: 82,
- 0x86a: 82,
- 0x870: 82,
- 0x871: 82,
- 0x872: 82,
- 0x873: 82,
- 0x874: 82,
- 0x875: 82,
- 0x876: 82,
- 0x877: 82,
- 0x878: 82,
- 0x879: 82,
- 0x87a: 82,
- 0x87b: 82,
- 0x87c: 82,
- 0x87d: 82,
- 0x87e: 82,
- 0x87f: 82,
- 0x880: 82,
- 0x881: 82,
- 0x882: 82,
- 0x883: 67,
- 0x884: 67,
- 0x885: 67,
- 0x886: 68,
- 0x889: 68,
- 0x88a: 68,
- 0x88b: 68,
- 0x88c: 68,
- 0x88d: 68,
- 0x88e: 82,
- 0x898: 84,
- 0x899: 84,
- 0x89a: 84,
- 0x89b: 84,
- 0x89c: 84,
- 0x89d: 84,
- 0x89e: 84,
- 0x89f: 84,
- 0x8a0: 68,
- 0x8a1: 68,
- 0x8a2: 68,
- 0x8a3: 68,
- 0x8a4: 68,
- 0x8a5: 68,
- 0x8a6: 68,
- 0x8a7: 68,
- 0x8a8: 68,
- 0x8a9: 68,
- 0x8aa: 82,
- 0x8ab: 82,
- 0x8ac: 82,
- 0x8ae: 82,
- 0x8af: 68,
- 0x8b0: 68,
- 0x8b1: 82,
- 0x8b2: 82,
- 0x8b3: 68,
- 0x8b4: 68,
- 0x8b5: 68,
- 0x8b6: 68,
- 0x8b7: 68,
- 0x8b8: 68,
- 0x8b9: 82,
- 0x8ba: 68,
- 0x8bb: 68,
- 0x8bc: 68,
- 0x8bd: 68,
- 0x8be: 68,
- 0x8bf: 68,
- 0x8c0: 68,
- 0x8c1: 68,
- 0x8c2: 68,
- 0x8c3: 68,
- 0x8c4: 68,
- 0x8c5: 68,
- 0x8c6: 68,
- 0x8c7: 68,
- 0x8c8: 68,
- 0x8ca: 84,
- 0x8cb: 84,
- 0x8cc: 84,
- 0x8cd: 84,
- 0x8ce: 84,
- 0x8cf: 84,
- 0x8d0: 84,
- 0x8d1: 84,
- 0x8d2: 84,
- 0x8d3: 84,
- 0x8d4: 84,
- 0x8d5: 84,
- 0x8d6: 84,
- 0x8d7: 84,
- 0x8d8: 84,
- 0x8d9: 84,
- 0x8da: 84,
- 0x8db: 84,
- 0x8dc: 84,
- 0x8dd: 84,
- 0x8de: 84,
- 0x8df: 84,
- 0x8e0: 84,
- 0x8e1: 84,
- 0x8e3: 84,
- 0x8e4: 84,
- 0x8e5: 84,
- 0x8e6: 84,
- 0x8e7: 84,
- 0x8e8: 84,
- 0x8e9: 84,
- 0x8ea: 84,
- 0x8eb: 84,
- 0x8ec: 84,
- 0x8ed: 84,
- 0x8ee: 84,
- 0x8ef: 84,
- 0x8f0: 84,
- 0x8f1: 84,
- 0x8f2: 84,
- 0x8f3: 84,
- 0x8f4: 84,
- 0x8f5: 84,
- 0x8f6: 84,
- 0x8f7: 84,
- 0x8f8: 84,
- 0x8f9: 84,
- 0x8fa: 84,
- 0x8fb: 84,
- 0x8fc: 84,
- 0x8fd: 84,
- 0x8fe: 84,
- 0x8ff: 84,
- 0x900: 84,
- 0x901: 84,
- 0x902: 84,
- 0x93a: 84,
- 0x93c: 84,
- 0x941: 84,
- 0x942: 84,
- 0x943: 84,
- 0x944: 84,
- 0x945: 84,
- 0x946: 84,
- 0x947: 84,
- 0x948: 84,
- 0x94d: 84,
- 0x951: 84,
- 0x952: 84,
- 0x953: 84,
- 0x954: 84,
- 0x955: 84,
- 0x956: 84,
- 0x957: 84,
- 0x962: 84,
- 0x963: 84,
- 0x981: 84,
- 0x9bc: 84,
- 0x9c1: 84,
- 0x9c2: 84,
- 0x9c3: 84,
- 0x9c4: 84,
- 0x9cd: 84,
- 0x9e2: 84,
- 0x9e3: 84,
- 0x9fe: 84,
- 0xa01: 84,
- 0xa02: 84,
- 0xa3c: 84,
- 0xa41: 84,
- 0xa42: 84,
- 0xa47: 84,
- 0xa48: 84,
- 0xa4b: 84,
- 0xa4c: 84,
- 0xa4d: 84,
- 0xa51: 84,
- 0xa70: 84,
- 0xa71: 84,
- 0xa75: 84,
- 0xa81: 84,
- 0xa82: 84,
- 0xabc: 84,
- 0xac1: 84,
- 0xac2: 84,
- 0xac3: 84,
- 0xac4: 84,
- 0xac5: 84,
- 0xac7: 84,
- 0xac8: 84,
- 0xacd: 84,
- 0xae2: 84,
- 0xae3: 84,
- 0xafa: 84,
- 0xafb: 84,
- 0xafc: 84,
- 0xafd: 84,
- 0xafe: 84,
- 0xaff: 84,
- 0xb01: 84,
- 0xb3c: 84,
- 0xb3f: 84,
- 0xb41: 84,
- 0xb42: 84,
- 0xb43: 84,
- 0xb44: 84,
- 0xb4d: 84,
- 0xb55: 84,
- 0xb56: 84,
- 0xb62: 84,
- 0xb63: 84,
- 0xb82: 84,
- 0xbc0: 84,
- 0xbcd: 84,
- 0xc00: 84,
- 0xc04: 84,
- 0xc3c: 84,
- 0xc3e: 84,
- 0xc3f: 84,
- 0xc40: 84,
- 0xc46: 84,
- 0xc47: 84,
- 0xc48: 84,
- 0xc4a: 84,
- 0xc4b: 84,
- 0xc4c: 84,
- 0xc4d: 84,
- 0xc55: 84,
- 0xc56: 84,
- 0xc62: 84,
- 0xc63: 84,
- 0xc81: 84,
- 0xcbc: 84,
- 0xcbf: 84,
- 0xcc6: 84,
- 0xccc: 84,
- 0xccd: 84,
- 0xce2: 84,
- 0xce3: 84,
- 0xd00: 84,
- 0xd01: 84,
- 0xd3b: 84,
- 0xd3c: 84,
- 0xd41: 84,
- 0xd42: 84,
- 0xd43: 84,
- 0xd44: 84,
- 0xd4d: 84,
- 0xd62: 84,
- 0xd63: 84,
- 0xd81: 84,
- 0xdca: 84,
- 0xdd2: 84,
- 0xdd3: 84,
- 0xdd4: 84,
- 0xdd6: 84,
- 0xe31: 84,
- 0xe34: 84,
- 0xe35: 84,
- 0xe36: 84,
- 0xe37: 84,
- 0xe38: 84,
- 0xe39: 84,
- 0xe3a: 84,
- 0xe47: 84,
- 0xe48: 84,
- 0xe49: 84,
- 0xe4a: 84,
- 0xe4b: 84,
- 0xe4c: 84,
- 0xe4d: 84,
- 0xe4e: 84,
- 0xeb1: 84,
- 0xeb4: 84,
- 0xeb5: 84,
- 0xeb6: 84,
- 0xeb7: 84,
- 0xeb8: 84,
- 0xeb9: 84,
- 0xeba: 84,
- 0xebb: 84,
- 0xebc: 84,
- 0xec8: 84,
- 0xec9: 84,
- 0xeca: 84,
- 0xecb: 84,
- 0xecc: 84,
- 0xecd: 84,
- 0xece: 84,
- 0xf18: 84,
- 0xf19: 84,
- 0xf35: 84,
- 0xf37: 84,
- 0xf39: 84,
- 0xf71: 84,
- 0xf72: 84,
- 0xf73: 84,
- 0xf74: 84,
- 0xf75: 84,
- 0xf76: 84,
- 0xf77: 84,
- 0xf78: 84,
- 0xf79: 84,
- 0xf7a: 84,
- 0xf7b: 84,
- 0xf7c: 84,
- 0xf7d: 84,
- 0xf7e: 84,
- 0xf80: 84,
- 0xf81: 84,
- 0xf82: 84,
- 0xf83: 84,
- 0xf84: 84,
- 0xf86: 84,
- 0xf87: 84,
- 0xf8d: 84,
- 0xf8e: 84,
- 0xf8f: 84,
- 0xf90: 84,
- 0xf91: 84,
- 0xf92: 84,
- 0xf93: 84,
- 0xf94: 84,
- 0xf95: 84,
- 0xf96: 84,
- 0xf97: 84,
- 0xf99: 84,
- 0xf9a: 84,
- 0xf9b: 84,
- 0xf9c: 84,
- 0xf9d: 84,
- 0xf9e: 84,
- 0xf9f: 84,
- 0xfa0: 84,
- 0xfa1: 84,
- 0xfa2: 84,
- 0xfa3: 84,
- 0xfa4: 84,
- 0xfa5: 84,
- 0xfa6: 84,
- 0xfa7: 84,
- 0xfa8: 84,
- 0xfa9: 84,
- 0xfaa: 84,
- 0xfab: 84,
- 0xfac: 84,
- 0xfad: 84,
- 0xfae: 84,
- 0xfaf: 84,
- 0xfb0: 84,
- 0xfb1: 84,
- 0xfb2: 84,
- 0xfb3: 84,
- 0xfb4: 84,
- 0xfb5: 84,
- 0xfb6: 84,
- 0xfb7: 84,
- 0xfb8: 84,
- 0xfb9: 84,
- 0xfba: 84,
- 0xfbb: 84,
- 0xfbc: 84,
- 0xfc6: 84,
- 0x102d: 84,
- 0x102e: 84,
- 0x102f: 84,
- 0x1030: 84,
- 0x1032: 84,
- 0x1033: 84,
- 0x1034: 84,
- 0x1035: 84,
- 0x1036: 84,
- 0x1037: 84,
- 0x1039: 84,
- 0x103a: 84,
- 0x103d: 84,
- 0x103e: 84,
- 0x1058: 84,
- 0x1059: 84,
- 0x105e: 84,
- 0x105f: 84,
- 0x1060: 84,
- 0x1071: 84,
- 0x1072: 84,
- 0x1073: 84,
- 0x1074: 84,
- 0x1082: 84,
- 0x1085: 84,
- 0x1086: 84,
- 0x108d: 84,
- 0x109d: 84,
- 0x135d: 84,
- 0x135e: 84,
- 0x135f: 84,
- 0x1712: 84,
- 0x1713: 84,
- 0x1714: 84,
- 0x1732: 84,
- 0x1733: 84,
- 0x1752: 84,
- 0x1753: 84,
- 0x1772: 84,
- 0x1773: 84,
- 0x17b4: 84,
- 0x17b5: 84,
- 0x17b7: 84,
- 0x17b8: 84,
- 0x17b9: 84,
- 0x17ba: 84,
- 0x17bb: 84,
- 0x17bc: 84,
- 0x17bd: 84,
- 0x17c6: 84,
- 0x17c9: 84,
- 0x17ca: 84,
- 0x17cb: 84,
- 0x17cc: 84,
- 0x17cd: 84,
- 0x17ce: 84,
- 0x17cf: 84,
- 0x17d0: 84,
- 0x17d1: 84,
- 0x17d2: 84,
- 0x17d3: 84,
- 0x17dd: 84,
- 0x1807: 68,
- 0x180a: 67,
- 0x180b: 84,
- 0x180c: 84,
- 0x180d: 84,
- 0x180f: 84,
- 0x1820: 68,
- 0x1821: 68,
- 0x1822: 68,
- 0x1823: 68,
- 0x1824: 68,
- 0x1825: 68,
- 0x1826: 68,
- 0x1827: 68,
- 0x1828: 68,
- 0x1829: 68,
- 0x182a: 68,
- 0x182b: 68,
- 0x182c: 68,
- 0x182d: 68,
- 0x182e: 68,
- 0x182f: 68,
- 0x1830: 68,
- 0x1831: 68,
- 0x1832: 68,
- 0x1833: 68,
- 0x1834: 68,
- 0x1835: 68,
- 0x1836: 68,
- 0x1837: 68,
- 0x1838: 68,
- 0x1839: 68,
- 0x183a: 68,
- 0x183b: 68,
- 0x183c: 68,
- 0x183d: 68,
- 0x183e: 68,
- 0x183f: 68,
- 0x1840: 68,
- 0x1841: 68,
- 0x1842: 68,
- 0x1843: 68,
- 0x1844: 68,
- 0x1845: 68,
- 0x1846: 68,
- 0x1847: 68,
- 0x1848: 68,
- 0x1849: 68,
- 0x184a: 68,
- 0x184b: 68,
- 0x184c: 68,
- 0x184d: 68,
- 0x184e: 68,
- 0x184f: 68,
- 0x1850: 68,
- 0x1851: 68,
- 0x1852: 68,
- 0x1853: 68,
- 0x1854: 68,
- 0x1855: 68,
- 0x1856: 68,
- 0x1857: 68,
- 0x1858: 68,
- 0x1859: 68,
- 0x185a: 68,
- 0x185b: 68,
- 0x185c: 68,
- 0x185d: 68,
- 0x185e: 68,
- 0x185f: 68,
- 0x1860: 68,
- 0x1861: 68,
- 0x1862: 68,
- 0x1863: 68,
- 0x1864: 68,
- 0x1865: 68,
- 0x1866: 68,
- 0x1867: 68,
- 0x1868: 68,
- 0x1869: 68,
- 0x186a: 68,
- 0x186b: 68,
- 0x186c: 68,
- 0x186d: 68,
- 0x186e: 68,
- 0x186f: 68,
- 0x1870: 68,
- 0x1871: 68,
- 0x1872: 68,
- 0x1873: 68,
- 0x1874: 68,
- 0x1875: 68,
- 0x1876: 68,
- 0x1877: 68,
- 0x1878: 68,
- 0x1885: 84,
- 0x1886: 84,
- 0x1887: 68,
- 0x1888: 68,
- 0x1889: 68,
- 0x188a: 68,
- 0x188b: 68,
- 0x188c: 68,
- 0x188d: 68,
- 0x188e: 68,
- 0x188f: 68,
- 0x1890: 68,
- 0x1891: 68,
- 0x1892: 68,
- 0x1893: 68,
- 0x1894: 68,
- 0x1895: 68,
- 0x1896: 68,
- 0x1897: 68,
- 0x1898: 68,
- 0x1899: 68,
- 0x189a: 68,
- 0x189b: 68,
- 0x189c: 68,
- 0x189d: 68,
- 0x189e: 68,
- 0x189f: 68,
- 0x18a0: 68,
- 0x18a1: 68,
- 0x18a2: 68,
- 0x18a3: 68,
- 0x18a4: 68,
- 0x18a5: 68,
- 0x18a6: 68,
- 0x18a7: 68,
- 0x18a8: 68,
- 0x18a9: 84,
- 0x18aa: 68,
- 0x1920: 84,
- 0x1921: 84,
- 0x1922: 84,
- 0x1927: 84,
- 0x1928: 84,
- 0x1932: 84,
- 0x1939: 84,
- 0x193a: 84,
- 0x193b: 84,
- 0x1a17: 84,
- 0x1a18: 84,
- 0x1a1b: 84,
- 0x1a56: 84,
- 0x1a58: 84,
- 0x1a59: 84,
- 0x1a5a: 84,
- 0x1a5b: 84,
- 0x1a5c: 84,
- 0x1a5d: 84,
- 0x1a5e: 84,
- 0x1a60: 84,
- 0x1a62: 84,
- 0x1a65: 84,
- 0x1a66: 84,
- 0x1a67: 84,
- 0x1a68: 84,
- 0x1a69: 84,
- 0x1a6a: 84,
- 0x1a6b: 84,
- 0x1a6c: 84,
- 0x1a73: 84,
- 0x1a74: 84,
- 0x1a75: 84,
- 0x1a76: 84,
- 0x1a77: 84,
- 0x1a78: 84,
- 0x1a79: 84,
- 0x1a7a: 84,
- 0x1a7b: 84,
- 0x1a7c: 84,
- 0x1a7f: 84,
- 0x1ab0: 84,
- 0x1ab1: 84,
- 0x1ab2: 84,
- 0x1ab3: 84,
- 0x1ab4: 84,
- 0x1ab5: 84,
- 0x1ab6: 84,
- 0x1ab7: 84,
- 0x1ab8: 84,
- 0x1ab9: 84,
- 0x1aba: 84,
- 0x1abb: 84,
- 0x1abc: 84,
- 0x1abd: 84,
- 0x1abe: 84,
- 0x1abf: 84,
- 0x1ac0: 84,
- 0x1ac1: 84,
- 0x1ac2: 84,
- 0x1ac3: 84,
- 0x1ac4: 84,
- 0x1ac5: 84,
- 0x1ac6: 84,
- 0x1ac7: 84,
- 0x1ac8: 84,
- 0x1ac9: 84,
- 0x1aca: 84,
- 0x1acb: 84,
- 0x1acc: 84,
- 0x1acd: 84,
- 0x1ace: 84,
- 0x1b00: 84,
- 0x1b01: 84,
- 0x1b02: 84,
- 0x1b03: 84,
- 0x1b34: 84,
- 0x1b36: 84,
- 0x1b37: 84,
- 0x1b38: 84,
- 0x1b39: 84,
- 0x1b3a: 84,
- 0x1b3c: 84,
- 0x1b42: 84,
- 0x1b6b: 84,
- 0x1b6c: 84,
- 0x1b6d: 84,
- 0x1b6e: 84,
- 0x1b6f: 84,
- 0x1b70: 84,
- 0x1b71: 84,
- 0x1b72: 84,
- 0x1b73: 84,
- 0x1b80: 84,
- 0x1b81: 84,
- 0x1ba2: 84,
- 0x1ba3: 84,
- 0x1ba4: 84,
- 0x1ba5: 84,
- 0x1ba8: 84,
- 0x1ba9: 84,
- 0x1bab: 84,
- 0x1bac: 84,
- 0x1bad: 84,
- 0x1be6: 84,
- 0x1be8: 84,
- 0x1be9: 84,
- 0x1bed: 84,
- 0x1bef: 84,
- 0x1bf0: 84,
- 0x1bf1: 84,
- 0x1c2c: 84,
- 0x1c2d: 84,
- 0x1c2e: 84,
- 0x1c2f: 84,
- 0x1c30: 84,
- 0x1c31: 84,
- 0x1c32: 84,
- 0x1c33: 84,
- 0x1c36: 84,
- 0x1c37: 84,
- 0x1cd0: 84,
- 0x1cd1: 84,
- 0x1cd2: 84,
- 0x1cd4: 84,
- 0x1cd5: 84,
- 0x1cd6: 84,
- 0x1cd7: 84,
- 0x1cd8: 84,
- 0x1cd9: 84,
- 0x1cda: 84,
- 0x1cdb: 84,
- 0x1cdc: 84,
- 0x1cdd: 84,
- 0x1cde: 84,
- 0x1cdf: 84,
- 0x1ce0: 84,
- 0x1ce2: 84,
- 0x1ce3: 84,
- 0x1ce4: 84,
- 0x1ce5: 84,
- 0x1ce6: 84,
- 0x1ce7: 84,
- 0x1ce8: 84,
- 0x1ced: 84,
- 0x1cf4: 84,
- 0x1cf8: 84,
- 0x1cf9: 84,
- 0x1dc0: 84,
- 0x1dc1: 84,
- 0x1dc2: 84,
- 0x1dc3: 84,
- 0x1dc4: 84,
- 0x1dc5: 84,
- 0x1dc6: 84,
- 0x1dc7: 84,
- 0x1dc8: 84,
- 0x1dc9: 84,
- 0x1dca: 84,
- 0x1dcb: 84,
- 0x1dcc: 84,
- 0x1dcd: 84,
- 0x1dce: 84,
- 0x1dcf: 84,
- 0x1dd0: 84,
- 0x1dd1: 84,
- 0x1dd2: 84,
- 0x1dd3: 84,
- 0x1dd4: 84,
- 0x1dd5: 84,
- 0x1dd6: 84,
- 0x1dd7: 84,
- 0x1dd8: 84,
- 0x1dd9: 84,
- 0x1dda: 84,
- 0x1ddb: 84,
- 0x1ddc: 84,
- 0x1ddd: 84,
- 0x1dde: 84,
- 0x1ddf: 84,
- 0x1de0: 84,
- 0x1de1: 84,
- 0x1de2: 84,
- 0x1de3: 84,
- 0x1de4: 84,
- 0x1de5: 84,
- 0x1de6: 84,
- 0x1de7: 84,
- 0x1de8: 84,
- 0x1de9: 84,
- 0x1dea: 84,
- 0x1deb: 84,
- 0x1dec: 84,
- 0x1ded: 84,
- 0x1dee: 84,
- 0x1def: 84,
- 0x1df0: 84,
- 0x1df1: 84,
- 0x1df2: 84,
- 0x1df3: 84,
- 0x1df4: 84,
- 0x1df5: 84,
- 0x1df6: 84,
- 0x1df7: 84,
- 0x1df8: 84,
- 0x1df9: 84,
- 0x1dfa: 84,
- 0x1dfb: 84,
- 0x1dfc: 84,
- 0x1dfd: 84,
- 0x1dfe: 84,
- 0x1dff: 84,
- 0x200b: 84,
- 0x200d: 67,
- 0x200e: 84,
- 0x200f: 84,
- 0x202a: 84,
- 0x202b: 84,
- 0x202c: 84,
- 0x202d: 84,
- 0x202e: 84,
- 0x2060: 84,
- 0x2061: 84,
- 0x2062: 84,
- 0x2063: 84,
- 0x2064: 84,
- 0x206a: 84,
- 0x206b: 84,
- 0x206c: 84,
- 0x206d: 84,
- 0x206e: 84,
- 0x206f: 84,
- 0x20d0: 84,
- 0x20d1: 84,
- 0x20d2: 84,
- 0x20d3: 84,
- 0x20d4: 84,
- 0x20d5: 84,
- 0x20d6: 84,
- 0x20d7: 84,
- 0x20d8: 84,
- 0x20d9: 84,
- 0x20da: 84,
- 0x20db: 84,
- 0x20dc: 84,
- 0x20dd: 84,
- 0x20de: 84,
- 0x20df: 84,
- 0x20e0: 84,
- 0x20e1: 84,
- 0x20e2: 84,
- 0x20e3: 84,
- 0x20e4: 84,
- 0x20e5: 84,
- 0x20e6: 84,
- 0x20e7: 84,
- 0x20e8: 84,
- 0x20e9: 84,
- 0x20ea: 84,
- 0x20eb: 84,
- 0x20ec: 84,
- 0x20ed: 84,
- 0x20ee: 84,
- 0x20ef: 84,
- 0x20f0: 84,
- 0x2cef: 84,
- 0x2cf0: 84,
- 0x2cf1: 84,
- 0x2d7f: 84,
- 0x2de0: 84,
- 0x2de1: 84,
- 0x2de2: 84,
- 0x2de3: 84,
- 0x2de4: 84,
- 0x2de5: 84,
- 0x2de6: 84,
- 0x2de7: 84,
- 0x2de8: 84,
- 0x2de9: 84,
- 0x2dea: 84,
- 0x2deb: 84,
- 0x2dec: 84,
- 0x2ded: 84,
- 0x2dee: 84,
- 0x2def: 84,
- 0x2df0: 84,
- 0x2df1: 84,
- 0x2df2: 84,
- 0x2df3: 84,
- 0x2df4: 84,
- 0x2df5: 84,
- 0x2df6: 84,
- 0x2df7: 84,
- 0x2df8: 84,
- 0x2df9: 84,
- 0x2dfa: 84,
- 0x2dfb: 84,
- 0x2dfc: 84,
- 0x2dfd: 84,
- 0x2dfe: 84,
- 0x2dff: 84,
- 0x302a: 84,
- 0x302b: 84,
- 0x302c: 84,
- 0x302d: 84,
- 0x3099: 84,
- 0x309a: 84,
- 0xa66f: 84,
- 0xa670: 84,
- 0xa671: 84,
- 0xa672: 84,
- 0xa674: 84,
- 0xa675: 84,
- 0xa676: 84,
- 0xa677: 84,
- 0xa678: 84,
- 0xa679: 84,
- 0xa67a: 84,
- 0xa67b: 84,
- 0xa67c: 84,
- 0xa67d: 84,
- 0xa69e: 84,
- 0xa69f: 84,
- 0xa6f0: 84,
- 0xa6f1: 84,
- 0xa802: 84,
- 0xa806: 84,
- 0xa80b: 84,
- 0xa825: 84,
- 0xa826: 84,
- 0xa82c: 84,
- 0xa840: 68,
- 0xa841: 68,
- 0xa842: 68,
- 0xa843: 68,
- 0xa844: 68,
- 0xa845: 68,
- 0xa846: 68,
- 0xa847: 68,
- 0xa848: 68,
- 0xa849: 68,
- 0xa84a: 68,
- 0xa84b: 68,
- 0xa84c: 68,
- 0xa84d: 68,
- 0xa84e: 68,
- 0xa84f: 68,
- 0xa850: 68,
- 0xa851: 68,
- 0xa852: 68,
- 0xa853: 68,
- 0xa854: 68,
- 0xa855: 68,
- 0xa856: 68,
- 0xa857: 68,
- 0xa858: 68,
- 0xa859: 68,
- 0xa85a: 68,
- 0xa85b: 68,
- 0xa85c: 68,
- 0xa85d: 68,
- 0xa85e: 68,
- 0xa85f: 68,
- 0xa860: 68,
- 0xa861: 68,
- 0xa862: 68,
- 0xa863: 68,
- 0xa864: 68,
- 0xa865: 68,
- 0xa866: 68,
- 0xa867: 68,
- 0xa868: 68,
- 0xa869: 68,
- 0xa86a: 68,
- 0xa86b: 68,
- 0xa86c: 68,
- 0xa86d: 68,
- 0xa86e: 68,
- 0xa86f: 68,
- 0xa870: 68,
- 0xa871: 68,
- 0xa872: 76,
- 0xa8c4: 84,
- 0xa8c5: 84,
- 0xa8e0: 84,
- 0xa8e1: 84,
- 0xa8e2: 84,
- 0xa8e3: 84,
- 0xa8e4: 84,
- 0xa8e5: 84,
- 0xa8e6: 84,
- 0xa8e7: 84,
- 0xa8e8: 84,
- 0xa8e9: 84,
- 0xa8ea: 84,
- 0xa8eb: 84,
- 0xa8ec: 84,
- 0xa8ed: 84,
- 0xa8ee: 84,
- 0xa8ef: 84,
- 0xa8f0: 84,
- 0xa8f1: 84,
- 0xa8ff: 84,
- 0xa926: 84,
- 0xa927: 84,
- 0xa928: 84,
- 0xa929: 84,
- 0xa92a: 84,
- 0xa92b: 84,
- 0xa92c: 84,
- 0xa92d: 84,
- 0xa947: 84,
- 0xa948: 84,
- 0xa949: 84,
- 0xa94a: 84,
- 0xa94b: 84,
- 0xa94c: 84,
- 0xa94d: 84,
- 0xa94e: 84,
- 0xa94f: 84,
- 0xa950: 84,
- 0xa951: 84,
- 0xa980: 84,
- 0xa981: 84,
- 0xa982: 84,
- 0xa9b3: 84,
- 0xa9b6: 84,
- 0xa9b7: 84,
- 0xa9b8: 84,
- 0xa9b9: 84,
- 0xa9bc: 84,
- 0xa9bd: 84,
- 0xa9e5: 84,
- 0xaa29: 84,
- 0xaa2a: 84,
- 0xaa2b: 84,
- 0xaa2c: 84,
- 0xaa2d: 84,
- 0xaa2e: 84,
- 0xaa31: 84,
- 0xaa32: 84,
- 0xaa35: 84,
- 0xaa36: 84,
- 0xaa43: 84,
- 0xaa4c: 84,
- 0xaa7c: 84,
- 0xaab0: 84,
- 0xaab2: 84,
- 0xaab3: 84,
- 0xaab4: 84,
- 0xaab7: 84,
- 0xaab8: 84,
- 0xaabe: 84,
- 0xaabf: 84,
- 0xaac1: 84,
- 0xaaec: 84,
- 0xaaed: 84,
- 0xaaf6: 84,
- 0xabe5: 84,
- 0xabe8: 84,
- 0xabed: 84,
- 0xfb1e: 84,
- 0xfe00: 84,
- 0xfe01: 84,
- 0xfe02: 84,
- 0xfe03: 84,
- 0xfe04: 84,
- 0xfe05: 84,
- 0xfe06: 84,
- 0xfe07: 84,
- 0xfe08: 84,
- 0xfe09: 84,
- 0xfe0a: 84,
- 0xfe0b: 84,
- 0xfe0c: 84,
- 0xfe0d: 84,
- 0xfe0e: 84,
- 0xfe0f: 84,
- 0xfe20: 84,
- 0xfe21: 84,
- 0xfe22: 84,
- 0xfe23: 84,
- 0xfe24: 84,
- 0xfe25: 84,
- 0xfe26: 84,
- 0xfe27: 84,
- 0xfe28: 84,
- 0xfe29: 84,
- 0xfe2a: 84,
- 0xfe2b: 84,
- 0xfe2c: 84,
- 0xfe2d: 84,
- 0xfe2e: 84,
- 0xfe2f: 84,
- 0xfeff: 84,
- 0xfff9: 84,
- 0xfffa: 84,
- 0xfffb: 84,
- 0x101fd: 84,
- 0x102e0: 84,
- 0x10376: 84,
- 0x10377: 84,
- 0x10378: 84,
- 0x10379: 84,
- 0x1037a: 84,
- 0x10a01: 84,
- 0x10a02: 84,
- 0x10a03: 84,
- 0x10a05: 84,
- 0x10a06: 84,
- 0x10a0c: 84,
- 0x10a0d: 84,
- 0x10a0e: 84,
- 0x10a0f: 84,
- 0x10a38: 84,
- 0x10a39: 84,
- 0x10a3a: 84,
- 0x10a3f: 84,
- 0x10ac0: 68,
- 0x10ac1: 68,
- 0x10ac2: 68,
- 0x10ac3: 68,
- 0x10ac4: 68,
- 0x10ac5: 82,
- 0x10ac7: 82,
- 0x10ac9: 82,
- 0x10aca: 82,
- 0x10acd: 76,
- 0x10ace: 82,
- 0x10acf: 82,
- 0x10ad0: 82,
- 0x10ad1: 82,
- 0x10ad2: 82,
- 0x10ad3: 68,
- 0x10ad4: 68,
- 0x10ad5: 68,
- 0x10ad6: 68,
- 0x10ad7: 76,
- 0x10ad8: 68,
- 0x10ad9: 68,
- 0x10ada: 68,
- 0x10adb: 68,
- 0x10adc: 68,
- 0x10add: 82,
- 0x10ade: 68,
- 0x10adf: 68,
- 0x10ae0: 68,
- 0x10ae1: 82,
- 0x10ae4: 82,
- 0x10ae5: 84,
- 0x10ae6: 84,
- 0x10aeb: 68,
- 0x10aec: 68,
- 0x10aed: 68,
- 0x10aee: 68,
- 0x10aef: 82,
- 0x10b80: 68,
- 0x10b81: 82,
- 0x10b82: 68,
- 0x10b83: 82,
- 0x10b84: 82,
- 0x10b85: 82,
- 0x10b86: 68,
- 0x10b87: 68,
- 0x10b88: 68,
- 0x10b89: 82,
- 0x10b8a: 68,
- 0x10b8b: 68,
- 0x10b8c: 82,
- 0x10b8d: 68,
- 0x10b8e: 82,
- 0x10b8f: 82,
- 0x10b90: 68,
- 0x10b91: 82,
- 0x10ba9: 82,
- 0x10baa: 82,
- 0x10bab: 82,
- 0x10bac: 82,
- 0x10bad: 68,
- 0x10bae: 68,
- 0x10d00: 76,
- 0x10d01: 68,
- 0x10d02: 68,
- 0x10d03: 68,
- 0x10d04: 68,
- 0x10d05: 68,
- 0x10d06: 68,
- 0x10d07: 68,
- 0x10d08: 68,
- 0x10d09: 68,
- 0x10d0a: 68,
- 0x10d0b: 68,
- 0x10d0c: 68,
- 0x10d0d: 68,
- 0x10d0e: 68,
- 0x10d0f: 68,
- 0x10d10: 68,
- 0x10d11: 68,
- 0x10d12: 68,
- 0x10d13: 68,
- 0x10d14: 68,
- 0x10d15: 68,
- 0x10d16: 68,
- 0x10d17: 68,
- 0x10d18: 68,
- 0x10d19: 68,
- 0x10d1a: 68,
- 0x10d1b: 68,
- 0x10d1c: 68,
- 0x10d1d: 68,
- 0x10d1e: 68,
- 0x10d1f: 68,
- 0x10d20: 68,
- 0x10d21: 68,
- 0x10d22: 82,
- 0x10d23: 68,
- 0x10d24: 84,
- 0x10d25: 84,
- 0x10d26: 84,
- 0x10d27: 84,
- 0x10eab: 84,
- 0x10eac: 84,
- 0x10efd: 84,
- 0x10efe: 84,
- 0x10eff: 84,
- 0x10f30: 68,
- 0x10f31: 68,
- 0x10f32: 68,
- 0x10f33: 82,
- 0x10f34: 68,
- 0x10f35: 68,
- 0x10f36: 68,
- 0x10f37: 68,
- 0x10f38: 68,
- 0x10f39: 68,
- 0x10f3a: 68,
- 0x10f3b: 68,
- 0x10f3c: 68,
- 0x10f3d: 68,
- 0x10f3e: 68,
- 0x10f3f: 68,
- 0x10f40: 68,
- 0x10f41: 68,
- 0x10f42: 68,
- 0x10f43: 68,
- 0x10f44: 68,
- 0x10f46: 84,
- 0x10f47: 84,
- 0x10f48: 84,
- 0x10f49: 84,
- 0x10f4a: 84,
- 0x10f4b: 84,
- 0x10f4c: 84,
- 0x10f4d: 84,
- 0x10f4e: 84,
- 0x10f4f: 84,
- 0x10f50: 84,
- 0x10f51: 68,
- 0x10f52: 68,
- 0x10f53: 68,
- 0x10f54: 82,
- 0x10f70: 68,
- 0x10f71: 68,
- 0x10f72: 68,
- 0x10f73: 68,
- 0x10f74: 82,
- 0x10f75: 82,
- 0x10f76: 68,
- 0x10f77: 68,
- 0x10f78: 68,
- 0x10f79: 68,
- 0x10f7a: 68,
- 0x10f7b: 68,
- 0x10f7c: 68,
- 0x10f7d: 68,
- 0x10f7e: 68,
- 0x10f7f: 68,
- 0x10f80: 68,
- 0x10f81: 68,
- 0x10f82: 84,
- 0x10f83: 84,
- 0x10f84: 84,
- 0x10f85: 84,
- 0x10fb0: 68,
- 0x10fb2: 68,
- 0x10fb3: 68,
- 0x10fb4: 82,
- 0x10fb5: 82,
- 0x10fb6: 82,
- 0x10fb8: 68,
- 0x10fb9: 82,
- 0x10fba: 82,
- 0x10fbb: 68,
- 0x10fbc: 68,
- 0x10fbd: 82,
- 0x10fbe: 68,
- 0x10fbf: 68,
- 0x10fc1: 68,
- 0x10fc2: 82,
- 0x10fc3: 82,
- 0x10fc4: 68,
- 0x10fc9: 82,
- 0x10fca: 68,
- 0x10fcb: 76,
- 0x11001: 84,
- 0x11038: 84,
- 0x11039: 84,
- 0x1103a: 84,
- 0x1103b: 84,
- 0x1103c: 84,
- 0x1103d: 84,
- 0x1103e: 84,
- 0x1103f: 84,
- 0x11040: 84,
- 0x11041: 84,
- 0x11042: 84,
- 0x11043: 84,
- 0x11044: 84,
- 0x11045: 84,
- 0x11046: 84,
- 0x11070: 84,
- 0x11073: 84,
- 0x11074: 84,
- 0x1107f: 84,
- 0x11080: 84,
- 0x11081: 84,
- 0x110b3: 84,
- 0x110b4: 84,
- 0x110b5: 84,
- 0x110b6: 84,
- 0x110b9: 84,
- 0x110ba: 84,
- 0x110c2: 84,
- 0x11100: 84,
- 0x11101: 84,
- 0x11102: 84,
- 0x11127: 84,
- 0x11128: 84,
- 0x11129: 84,
- 0x1112a: 84,
- 0x1112b: 84,
- 0x1112d: 84,
- 0x1112e: 84,
- 0x1112f: 84,
- 0x11130: 84,
- 0x11131: 84,
- 0x11132: 84,
- 0x11133: 84,
- 0x11134: 84,
- 0x11173: 84,
- 0x11180: 84,
- 0x11181: 84,
- 0x111b6: 84,
- 0x111b7: 84,
- 0x111b8: 84,
- 0x111b9: 84,
- 0x111ba: 84,
- 0x111bb: 84,
- 0x111bc: 84,
- 0x111bd: 84,
- 0x111be: 84,
- 0x111c9: 84,
- 0x111ca: 84,
- 0x111cb: 84,
- 0x111cc: 84,
- 0x111cf: 84,
- 0x1122f: 84,
- 0x11230: 84,
- 0x11231: 84,
- 0x11234: 84,
- 0x11236: 84,
- 0x11237: 84,
- 0x1123e: 84,
- 0x11241: 84,
- 0x112df: 84,
- 0x112e3: 84,
- 0x112e4: 84,
- 0x112e5: 84,
- 0x112e6: 84,
- 0x112e7: 84,
- 0x112e8: 84,
- 0x112e9: 84,
- 0x112ea: 84,
- 0x11300: 84,
- 0x11301: 84,
- 0x1133b: 84,
- 0x1133c: 84,
- 0x11340: 84,
- 0x11366: 84,
- 0x11367: 84,
- 0x11368: 84,
- 0x11369: 84,
- 0x1136a: 84,
- 0x1136b: 84,
- 0x1136c: 84,
- 0x11370: 84,
- 0x11371: 84,
- 0x11372: 84,
- 0x11373: 84,
- 0x11374: 84,
- 0x11438: 84,
- 0x11439: 84,
- 0x1143a: 84,
- 0x1143b: 84,
- 0x1143c: 84,
- 0x1143d: 84,
- 0x1143e: 84,
- 0x1143f: 84,
- 0x11442: 84,
- 0x11443: 84,
- 0x11444: 84,
- 0x11446: 84,
- 0x1145e: 84,
- 0x114b3: 84,
- 0x114b4: 84,
- 0x114b5: 84,
- 0x114b6: 84,
- 0x114b7: 84,
- 0x114b8: 84,
- 0x114ba: 84,
- 0x114bf: 84,
- 0x114c0: 84,
- 0x114c2: 84,
- 0x114c3: 84,
- 0x115b2: 84,
- 0x115b3: 84,
- 0x115b4: 84,
- 0x115b5: 84,
- 0x115bc: 84,
- 0x115bd: 84,
- 0x115bf: 84,
- 0x115c0: 84,
- 0x115dc: 84,
- 0x115dd: 84,
- 0x11633: 84,
- 0x11634: 84,
- 0x11635: 84,
- 0x11636: 84,
- 0x11637: 84,
- 0x11638: 84,
- 0x11639: 84,
- 0x1163a: 84,
- 0x1163d: 84,
- 0x1163f: 84,
- 0x11640: 84,
- 0x116ab: 84,
- 0x116ad: 84,
- 0x116b0: 84,
- 0x116b1: 84,
- 0x116b2: 84,
- 0x116b3: 84,
- 0x116b4: 84,
- 0x116b5: 84,
- 0x116b7: 84,
- 0x1171d: 84,
- 0x1171e: 84,
- 0x1171f: 84,
- 0x11722: 84,
- 0x11723: 84,
- 0x11724: 84,
- 0x11725: 84,
- 0x11727: 84,
- 0x11728: 84,
- 0x11729: 84,
- 0x1172a: 84,
- 0x1172b: 84,
- 0x1182f: 84,
- 0x11830: 84,
- 0x11831: 84,
- 0x11832: 84,
- 0x11833: 84,
- 0x11834: 84,
- 0x11835: 84,
- 0x11836: 84,
- 0x11837: 84,
- 0x11839: 84,
- 0x1183a: 84,
- 0x1193b: 84,
- 0x1193c: 84,
- 0x1193e: 84,
- 0x11943: 84,
- 0x119d4: 84,
- 0x119d5: 84,
- 0x119d6: 84,
- 0x119d7: 84,
- 0x119da: 84,
- 0x119db: 84,
- 0x119e0: 84,
- 0x11a01: 84,
- 0x11a02: 84,
- 0x11a03: 84,
- 0x11a04: 84,
- 0x11a05: 84,
- 0x11a06: 84,
- 0x11a07: 84,
- 0x11a08: 84,
- 0x11a09: 84,
- 0x11a0a: 84,
- 0x11a33: 84,
- 0x11a34: 84,
- 0x11a35: 84,
- 0x11a36: 84,
- 0x11a37: 84,
- 0x11a38: 84,
- 0x11a3b: 84,
- 0x11a3c: 84,
- 0x11a3d: 84,
- 0x11a3e: 84,
- 0x11a47: 84,
- 0x11a51: 84,
- 0x11a52: 84,
- 0x11a53: 84,
- 0x11a54: 84,
- 0x11a55: 84,
- 0x11a56: 84,
- 0x11a59: 84,
- 0x11a5a: 84,
- 0x11a5b: 84,
- 0x11a8a: 84,
- 0x11a8b: 84,
- 0x11a8c: 84,
- 0x11a8d: 84,
- 0x11a8e: 84,
- 0x11a8f: 84,
- 0x11a90: 84,
- 0x11a91: 84,
- 0x11a92: 84,
- 0x11a93: 84,
- 0x11a94: 84,
- 0x11a95: 84,
- 0x11a96: 84,
- 0x11a98: 84,
- 0x11a99: 84,
- 0x11c30: 84,
- 0x11c31: 84,
- 0x11c32: 84,
- 0x11c33: 84,
- 0x11c34: 84,
- 0x11c35: 84,
- 0x11c36: 84,
- 0x11c38: 84,
- 0x11c39: 84,
- 0x11c3a: 84,
- 0x11c3b: 84,
- 0x11c3c: 84,
- 0x11c3d: 84,
- 0x11c3f: 84,
- 0x11c92: 84,
- 0x11c93: 84,
- 0x11c94: 84,
- 0x11c95: 84,
- 0x11c96: 84,
- 0x11c97: 84,
- 0x11c98: 84,
- 0x11c99: 84,
- 0x11c9a: 84,
- 0x11c9b: 84,
- 0x11c9c: 84,
- 0x11c9d: 84,
- 0x11c9e: 84,
- 0x11c9f: 84,
- 0x11ca0: 84,
- 0x11ca1: 84,
- 0x11ca2: 84,
- 0x11ca3: 84,
- 0x11ca4: 84,
- 0x11ca5: 84,
- 0x11ca6: 84,
- 0x11ca7: 84,
- 0x11caa: 84,
- 0x11cab: 84,
- 0x11cac: 84,
- 0x11cad: 84,
- 0x11cae: 84,
- 0x11caf: 84,
- 0x11cb0: 84,
- 0x11cb2: 84,
- 0x11cb3: 84,
- 0x11cb5: 84,
- 0x11cb6: 84,
- 0x11d31: 84,
- 0x11d32: 84,
- 0x11d33: 84,
- 0x11d34: 84,
- 0x11d35: 84,
- 0x11d36: 84,
- 0x11d3a: 84,
- 0x11d3c: 84,
- 0x11d3d: 84,
- 0x11d3f: 84,
- 0x11d40: 84,
- 0x11d41: 84,
- 0x11d42: 84,
- 0x11d43: 84,
- 0x11d44: 84,
- 0x11d45: 84,
- 0x11d47: 84,
- 0x11d90: 84,
- 0x11d91: 84,
- 0x11d95: 84,
- 0x11d97: 84,
- 0x11ef3: 84,
- 0x11ef4: 84,
- 0x11f00: 84,
- 0x11f01: 84,
- 0x11f36: 84,
- 0x11f37: 84,
- 0x11f38: 84,
- 0x11f39: 84,
- 0x11f3a: 84,
- 0x11f40: 84,
- 0x11f42: 84,
- 0x13430: 84,
- 0x13431: 84,
- 0x13432: 84,
- 0x13433: 84,
- 0x13434: 84,
- 0x13435: 84,
- 0x13436: 84,
- 0x13437: 84,
- 0x13438: 84,
- 0x13439: 84,
- 0x1343a: 84,
- 0x1343b: 84,
- 0x1343c: 84,
- 0x1343d: 84,
- 0x1343e: 84,
- 0x1343f: 84,
- 0x13440: 84,
- 0x13447: 84,
- 0x13448: 84,
- 0x13449: 84,
- 0x1344a: 84,
- 0x1344b: 84,
- 0x1344c: 84,
- 0x1344d: 84,
- 0x1344e: 84,
- 0x1344f: 84,
- 0x13450: 84,
- 0x13451: 84,
- 0x13452: 84,
- 0x13453: 84,
- 0x13454: 84,
- 0x13455: 84,
- 0x16af0: 84,
- 0x16af1: 84,
- 0x16af2: 84,
- 0x16af3: 84,
- 0x16af4: 84,
- 0x16b30: 84,
- 0x16b31: 84,
- 0x16b32: 84,
- 0x16b33: 84,
- 0x16b34: 84,
- 0x16b35: 84,
- 0x16b36: 84,
- 0x16f4f: 84,
- 0x16f8f: 84,
- 0x16f90: 84,
- 0x16f91: 84,
- 0x16f92: 84,
- 0x16fe4: 84,
- 0x1bc9d: 84,
- 0x1bc9e: 84,
- 0x1bca0: 84,
- 0x1bca1: 84,
- 0x1bca2: 84,
- 0x1bca3: 84,
- 0x1cf00: 84,
- 0x1cf01: 84,
- 0x1cf02: 84,
- 0x1cf03: 84,
- 0x1cf04: 84,
- 0x1cf05: 84,
- 0x1cf06: 84,
- 0x1cf07: 84,
- 0x1cf08: 84,
- 0x1cf09: 84,
- 0x1cf0a: 84,
- 0x1cf0b: 84,
- 0x1cf0c: 84,
- 0x1cf0d: 84,
- 0x1cf0e: 84,
- 0x1cf0f: 84,
- 0x1cf10: 84,
- 0x1cf11: 84,
- 0x1cf12: 84,
- 0x1cf13: 84,
- 0x1cf14: 84,
- 0x1cf15: 84,
- 0x1cf16: 84,
- 0x1cf17: 84,
- 0x1cf18: 84,
- 0x1cf19: 84,
- 0x1cf1a: 84,
- 0x1cf1b: 84,
- 0x1cf1c: 84,
- 0x1cf1d: 84,
- 0x1cf1e: 84,
- 0x1cf1f: 84,
- 0x1cf20: 84,
- 0x1cf21: 84,
- 0x1cf22: 84,
- 0x1cf23: 84,
- 0x1cf24: 84,
- 0x1cf25: 84,
- 0x1cf26: 84,
- 0x1cf27: 84,
- 0x1cf28: 84,
- 0x1cf29: 84,
- 0x1cf2a: 84,
- 0x1cf2b: 84,
- 0x1cf2c: 84,
- 0x1cf2d: 84,
- 0x1cf30: 84,
- 0x1cf31: 84,
- 0x1cf32: 84,
- 0x1cf33: 84,
- 0x1cf34: 84,
- 0x1cf35: 84,
- 0x1cf36: 84,
- 0x1cf37: 84,
- 0x1cf38: 84,
- 0x1cf39: 84,
- 0x1cf3a: 84,
- 0x1cf3b: 84,
- 0x1cf3c: 84,
- 0x1cf3d: 84,
- 0x1cf3e: 84,
- 0x1cf3f: 84,
- 0x1cf40: 84,
- 0x1cf41: 84,
- 0x1cf42: 84,
- 0x1cf43: 84,
- 0x1cf44: 84,
- 0x1cf45: 84,
- 0x1cf46: 84,
- 0x1d167: 84,
- 0x1d168: 84,
- 0x1d169: 84,
- 0x1d173: 84,
- 0x1d174: 84,
- 0x1d175: 84,
- 0x1d176: 84,
- 0x1d177: 84,
- 0x1d178: 84,
- 0x1d179: 84,
- 0x1d17a: 84,
- 0x1d17b: 84,
- 0x1d17c: 84,
- 0x1d17d: 84,
- 0x1d17e: 84,
- 0x1d17f: 84,
- 0x1d180: 84,
- 0x1d181: 84,
- 0x1d182: 84,
- 0x1d185: 84,
- 0x1d186: 84,
- 0x1d187: 84,
- 0x1d188: 84,
- 0x1d189: 84,
- 0x1d18a: 84,
- 0x1d18b: 84,
- 0x1d1aa: 84,
- 0x1d1ab: 84,
- 0x1d1ac: 84,
- 0x1d1ad: 84,
- 0x1d242: 84,
- 0x1d243: 84,
- 0x1d244: 84,
- 0x1da00: 84,
- 0x1da01: 84,
- 0x1da02: 84,
- 0x1da03: 84,
- 0x1da04: 84,
- 0x1da05: 84,
- 0x1da06: 84,
- 0x1da07: 84,
- 0x1da08: 84,
- 0x1da09: 84,
- 0x1da0a: 84,
- 0x1da0b: 84,
- 0x1da0c: 84,
- 0x1da0d: 84,
- 0x1da0e: 84,
- 0x1da0f: 84,
- 0x1da10: 84,
- 0x1da11: 84,
- 0x1da12: 84,
- 0x1da13: 84,
- 0x1da14: 84,
- 0x1da15: 84,
- 0x1da16: 84,
- 0x1da17: 84,
- 0x1da18: 84,
- 0x1da19: 84,
- 0x1da1a: 84,
- 0x1da1b: 84,
- 0x1da1c: 84,
- 0x1da1d: 84,
- 0x1da1e: 84,
- 0x1da1f: 84,
- 0x1da20: 84,
- 0x1da21: 84,
- 0x1da22: 84,
- 0x1da23: 84,
- 0x1da24: 84,
- 0x1da25: 84,
- 0x1da26: 84,
- 0x1da27: 84,
- 0x1da28: 84,
- 0x1da29: 84,
- 0x1da2a: 84,
- 0x1da2b: 84,
- 0x1da2c: 84,
- 0x1da2d: 84,
- 0x1da2e: 84,
- 0x1da2f: 84,
- 0x1da30: 84,
- 0x1da31: 84,
- 0x1da32: 84,
- 0x1da33: 84,
- 0x1da34: 84,
- 0x1da35: 84,
- 0x1da36: 84,
- 0x1da3b: 84,
- 0x1da3c: 84,
- 0x1da3d: 84,
- 0x1da3e: 84,
- 0x1da3f: 84,
- 0x1da40: 84,
- 0x1da41: 84,
- 0x1da42: 84,
- 0x1da43: 84,
- 0x1da44: 84,
- 0x1da45: 84,
- 0x1da46: 84,
- 0x1da47: 84,
- 0x1da48: 84,
- 0x1da49: 84,
- 0x1da4a: 84,
- 0x1da4b: 84,
- 0x1da4c: 84,
- 0x1da4d: 84,
- 0x1da4e: 84,
- 0x1da4f: 84,
- 0x1da50: 84,
- 0x1da51: 84,
- 0x1da52: 84,
- 0x1da53: 84,
- 0x1da54: 84,
- 0x1da55: 84,
- 0x1da56: 84,
- 0x1da57: 84,
- 0x1da58: 84,
- 0x1da59: 84,
- 0x1da5a: 84,
- 0x1da5b: 84,
- 0x1da5c: 84,
- 0x1da5d: 84,
- 0x1da5e: 84,
- 0x1da5f: 84,
- 0x1da60: 84,
- 0x1da61: 84,
- 0x1da62: 84,
- 0x1da63: 84,
- 0x1da64: 84,
- 0x1da65: 84,
- 0x1da66: 84,
- 0x1da67: 84,
- 0x1da68: 84,
- 0x1da69: 84,
- 0x1da6a: 84,
- 0x1da6b: 84,
- 0x1da6c: 84,
- 0x1da75: 84,
- 0x1da84: 84,
- 0x1da9b: 84,
- 0x1da9c: 84,
- 0x1da9d: 84,
- 0x1da9e: 84,
- 0x1da9f: 84,
- 0x1daa1: 84,
- 0x1daa2: 84,
- 0x1daa3: 84,
- 0x1daa4: 84,
- 0x1daa5: 84,
- 0x1daa6: 84,
- 0x1daa7: 84,
- 0x1daa8: 84,
- 0x1daa9: 84,
- 0x1daaa: 84,
- 0x1daab: 84,
- 0x1daac: 84,
- 0x1daad: 84,
- 0x1daae: 84,
- 0x1daaf: 84,
- 0x1e000: 84,
- 0x1e001: 84,
- 0x1e002: 84,
- 0x1e003: 84,
- 0x1e004: 84,
- 0x1e005: 84,
- 0x1e006: 84,
- 0x1e008: 84,
- 0x1e009: 84,
- 0x1e00a: 84,
- 0x1e00b: 84,
- 0x1e00c: 84,
- 0x1e00d: 84,
- 0x1e00e: 84,
- 0x1e00f: 84,
- 0x1e010: 84,
- 0x1e011: 84,
- 0x1e012: 84,
- 0x1e013: 84,
- 0x1e014: 84,
- 0x1e015: 84,
- 0x1e016: 84,
- 0x1e017: 84,
- 0x1e018: 84,
- 0x1e01b: 84,
- 0x1e01c: 84,
- 0x1e01d: 84,
- 0x1e01e: 84,
- 0x1e01f: 84,
- 0x1e020: 84,
- 0x1e021: 84,
- 0x1e023: 84,
- 0x1e024: 84,
- 0x1e026: 84,
- 0x1e027: 84,
- 0x1e028: 84,
- 0x1e029: 84,
- 0x1e02a: 84,
- 0x1e08f: 84,
- 0x1e130: 84,
- 0x1e131: 84,
- 0x1e132: 84,
- 0x1e133: 84,
- 0x1e134: 84,
- 0x1e135: 84,
- 0x1e136: 84,
- 0x1e2ae: 84,
- 0x1e2ec: 84,
- 0x1e2ed: 84,
- 0x1e2ee: 84,
- 0x1e2ef: 84,
- 0x1e4ec: 84,
- 0x1e4ed: 84,
- 0x1e4ee: 84,
- 0x1e4ef: 84,
- 0x1e8d0: 84,
- 0x1e8d1: 84,
- 0x1e8d2: 84,
- 0x1e8d3: 84,
- 0x1e8d4: 84,
- 0x1e8d5: 84,
- 0x1e8d6: 84,
- 0x1e900: 68,
- 0x1e901: 68,
- 0x1e902: 68,
- 0x1e903: 68,
- 0x1e904: 68,
- 0x1e905: 68,
- 0x1e906: 68,
- 0x1e907: 68,
- 0x1e908: 68,
- 0x1e909: 68,
- 0x1e90a: 68,
- 0x1e90b: 68,
- 0x1e90c: 68,
- 0x1e90d: 68,
- 0x1e90e: 68,
- 0x1e90f: 68,
- 0x1e910: 68,
- 0x1e911: 68,
- 0x1e912: 68,
- 0x1e913: 68,
- 0x1e914: 68,
- 0x1e915: 68,
- 0x1e916: 68,
- 0x1e917: 68,
- 0x1e918: 68,
- 0x1e919: 68,
- 0x1e91a: 68,
- 0x1e91b: 68,
- 0x1e91c: 68,
- 0x1e91d: 68,
- 0x1e91e: 68,
- 0x1e91f: 68,
- 0x1e920: 68,
- 0x1e921: 68,
- 0x1e922: 68,
- 0x1e923: 68,
- 0x1e924: 68,
- 0x1e925: 68,
- 0x1e926: 68,
- 0x1e927: 68,
- 0x1e928: 68,
- 0x1e929: 68,
- 0x1e92a: 68,
- 0x1e92b: 68,
- 0x1e92c: 68,
- 0x1e92d: 68,
- 0x1e92e: 68,
- 0x1e92f: 68,
- 0x1e930: 68,
- 0x1e931: 68,
- 0x1e932: 68,
- 0x1e933: 68,
- 0x1e934: 68,
- 0x1e935: 68,
- 0x1e936: 68,
- 0x1e937: 68,
- 0x1e938: 68,
- 0x1e939: 68,
- 0x1e93a: 68,
- 0x1e93b: 68,
- 0x1e93c: 68,
- 0x1e93d: 68,
- 0x1e93e: 68,
- 0x1e93f: 68,
- 0x1e940: 68,
- 0x1e941: 68,
- 0x1e942: 68,
- 0x1e943: 68,
- 0x1e944: 84,
- 0x1e945: 84,
- 0x1e946: 84,
- 0x1e947: 84,
- 0x1e948: 84,
- 0x1e949: 84,
- 0x1e94a: 84,
- 0x1e94b: 84,
- 0xe0001: 84,
- 0xe0020: 84,
- 0xe0021: 84,
- 0xe0022: 84,
- 0xe0023: 84,
- 0xe0024: 84,
- 0xe0025: 84,
- 0xe0026: 84,
- 0xe0027: 84,
- 0xe0028: 84,
- 0xe0029: 84,
- 0xe002a: 84,
- 0xe002b: 84,
- 0xe002c: 84,
- 0xe002d: 84,
- 0xe002e: 84,
- 0xe002f: 84,
- 0xe0030: 84,
- 0xe0031: 84,
- 0xe0032: 84,
- 0xe0033: 84,
- 0xe0034: 84,
- 0xe0035: 84,
- 0xe0036: 84,
- 0xe0037: 84,
- 0xe0038: 84,
- 0xe0039: 84,
- 0xe003a: 84,
- 0xe003b: 84,
- 0xe003c: 84,
- 0xe003d: 84,
- 0xe003e: 84,
- 0xe003f: 84,
- 0xe0040: 84,
- 0xe0041: 84,
- 0xe0042: 84,
- 0xe0043: 84,
- 0xe0044: 84,
- 0xe0045: 84,
- 0xe0046: 84,
- 0xe0047: 84,
- 0xe0048: 84,
- 0xe0049: 84,
- 0xe004a: 84,
- 0xe004b: 84,
- 0xe004c: 84,
- 0xe004d: 84,
- 0xe004e: 84,
- 0xe004f: 84,
- 0xe0050: 84,
- 0xe0051: 84,
- 0xe0052: 84,
- 0xe0053: 84,
- 0xe0054: 84,
- 0xe0055: 84,
- 0xe0056: 84,
- 0xe0057: 84,
- 0xe0058: 84,
- 0xe0059: 84,
- 0xe005a: 84,
- 0xe005b: 84,
- 0xe005c: 84,
- 0xe005d: 84,
- 0xe005e: 84,
- 0xe005f: 84,
- 0xe0060: 84,
- 0xe0061: 84,
- 0xe0062: 84,
- 0xe0063: 84,
- 0xe0064: 84,
- 0xe0065: 84,
- 0xe0066: 84,
- 0xe0067: 84,
- 0xe0068: 84,
- 0xe0069: 84,
- 0xe006a: 84,
- 0xe006b: 84,
- 0xe006c: 84,
- 0xe006d: 84,
- 0xe006e: 84,
- 0xe006f: 84,
- 0xe0070: 84,
- 0xe0071: 84,
- 0xe0072: 84,
- 0xe0073: 84,
- 0xe0074: 84,
- 0xe0075: 84,
- 0xe0076: 84,
- 0xe0077: 84,
- 0xe0078: 84,
- 0xe0079: 84,
- 0xe007a: 84,
- 0xe007b: 84,
- 0xe007c: 84,
- 0xe007d: 84,
- 0xe007e: 84,
- 0xe007f: 84,
- 0xe0100: 84,
- 0xe0101: 84,
- 0xe0102: 84,
- 0xe0103: 84,
- 0xe0104: 84,
- 0xe0105: 84,
- 0xe0106: 84,
- 0xe0107: 84,
- 0xe0108: 84,
- 0xe0109: 84,
- 0xe010a: 84,
- 0xe010b: 84,
- 0xe010c: 84,
- 0xe010d: 84,
- 0xe010e: 84,
- 0xe010f: 84,
- 0xe0110: 84,
- 0xe0111: 84,
- 0xe0112: 84,
- 0xe0113: 84,
- 0xe0114: 84,
- 0xe0115: 84,
- 0xe0116: 84,
- 0xe0117: 84,
- 0xe0118: 84,
- 0xe0119: 84,
- 0xe011a: 84,
- 0xe011b: 84,
- 0xe011c: 84,
- 0xe011d: 84,
- 0xe011e: 84,
- 0xe011f: 84,
- 0xe0120: 84,
- 0xe0121: 84,
- 0xe0122: 84,
- 0xe0123: 84,
- 0xe0124: 84,
- 0xe0125: 84,
- 0xe0126: 84,
- 0xe0127: 84,
- 0xe0128: 84,
- 0xe0129: 84,
- 0xe012a: 84,
- 0xe012b: 84,
- 0xe012c: 84,
- 0xe012d: 84,
- 0xe012e: 84,
- 0xe012f: 84,
- 0xe0130: 84,
- 0xe0131: 84,
- 0xe0132: 84,
- 0xe0133: 84,
- 0xe0134: 84,
- 0xe0135: 84,
- 0xe0136: 84,
- 0xe0137: 84,
- 0xe0138: 84,
- 0xe0139: 84,
- 0xe013a: 84,
- 0xe013b: 84,
- 0xe013c: 84,
- 0xe013d: 84,
- 0xe013e: 84,
- 0xe013f: 84,
- 0xe0140: 84,
- 0xe0141: 84,
- 0xe0142: 84,
- 0xe0143: 84,
- 0xe0144: 84,
- 0xe0145: 84,
- 0xe0146: 84,
- 0xe0147: 84,
- 0xe0148: 84,
- 0xe0149: 84,
- 0xe014a: 84,
- 0xe014b: 84,
- 0xe014c: 84,
- 0xe014d: 84,
- 0xe014e: 84,
- 0xe014f: 84,
- 0xe0150: 84,
- 0xe0151: 84,
- 0xe0152: 84,
- 0xe0153: 84,
- 0xe0154: 84,
- 0xe0155: 84,
- 0xe0156: 84,
- 0xe0157: 84,
- 0xe0158: 84,
- 0xe0159: 84,
- 0xe015a: 84,
- 0xe015b: 84,
- 0xe015c: 84,
- 0xe015d: 84,
- 0xe015e: 84,
- 0xe015f: 84,
- 0xe0160: 84,
- 0xe0161: 84,
- 0xe0162: 84,
- 0xe0163: 84,
- 0xe0164: 84,
- 0xe0165: 84,
- 0xe0166: 84,
- 0xe0167: 84,
- 0xe0168: 84,
- 0xe0169: 84,
- 0xe016a: 84,
- 0xe016b: 84,
- 0xe016c: 84,
- 0xe016d: 84,
- 0xe016e: 84,
- 0xe016f: 84,
- 0xe0170: 84,
- 0xe0171: 84,
- 0xe0172: 84,
- 0xe0173: 84,
- 0xe0174: 84,
- 0xe0175: 84,
- 0xe0176: 84,
- 0xe0177: 84,
- 0xe0178: 84,
- 0xe0179: 84,
- 0xe017a: 84,
- 0xe017b: 84,
- 0xe017c: 84,
- 0xe017d: 84,
- 0xe017e: 84,
- 0xe017f: 84,
- 0xe0180: 84,
- 0xe0181: 84,
- 0xe0182: 84,
- 0xe0183: 84,
- 0xe0184: 84,
- 0xe0185: 84,
- 0xe0186: 84,
- 0xe0187: 84,
- 0xe0188: 84,
- 0xe0189: 84,
- 0xe018a: 84,
- 0xe018b: 84,
- 0xe018c: 84,
- 0xe018d: 84,
- 0xe018e: 84,
- 0xe018f: 84,
- 0xe0190: 84,
- 0xe0191: 84,
- 0xe0192: 84,
- 0xe0193: 84,
- 0xe0194: 84,
- 0xe0195: 84,
- 0xe0196: 84,
- 0xe0197: 84,
- 0xe0198: 84,
- 0xe0199: 84,
- 0xe019a: 84,
- 0xe019b: 84,
- 0xe019c: 84,
- 0xe019d: 84,
- 0xe019e: 84,
- 0xe019f: 84,
- 0xe01a0: 84,
- 0xe01a1: 84,
- 0xe01a2: 84,
- 0xe01a3: 84,
- 0xe01a4: 84,
- 0xe01a5: 84,
- 0xe01a6: 84,
- 0xe01a7: 84,
- 0xe01a8: 84,
- 0xe01a9: 84,
- 0xe01aa: 84,
- 0xe01ab: 84,
- 0xe01ac: 84,
- 0xe01ad: 84,
- 0xe01ae: 84,
- 0xe01af: 84,
- 0xe01b0: 84,
- 0xe01b1: 84,
- 0xe01b2: 84,
- 0xe01b3: 84,
- 0xe01b4: 84,
- 0xe01b5: 84,
- 0xe01b6: 84,
- 0xe01b7: 84,
- 0xe01b8: 84,
- 0xe01b9: 84,
- 0xe01ba: 84,
- 0xe01bb: 84,
- 0xe01bc: 84,
- 0xe01bd: 84,
- 0xe01be: 84,
- 0xe01bf: 84,
- 0xe01c0: 84,
- 0xe01c1: 84,
- 0xe01c2: 84,
- 0xe01c3: 84,
- 0xe01c4: 84,
- 0xe01c5: 84,
- 0xe01c6: 84,
- 0xe01c7: 84,
- 0xe01c8: 84,
- 0xe01c9: 84,
- 0xe01ca: 84,
- 0xe01cb: 84,
- 0xe01cc: 84,
- 0xe01cd: 84,
- 0xe01ce: 84,
- 0xe01cf: 84,
- 0xe01d0: 84,
- 0xe01d1: 84,
- 0xe01d2: 84,
- 0xe01d3: 84,
- 0xe01d4: 84,
- 0xe01d5: 84,
- 0xe01d6: 84,
- 0xe01d7: 84,
- 0xe01d8: 84,
- 0xe01d9: 84,
- 0xe01da: 84,
- 0xe01db: 84,
- 0xe01dc: 84,
- 0xe01dd: 84,
- 0xe01de: 84,
- 0xe01df: 84,
- 0xe01e0: 84,
- 0xe01e1: 84,
- 0xe01e2: 84,
- 0xe01e3: 84,
- 0xe01e4: 84,
- 0xe01e5: 84,
- 0xe01e6: 84,
- 0xe01e7: 84,
- 0xe01e8: 84,
- 0xe01e9: 84,
- 0xe01ea: 84,
- 0xe01eb: 84,
- 0xe01ec: 84,
- 0xe01ed: 84,
- 0xe01ee: 84,
- 0xe01ef: 84,
-}
-codepoint_classes = {
- 'PVALID': (
- 0x2d0000002e,
- 0x300000003a,
- 0x610000007b,
- 0xdf000000f7,
- 0xf800000100,
- 0x10100000102,
- 0x10300000104,
- 0x10500000106,
- 0x10700000108,
- 0x1090000010a,
- 0x10b0000010c,
- 0x10d0000010e,
- 0x10f00000110,
- 0x11100000112,
- 0x11300000114,
- 0x11500000116,
- 0x11700000118,
- 0x1190000011a,
- 0x11b0000011c,
- 0x11d0000011e,
- 0x11f00000120,
- 0x12100000122,
- 0x12300000124,
- 0x12500000126,
- 0x12700000128,
- 0x1290000012a,
- 0x12b0000012c,
- 0x12d0000012e,
- 0x12f00000130,
- 0x13100000132,
- 0x13500000136,
- 0x13700000139,
- 0x13a0000013b,
- 0x13c0000013d,
- 0x13e0000013f,
- 0x14200000143,
- 0x14400000145,
- 0x14600000147,
- 0x14800000149,
- 0x14b0000014c,
- 0x14d0000014e,
- 0x14f00000150,
- 0x15100000152,
- 0x15300000154,
- 0x15500000156,
- 0x15700000158,
- 0x1590000015a,
- 0x15b0000015c,
- 0x15d0000015e,
- 0x15f00000160,
- 0x16100000162,
- 0x16300000164,
- 0x16500000166,
- 0x16700000168,
- 0x1690000016a,
- 0x16b0000016c,
- 0x16d0000016e,
- 0x16f00000170,
- 0x17100000172,
- 0x17300000174,
- 0x17500000176,
- 0x17700000178,
- 0x17a0000017b,
- 0x17c0000017d,
- 0x17e0000017f,
- 0x18000000181,
- 0x18300000184,
- 0x18500000186,
- 0x18800000189,
- 0x18c0000018e,
- 0x19200000193,
- 0x19500000196,
- 0x1990000019c,
- 0x19e0000019f,
- 0x1a1000001a2,
- 0x1a3000001a4,
- 0x1a5000001a6,
- 0x1a8000001a9,
- 0x1aa000001ac,
- 0x1ad000001ae,
- 0x1b0000001b1,
- 0x1b4000001b5,
- 0x1b6000001b7,
- 0x1b9000001bc,
- 0x1bd000001c4,
- 0x1ce000001cf,
- 0x1d0000001d1,
- 0x1d2000001d3,
- 0x1d4000001d5,
- 0x1d6000001d7,
- 0x1d8000001d9,
- 0x1da000001db,
- 0x1dc000001de,
- 0x1df000001e0,
- 0x1e1000001e2,
- 0x1e3000001e4,
- 0x1e5000001e6,
- 0x1e7000001e8,
- 0x1e9000001ea,
- 0x1eb000001ec,
- 0x1ed000001ee,
- 0x1ef000001f1,
- 0x1f5000001f6,
- 0x1f9000001fa,
- 0x1fb000001fc,
- 0x1fd000001fe,
- 0x1ff00000200,
- 0x20100000202,
- 0x20300000204,
- 0x20500000206,
- 0x20700000208,
- 0x2090000020a,
- 0x20b0000020c,
- 0x20d0000020e,
- 0x20f00000210,
- 0x21100000212,
- 0x21300000214,
- 0x21500000216,
- 0x21700000218,
- 0x2190000021a,
- 0x21b0000021c,
- 0x21d0000021e,
- 0x21f00000220,
- 0x22100000222,
- 0x22300000224,
- 0x22500000226,
- 0x22700000228,
- 0x2290000022a,
- 0x22b0000022c,
- 0x22d0000022e,
- 0x22f00000230,
- 0x23100000232,
- 0x2330000023a,
- 0x23c0000023d,
- 0x23f00000241,
- 0x24200000243,
- 0x24700000248,
- 0x2490000024a,
- 0x24b0000024c,
- 0x24d0000024e,
- 0x24f000002b0,
- 0x2b9000002c2,
- 0x2c6000002d2,
- 0x2ec000002ed,
- 0x2ee000002ef,
- 0x30000000340,
- 0x34200000343,
- 0x3460000034f,
- 0x35000000370,
- 0x37100000372,
- 0x37300000374,
- 0x37700000378,
- 0x37b0000037e,
- 0x39000000391,
- 0x3ac000003cf,
- 0x3d7000003d8,
- 0x3d9000003da,
- 0x3db000003dc,
- 0x3dd000003de,
- 0x3df000003e0,
- 0x3e1000003e2,
- 0x3e3000003e4,
- 0x3e5000003e6,
- 0x3e7000003e8,
- 0x3e9000003ea,
- 0x3eb000003ec,
- 0x3ed000003ee,
- 0x3ef000003f0,
- 0x3f3000003f4,
- 0x3f8000003f9,
- 0x3fb000003fd,
- 0x43000000460,
- 0x46100000462,
- 0x46300000464,
- 0x46500000466,
- 0x46700000468,
- 0x4690000046a,
- 0x46b0000046c,
- 0x46d0000046e,
- 0x46f00000470,
- 0x47100000472,
- 0x47300000474,
- 0x47500000476,
- 0x47700000478,
- 0x4790000047a,
- 0x47b0000047c,
- 0x47d0000047e,
- 0x47f00000480,
- 0x48100000482,
- 0x48300000488,
- 0x48b0000048c,
- 0x48d0000048e,
- 0x48f00000490,
- 0x49100000492,
- 0x49300000494,
- 0x49500000496,
- 0x49700000498,
- 0x4990000049a,
- 0x49b0000049c,
- 0x49d0000049e,
- 0x49f000004a0,
- 0x4a1000004a2,
- 0x4a3000004a4,
- 0x4a5000004a6,
- 0x4a7000004a8,
- 0x4a9000004aa,
- 0x4ab000004ac,
- 0x4ad000004ae,
- 0x4af000004b0,
- 0x4b1000004b2,
- 0x4b3000004b4,
- 0x4b5000004b6,
- 0x4b7000004b8,
- 0x4b9000004ba,
- 0x4bb000004bc,
- 0x4bd000004be,
- 0x4bf000004c0,
- 0x4c2000004c3,
- 0x4c4000004c5,
- 0x4c6000004c7,
- 0x4c8000004c9,
- 0x4ca000004cb,
- 0x4cc000004cd,
- 0x4ce000004d0,
- 0x4d1000004d2,
- 0x4d3000004d4,
- 0x4d5000004d6,
- 0x4d7000004d8,
- 0x4d9000004da,
- 0x4db000004dc,
- 0x4dd000004de,
- 0x4df000004e0,
- 0x4e1000004e2,
- 0x4e3000004e4,
- 0x4e5000004e6,
- 0x4e7000004e8,
- 0x4e9000004ea,
- 0x4eb000004ec,
- 0x4ed000004ee,
- 0x4ef000004f0,
- 0x4f1000004f2,
- 0x4f3000004f4,
- 0x4f5000004f6,
- 0x4f7000004f8,
- 0x4f9000004fa,
- 0x4fb000004fc,
- 0x4fd000004fe,
- 0x4ff00000500,
- 0x50100000502,
- 0x50300000504,
- 0x50500000506,
- 0x50700000508,
- 0x5090000050a,
- 0x50b0000050c,
- 0x50d0000050e,
- 0x50f00000510,
- 0x51100000512,
- 0x51300000514,
- 0x51500000516,
- 0x51700000518,
- 0x5190000051a,
- 0x51b0000051c,
- 0x51d0000051e,
- 0x51f00000520,
- 0x52100000522,
- 0x52300000524,
- 0x52500000526,
- 0x52700000528,
- 0x5290000052a,
- 0x52b0000052c,
- 0x52d0000052e,
- 0x52f00000530,
- 0x5590000055a,
- 0x56000000587,
- 0x58800000589,
- 0x591000005be,
- 0x5bf000005c0,
- 0x5c1000005c3,
- 0x5c4000005c6,
- 0x5c7000005c8,
- 0x5d0000005eb,
- 0x5ef000005f3,
- 0x6100000061b,
- 0x62000000640,
- 0x64100000660,
- 0x66e00000675,
- 0x679000006d4,
- 0x6d5000006dd,
- 0x6df000006e9,
- 0x6ea000006f0,
- 0x6fa00000700,
- 0x7100000074b,
- 0x74d000007b2,
- 0x7c0000007f6,
- 0x7fd000007fe,
- 0x8000000082e,
- 0x8400000085c,
- 0x8600000086b,
- 0x87000000888,
- 0x8890000088f,
- 0x898000008e2,
- 0x8e300000958,
- 0x96000000964,
- 0x96600000970,
- 0x97100000984,
- 0x9850000098d,
- 0x98f00000991,
- 0x993000009a9,
- 0x9aa000009b1,
- 0x9b2000009b3,
- 0x9b6000009ba,
- 0x9bc000009c5,
- 0x9c7000009c9,
- 0x9cb000009cf,
- 0x9d7000009d8,
- 0x9e0000009e4,
- 0x9e6000009f2,
- 0x9fc000009fd,
- 0x9fe000009ff,
- 0xa0100000a04,
- 0xa0500000a0b,
- 0xa0f00000a11,
- 0xa1300000a29,
- 0xa2a00000a31,
- 0xa3200000a33,
- 0xa3500000a36,
- 0xa3800000a3a,
- 0xa3c00000a3d,
- 0xa3e00000a43,
- 0xa4700000a49,
- 0xa4b00000a4e,
- 0xa5100000a52,
- 0xa5c00000a5d,
- 0xa6600000a76,
- 0xa8100000a84,
- 0xa8500000a8e,
- 0xa8f00000a92,
- 0xa9300000aa9,
- 0xaaa00000ab1,
- 0xab200000ab4,
- 0xab500000aba,
- 0xabc00000ac6,
- 0xac700000aca,
- 0xacb00000ace,
- 0xad000000ad1,
- 0xae000000ae4,
- 0xae600000af0,
- 0xaf900000b00,
- 0xb0100000b04,
- 0xb0500000b0d,
- 0xb0f00000b11,
- 0xb1300000b29,
- 0xb2a00000b31,
- 0xb3200000b34,
- 0xb3500000b3a,
- 0xb3c00000b45,
- 0xb4700000b49,
- 0xb4b00000b4e,
- 0xb5500000b58,
- 0xb5f00000b64,
- 0xb6600000b70,
- 0xb7100000b72,
- 0xb8200000b84,
- 0xb8500000b8b,
- 0xb8e00000b91,
- 0xb9200000b96,
- 0xb9900000b9b,
- 0xb9c00000b9d,
- 0xb9e00000ba0,
- 0xba300000ba5,
- 0xba800000bab,
- 0xbae00000bba,
- 0xbbe00000bc3,
- 0xbc600000bc9,
- 0xbca00000bce,
- 0xbd000000bd1,
- 0xbd700000bd8,
- 0xbe600000bf0,
- 0xc0000000c0d,
- 0xc0e00000c11,
- 0xc1200000c29,
- 0xc2a00000c3a,
- 0xc3c00000c45,
- 0xc4600000c49,
- 0xc4a00000c4e,
- 0xc5500000c57,
- 0xc5800000c5b,
- 0xc5d00000c5e,
- 0xc6000000c64,
- 0xc6600000c70,
- 0xc8000000c84,
- 0xc8500000c8d,
- 0xc8e00000c91,
- 0xc9200000ca9,
- 0xcaa00000cb4,
- 0xcb500000cba,
- 0xcbc00000cc5,
- 0xcc600000cc9,
- 0xcca00000cce,
- 0xcd500000cd7,
- 0xcdd00000cdf,
- 0xce000000ce4,
- 0xce600000cf0,
- 0xcf100000cf4,
- 0xd0000000d0d,
- 0xd0e00000d11,
- 0xd1200000d45,
- 0xd4600000d49,
- 0xd4a00000d4f,
- 0xd5400000d58,
- 0xd5f00000d64,
- 0xd6600000d70,
- 0xd7a00000d80,
- 0xd8100000d84,
- 0xd8500000d97,
- 0xd9a00000db2,
- 0xdb300000dbc,
- 0xdbd00000dbe,
- 0xdc000000dc7,
- 0xdca00000dcb,
- 0xdcf00000dd5,
- 0xdd600000dd7,
- 0xdd800000de0,
- 0xde600000df0,
- 0xdf200000df4,
- 0xe0100000e33,
- 0xe3400000e3b,
- 0xe4000000e4f,
- 0xe5000000e5a,
- 0xe8100000e83,
- 0xe8400000e85,
- 0xe8600000e8b,
- 0xe8c00000ea4,
- 0xea500000ea6,
- 0xea700000eb3,
- 0xeb400000ebe,
- 0xec000000ec5,
- 0xec600000ec7,
- 0xec800000ecf,
- 0xed000000eda,
- 0xede00000ee0,
- 0xf0000000f01,
- 0xf0b00000f0c,
- 0xf1800000f1a,
- 0xf2000000f2a,
- 0xf3500000f36,
- 0xf3700000f38,
- 0xf3900000f3a,
- 0xf3e00000f43,
- 0xf4400000f48,
- 0xf4900000f4d,
- 0xf4e00000f52,
- 0xf5300000f57,
- 0xf5800000f5c,
- 0xf5d00000f69,
- 0xf6a00000f6d,
- 0xf7100000f73,
- 0xf7400000f75,
- 0xf7a00000f81,
- 0xf8200000f85,
- 0xf8600000f93,
- 0xf9400000f98,
- 0xf9900000f9d,
- 0xf9e00000fa2,
- 0xfa300000fa7,
- 0xfa800000fac,
- 0xfad00000fb9,
- 0xfba00000fbd,
- 0xfc600000fc7,
- 0x10000000104a,
- 0x10500000109e,
- 0x10d0000010fb,
- 0x10fd00001100,
- 0x120000001249,
- 0x124a0000124e,
- 0x125000001257,
- 0x125800001259,
- 0x125a0000125e,
- 0x126000001289,
- 0x128a0000128e,
- 0x1290000012b1,
- 0x12b2000012b6,
- 0x12b8000012bf,
- 0x12c0000012c1,
- 0x12c2000012c6,
- 0x12c8000012d7,
- 0x12d800001311,
- 0x131200001316,
- 0x13180000135b,
- 0x135d00001360,
- 0x138000001390,
- 0x13a0000013f6,
- 0x14010000166d,
- 0x166f00001680,
- 0x16810000169b,
- 0x16a0000016eb,
- 0x16f1000016f9,
- 0x170000001716,
- 0x171f00001735,
- 0x174000001754,
- 0x17600000176d,
- 0x176e00001771,
- 0x177200001774,
- 0x1780000017b4,
- 0x17b6000017d4,
- 0x17d7000017d8,
- 0x17dc000017de,
- 0x17e0000017ea,
- 0x18100000181a,
- 0x182000001879,
- 0x1880000018ab,
- 0x18b0000018f6,
- 0x19000000191f,
- 0x19200000192c,
- 0x19300000193c,
- 0x19460000196e,
- 0x197000001975,
- 0x1980000019ac,
- 0x19b0000019ca,
- 0x19d0000019da,
- 0x1a0000001a1c,
- 0x1a2000001a5f,
- 0x1a6000001a7d,
- 0x1a7f00001a8a,
- 0x1a9000001a9a,
- 0x1aa700001aa8,
- 0x1ab000001abe,
- 0x1abf00001acf,
- 0x1b0000001b4d,
- 0x1b5000001b5a,
- 0x1b6b00001b74,
- 0x1b8000001bf4,
- 0x1c0000001c38,
- 0x1c4000001c4a,
- 0x1c4d00001c7e,
- 0x1cd000001cd3,
- 0x1cd400001cfb,
- 0x1d0000001d2c,
- 0x1d2f00001d30,
- 0x1d3b00001d3c,
- 0x1d4e00001d4f,
- 0x1d6b00001d78,
- 0x1d7900001d9b,
- 0x1dc000001e00,
- 0x1e0100001e02,
- 0x1e0300001e04,
- 0x1e0500001e06,
- 0x1e0700001e08,
- 0x1e0900001e0a,
- 0x1e0b00001e0c,
- 0x1e0d00001e0e,
- 0x1e0f00001e10,
- 0x1e1100001e12,
- 0x1e1300001e14,
- 0x1e1500001e16,
- 0x1e1700001e18,
- 0x1e1900001e1a,
- 0x1e1b00001e1c,
- 0x1e1d00001e1e,
- 0x1e1f00001e20,
- 0x1e2100001e22,
- 0x1e2300001e24,
- 0x1e2500001e26,
- 0x1e2700001e28,
- 0x1e2900001e2a,
- 0x1e2b00001e2c,
- 0x1e2d00001e2e,
- 0x1e2f00001e30,
- 0x1e3100001e32,
- 0x1e3300001e34,
- 0x1e3500001e36,
- 0x1e3700001e38,
- 0x1e3900001e3a,
- 0x1e3b00001e3c,
- 0x1e3d00001e3e,
- 0x1e3f00001e40,
- 0x1e4100001e42,
- 0x1e4300001e44,
- 0x1e4500001e46,
- 0x1e4700001e48,
- 0x1e4900001e4a,
- 0x1e4b00001e4c,
- 0x1e4d00001e4e,
- 0x1e4f00001e50,
- 0x1e5100001e52,
- 0x1e5300001e54,
- 0x1e5500001e56,
- 0x1e5700001e58,
- 0x1e5900001e5a,
- 0x1e5b00001e5c,
- 0x1e5d00001e5e,
- 0x1e5f00001e60,
- 0x1e6100001e62,
- 0x1e6300001e64,
- 0x1e6500001e66,
- 0x1e6700001e68,
- 0x1e6900001e6a,
- 0x1e6b00001e6c,
- 0x1e6d00001e6e,
- 0x1e6f00001e70,
- 0x1e7100001e72,
- 0x1e7300001e74,
- 0x1e7500001e76,
- 0x1e7700001e78,
- 0x1e7900001e7a,
- 0x1e7b00001e7c,
- 0x1e7d00001e7e,
- 0x1e7f00001e80,
- 0x1e8100001e82,
- 0x1e8300001e84,
- 0x1e8500001e86,
- 0x1e8700001e88,
- 0x1e8900001e8a,
- 0x1e8b00001e8c,
- 0x1e8d00001e8e,
- 0x1e8f00001e90,
- 0x1e9100001e92,
- 0x1e9300001e94,
- 0x1e9500001e9a,
- 0x1e9c00001e9e,
- 0x1e9f00001ea0,
- 0x1ea100001ea2,
- 0x1ea300001ea4,
- 0x1ea500001ea6,
- 0x1ea700001ea8,
- 0x1ea900001eaa,
- 0x1eab00001eac,
- 0x1ead00001eae,
- 0x1eaf00001eb0,
- 0x1eb100001eb2,
- 0x1eb300001eb4,
- 0x1eb500001eb6,
- 0x1eb700001eb8,
- 0x1eb900001eba,
- 0x1ebb00001ebc,
- 0x1ebd00001ebe,
- 0x1ebf00001ec0,
- 0x1ec100001ec2,
- 0x1ec300001ec4,
- 0x1ec500001ec6,
- 0x1ec700001ec8,
- 0x1ec900001eca,
- 0x1ecb00001ecc,
- 0x1ecd00001ece,
- 0x1ecf00001ed0,
- 0x1ed100001ed2,
- 0x1ed300001ed4,
- 0x1ed500001ed6,
- 0x1ed700001ed8,
- 0x1ed900001eda,
- 0x1edb00001edc,
- 0x1edd00001ede,
- 0x1edf00001ee0,
- 0x1ee100001ee2,
- 0x1ee300001ee4,
- 0x1ee500001ee6,
- 0x1ee700001ee8,
- 0x1ee900001eea,
- 0x1eeb00001eec,
- 0x1eed00001eee,
- 0x1eef00001ef0,
- 0x1ef100001ef2,
- 0x1ef300001ef4,
- 0x1ef500001ef6,
- 0x1ef700001ef8,
- 0x1ef900001efa,
- 0x1efb00001efc,
- 0x1efd00001efe,
- 0x1eff00001f08,
- 0x1f1000001f16,
- 0x1f2000001f28,
- 0x1f3000001f38,
- 0x1f4000001f46,
- 0x1f5000001f58,
- 0x1f6000001f68,
- 0x1f7000001f71,
- 0x1f7200001f73,
- 0x1f7400001f75,
- 0x1f7600001f77,
- 0x1f7800001f79,
- 0x1f7a00001f7b,
- 0x1f7c00001f7d,
- 0x1fb000001fb2,
- 0x1fb600001fb7,
- 0x1fc600001fc7,
- 0x1fd000001fd3,
- 0x1fd600001fd8,
- 0x1fe000001fe3,
- 0x1fe400001fe8,
- 0x1ff600001ff7,
- 0x214e0000214f,
- 0x218400002185,
- 0x2c3000002c60,
- 0x2c6100002c62,
- 0x2c6500002c67,
- 0x2c6800002c69,
- 0x2c6a00002c6b,
- 0x2c6c00002c6d,
- 0x2c7100002c72,
- 0x2c7300002c75,
- 0x2c7600002c7c,
- 0x2c8100002c82,
- 0x2c8300002c84,
- 0x2c8500002c86,
- 0x2c8700002c88,
- 0x2c8900002c8a,
- 0x2c8b00002c8c,
- 0x2c8d00002c8e,
- 0x2c8f00002c90,
- 0x2c9100002c92,
- 0x2c9300002c94,
- 0x2c9500002c96,
- 0x2c9700002c98,
- 0x2c9900002c9a,
- 0x2c9b00002c9c,
- 0x2c9d00002c9e,
- 0x2c9f00002ca0,
- 0x2ca100002ca2,
- 0x2ca300002ca4,
- 0x2ca500002ca6,
- 0x2ca700002ca8,
- 0x2ca900002caa,
- 0x2cab00002cac,
- 0x2cad00002cae,
- 0x2caf00002cb0,
- 0x2cb100002cb2,
- 0x2cb300002cb4,
- 0x2cb500002cb6,
- 0x2cb700002cb8,
- 0x2cb900002cba,
- 0x2cbb00002cbc,
- 0x2cbd00002cbe,
- 0x2cbf00002cc0,
- 0x2cc100002cc2,
- 0x2cc300002cc4,
- 0x2cc500002cc6,
- 0x2cc700002cc8,
- 0x2cc900002cca,
- 0x2ccb00002ccc,
- 0x2ccd00002cce,
- 0x2ccf00002cd0,
- 0x2cd100002cd2,
- 0x2cd300002cd4,
- 0x2cd500002cd6,
- 0x2cd700002cd8,
- 0x2cd900002cda,
- 0x2cdb00002cdc,
- 0x2cdd00002cde,
- 0x2cdf00002ce0,
- 0x2ce100002ce2,
- 0x2ce300002ce5,
- 0x2cec00002ced,
- 0x2cee00002cf2,
- 0x2cf300002cf4,
- 0x2d0000002d26,
- 0x2d2700002d28,
- 0x2d2d00002d2e,
- 0x2d3000002d68,
- 0x2d7f00002d97,
- 0x2da000002da7,
- 0x2da800002daf,
- 0x2db000002db7,
- 0x2db800002dbf,
- 0x2dc000002dc7,
- 0x2dc800002dcf,
- 0x2dd000002dd7,
- 0x2dd800002ddf,
- 0x2de000002e00,
- 0x2e2f00002e30,
- 0x300500003008,
- 0x302a0000302e,
- 0x303c0000303d,
- 0x304100003097,
- 0x30990000309b,
- 0x309d0000309f,
- 0x30a1000030fb,
- 0x30fc000030ff,
- 0x310500003130,
- 0x31a0000031c0,
- 0x31f000003200,
- 0x340000004dc0,
- 0x4e000000a48d,
- 0xa4d00000a4fe,
- 0xa5000000a60d,
- 0xa6100000a62c,
- 0xa6410000a642,
- 0xa6430000a644,
- 0xa6450000a646,
- 0xa6470000a648,
- 0xa6490000a64a,
- 0xa64b0000a64c,
- 0xa64d0000a64e,
- 0xa64f0000a650,
- 0xa6510000a652,
- 0xa6530000a654,
- 0xa6550000a656,
- 0xa6570000a658,
- 0xa6590000a65a,
- 0xa65b0000a65c,
- 0xa65d0000a65e,
- 0xa65f0000a660,
- 0xa6610000a662,
- 0xa6630000a664,
- 0xa6650000a666,
- 0xa6670000a668,
- 0xa6690000a66a,
- 0xa66b0000a66c,
- 0xa66d0000a670,
- 0xa6740000a67e,
- 0xa67f0000a680,
- 0xa6810000a682,
- 0xa6830000a684,
- 0xa6850000a686,
- 0xa6870000a688,
- 0xa6890000a68a,
- 0xa68b0000a68c,
- 0xa68d0000a68e,
- 0xa68f0000a690,
- 0xa6910000a692,
- 0xa6930000a694,
- 0xa6950000a696,
- 0xa6970000a698,
- 0xa6990000a69a,
- 0xa69b0000a69c,
- 0xa69e0000a6e6,
- 0xa6f00000a6f2,
- 0xa7170000a720,
- 0xa7230000a724,
- 0xa7250000a726,
- 0xa7270000a728,
- 0xa7290000a72a,
- 0xa72b0000a72c,
- 0xa72d0000a72e,
- 0xa72f0000a732,
- 0xa7330000a734,
- 0xa7350000a736,
- 0xa7370000a738,
- 0xa7390000a73a,
- 0xa73b0000a73c,
- 0xa73d0000a73e,
- 0xa73f0000a740,
- 0xa7410000a742,
- 0xa7430000a744,
- 0xa7450000a746,
- 0xa7470000a748,
- 0xa7490000a74a,
- 0xa74b0000a74c,
- 0xa74d0000a74e,
- 0xa74f0000a750,
- 0xa7510000a752,
- 0xa7530000a754,
- 0xa7550000a756,
- 0xa7570000a758,
- 0xa7590000a75a,
- 0xa75b0000a75c,
- 0xa75d0000a75e,
- 0xa75f0000a760,
- 0xa7610000a762,
- 0xa7630000a764,
- 0xa7650000a766,
- 0xa7670000a768,
- 0xa7690000a76a,
- 0xa76b0000a76c,
- 0xa76d0000a76e,
- 0xa76f0000a770,
- 0xa7710000a779,
- 0xa77a0000a77b,
- 0xa77c0000a77d,
- 0xa77f0000a780,
- 0xa7810000a782,
- 0xa7830000a784,
- 0xa7850000a786,
- 0xa7870000a789,
- 0xa78c0000a78d,
- 0xa78e0000a790,
- 0xa7910000a792,
- 0xa7930000a796,
- 0xa7970000a798,
- 0xa7990000a79a,
- 0xa79b0000a79c,
- 0xa79d0000a79e,
- 0xa79f0000a7a0,
- 0xa7a10000a7a2,
- 0xa7a30000a7a4,
- 0xa7a50000a7a6,
- 0xa7a70000a7a8,
- 0xa7a90000a7aa,
- 0xa7af0000a7b0,
- 0xa7b50000a7b6,
- 0xa7b70000a7b8,
- 0xa7b90000a7ba,
- 0xa7bb0000a7bc,
- 0xa7bd0000a7be,
- 0xa7bf0000a7c0,
- 0xa7c10000a7c2,
- 0xa7c30000a7c4,
- 0xa7c80000a7c9,
- 0xa7ca0000a7cb,
- 0xa7d10000a7d2,
- 0xa7d30000a7d4,
- 0xa7d50000a7d6,
- 0xa7d70000a7d8,
- 0xa7d90000a7da,
- 0xa7f60000a7f8,
- 0xa7fa0000a828,
- 0xa82c0000a82d,
- 0xa8400000a874,
- 0xa8800000a8c6,
- 0xa8d00000a8da,
- 0xa8e00000a8f8,
- 0xa8fb0000a8fc,
- 0xa8fd0000a92e,
- 0xa9300000a954,
- 0xa9800000a9c1,
- 0xa9cf0000a9da,
- 0xa9e00000a9ff,
- 0xaa000000aa37,
- 0xaa400000aa4e,
- 0xaa500000aa5a,
- 0xaa600000aa77,
- 0xaa7a0000aac3,
- 0xaadb0000aade,
- 0xaae00000aaf0,
- 0xaaf20000aaf7,
- 0xab010000ab07,
- 0xab090000ab0f,
- 0xab110000ab17,
- 0xab200000ab27,
- 0xab280000ab2f,
- 0xab300000ab5b,
- 0xab600000ab69,
- 0xabc00000abeb,
- 0xabec0000abee,
- 0xabf00000abfa,
- 0xac000000d7a4,
- 0xfa0e0000fa10,
- 0xfa110000fa12,
- 0xfa130000fa15,
- 0xfa1f0000fa20,
- 0xfa210000fa22,
- 0xfa230000fa25,
- 0xfa270000fa2a,
- 0xfb1e0000fb1f,
- 0xfe200000fe30,
- 0xfe730000fe74,
- 0x100000001000c,
- 0x1000d00010027,
- 0x100280001003b,
- 0x1003c0001003e,
- 0x1003f0001004e,
- 0x100500001005e,
- 0x10080000100fb,
- 0x101fd000101fe,
- 0x102800001029d,
- 0x102a0000102d1,
- 0x102e0000102e1,
- 0x1030000010320,
- 0x1032d00010341,
- 0x103420001034a,
- 0x103500001037b,
- 0x103800001039e,
- 0x103a0000103c4,
- 0x103c8000103d0,
- 0x104280001049e,
- 0x104a0000104aa,
- 0x104d8000104fc,
- 0x1050000010528,
- 0x1053000010564,
- 0x10597000105a2,
- 0x105a3000105b2,
- 0x105b3000105ba,
- 0x105bb000105bd,
- 0x1060000010737,
- 0x1074000010756,
- 0x1076000010768,
- 0x1078000010781,
- 0x1080000010806,
- 0x1080800010809,
- 0x1080a00010836,
- 0x1083700010839,
- 0x1083c0001083d,
- 0x1083f00010856,
- 0x1086000010877,
- 0x108800001089f,
- 0x108e0000108f3,
- 0x108f4000108f6,
- 0x1090000010916,
- 0x109200001093a,
- 0x10980000109b8,
- 0x109be000109c0,
- 0x10a0000010a04,
- 0x10a0500010a07,
- 0x10a0c00010a14,
- 0x10a1500010a18,
- 0x10a1900010a36,
- 0x10a3800010a3b,
- 0x10a3f00010a40,
- 0x10a6000010a7d,
- 0x10a8000010a9d,
- 0x10ac000010ac8,
- 0x10ac900010ae7,
- 0x10b0000010b36,
- 0x10b4000010b56,
- 0x10b6000010b73,
- 0x10b8000010b92,
- 0x10c0000010c49,
- 0x10cc000010cf3,
- 0x10d0000010d28,
- 0x10d3000010d3a,
- 0x10e8000010eaa,
- 0x10eab00010ead,
- 0x10eb000010eb2,
- 0x10efd00010f1d,
- 0x10f2700010f28,
- 0x10f3000010f51,
- 0x10f7000010f86,
- 0x10fb000010fc5,
- 0x10fe000010ff7,
- 0x1100000011047,
- 0x1106600011076,
- 0x1107f000110bb,
- 0x110c2000110c3,
- 0x110d0000110e9,
- 0x110f0000110fa,
- 0x1110000011135,
- 0x1113600011140,
- 0x1114400011148,
- 0x1115000011174,
- 0x1117600011177,
- 0x11180000111c5,
- 0x111c9000111cd,
- 0x111ce000111db,
- 0x111dc000111dd,
- 0x1120000011212,
- 0x1121300011238,
- 0x1123e00011242,
- 0x1128000011287,
- 0x1128800011289,
- 0x1128a0001128e,
- 0x1128f0001129e,
- 0x1129f000112a9,
- 0x112b0000112eb,
- 0x112f0000112fa,
- 0x1130000011304,
- 0x113050001130d,
- 0x1130f00011311,
- 0x1131300011329,
- 0x1132a00011331,
- 0x1133200011334,
- 0x113350001133a,
- 0x1133b00011345,
- 0x1134700011349,
- 0x1134b0001134e,
- 0x1135000011351,
- 0x1135700011358,
- 0x1135d00011364,
- 0x113660001136d,
- 0x1137000011375,
- 0x114000001144b,
- 0x114500001145a,
- 0x1145e00011462,
- 0x11480000114c6,
- 0x114c7000114c8,
- 0x114d0000114da,
- 0x11580000115b6,
- 0x115b8000115c1,
- 0x115d8000115de,
- 0x1160000011641,
- 0x1164400011645,
- 0x116500001165a,
- 0x11680000116b9,
- 0x116c0000116ca,
- 0x117000001171b,
- 0x1171d0001172c,
- 0x117300001173a,
- 0x1174000011747,
- 0x118000001183b,
- 0x118c0000118ea,
- 0x118ff00011907,
- 0x119090001190a,
- 0x1190c00011914,
- 0x1191500011917,
- 0x1191800011936,
- 0x1193700011939,
- 0x1193b00011944,
- 0x119500001195a,
- 0x119a0000119a8,
- 0x119aa000119d8,
- 0x119da000119e2,
- 0x119e3000119e5,
- 0x11a0000011a3f,
- 0x11a4700011a48,
- 0x11a5000011a9a,
- 0x11a9d00011a9e,
- 0x11ab000011af9,
- 0x11c0000011c09,
- 0x11c0a00011c37,
- 0x11c3800011c41,
- 0x11c5000011c5a,
- 0x11c7200011c90,
- 0x11c9200011ca8,
- 0x11ca900011cb7,
- 0x11d0000011d07,
- 0x11d0800011d0a,
- 0x11d0b00011d37,
- 0x11d3a00011d3b,
- 0x11d3c00011d3e,
- 0x11d3f00011d48,
- 0x11d5000011d5a,
- 0x11d6000011d66,
- 0x11d6700011d69,
- 0x11d6a00011d8f,
- 0x11d9000011d92,
- 0x11d9300011d99,
- 0x11da000011daa,
- 0x11ee000011ef7,
- 0x11f0000011f11,
- 0x11f1200011f3b,
- 0x11f3e00011f43,
- 0x11f5000011f5a,
- 0x11fb000011fb1,
- 0x120000001239a,
- 0x1248000012544,
- 0x12f9000012ff1,
- 0x1300000013430,
- 0x1344000013456,
- 0x1440000014647,
- 0x1680000016a39,
- 0x16a4000016a5f,
- 0x16a6000016a6a,
- 0x16a7000016abf,
- 0x16ac000016aca,
- 0x16ad000016aee,
- 0x16af000016af5,
- 0x16b0000016b37,
- 0x16b4000016b44,
- 0x16b5000016b5a,
- 0x16b6300016b78,
- 0x16b7d00016b90,
- 0x16e6000016e80,
- 0x16f0000016f4b,
- 0x16f4f00016f88,
- 0x16f8f00016fa0,
- 0x16fe000016fe2,
- 0x16fe300016fe5,
- 0x16ff000016ff2,
- 0x17000000187f8,
- 0x1880000018cd6,
- 0x18d0000018d09,
- 0x1aff00001aff4,
- 0x1aff50001affc,
- 0x1affd0001afff,
- 0x1b0000001b123,
- 0x1b1320001b133,
- 0x1b1500001b153,
- 0x1b1550001b156,
- 0x1b1640001b168,
- 0x1b1700001b2fc,
- 0x1bc000001bc6b,
- 0x1bc700001bc7d,
- 0x1bc800001bc89,
- 0x1bc900001bc9a,
- 0x1bc9d0001bc9f,
- 0x1cf000001cf2e,
- 0x1cf300001cf47,
- 0x1da000001da37,
- 0x1da3b0001da6d,
- 0x1da750001da76,
- 0x1da840001da85,
- 0x1da9b0001daa0,
- 0x1daa10001dab0,
- 0x1df000001df1f,
- 0x1df250001df2b,
- 0x1e0000001e007,
- 0x1e0080001e019,
- 0x1e01b0001e022,
- 0x1e0230001e025,
- 0x1e0260001e02b,
- 0x1e08f0001e090,
- 0x1e1000001e12d,
- 0x1e1300001e13e,
- 0x1e1400001e14a,
- 0x1e14e0001e14f,
- 0x1e2900001e2af,
- 0x1e2c00001e2fa,
- 0x1e4d00001e4fa,
- 0x1e7e00001e7e7,
- 0x1e7e80001e7ec,
- 0x1e7ed0001e7ef,
- 0x1e7f00001e7ff,
- 0x1e8000001e8c5,
- 0x1e8d00001e8d7,
- 0x1e9220001e94c,
- 0x1e9500001e95a,
- 0x200000002a6e0,
- 0x2a7000002b73a,
- 0x2b7400002b81e,
- 0x2b8200002cea2,
- 0x2ceb00002ebe1,
- 0x2ebf00002ee5e,
- 0x300000003134b,
- 0x31350000323b0,
- ),
- 'CONTEXTJ': (
- 0x200c0000200e,
- ),
- 'CONTEXTO': (
- 0xb7000000b8,
- 0x37500000376,
- 0x5f3000005f5,
- 0x6600000066a,
- 0x6f0000006fa,
- 0x30fb000030fc,
- ),
-}
diff --git a/.venv/lib/python3.12/site-packages/idna/intranges.py b/.venv/lib/python3.12/site-packages/idna/intranges.py
deleted file mode 100644
index 6a43b04..0000000
--- a/.venv/lib/python3.12/site-packages/idna/intranges.py
+++ /dev/null
@@ -1,54 +0,0 @@
-"""
-Given a list of integers, made up of (hopefully) a small number of long runs
-of consecutive integers, compute a representation of the form
-((start1, end1), (start2, end2) ...). Then answer the question "was x present
-in the original list?" in time O(log(# runs)).
-"""
-
-import bisect
-from typing import List, Tuple
-
-def intranges_from_list(list_: List[int]) -> Tuple[int, ...]:
- """Represent a list of integers as a sequence of ranges:
- ((start_0, end_0), (start_1, end_1), ...), such that the original
- integers are exactly those x such that start_i <= x < end_i for some i.
-
- Ranges are encoded as single integers (start << 32 | end), not as tuples.
- """
-
- sorted_list = sorted(list_)
- ranges = []
- last_write = -1
- for i in range(len(sorted_list)):
- if i+1 < len(sorted_list):
- if sorted_list[i] == sorted_list[i+1]-1:
- continue
- current_range = sorted_list[last_write+1:i+1]
- ranges.append(_encode_range(current_range[0], current_range[-1] + 1))
- last_write = i
-
- return tuple(ranges)
-
-def _encode_range(start: int, end: int) -> int:
- return (start << 32) | end
-
-def _decode_range(r: int) -> Tuple[int, int]:
- return (r >> 32), (r & ((1 << 32) - 1))
-
-
-def intranges_contain(int_: int, ranges: Tuple[int, ...]) -> bool:
- """Determine if `int_` falls into one of the ranges in `ranges`."""
- tuple_ = _encode_range(int_, 0)
- pos = bisect.bisect_left(ranges, tuple_)
- # we could be immediately ahead of a tuple (start, end)
- # with start < int_ <= end
- if pos > 0:
- left, right = _decode_range(ranges[pos-1])
- if left <= int_ < right:
- return True
- # or we could be immediately behind a tuple (int_, end)
- if pos < len(ranges):
- left, _ = _decode_range(ranges[pos])
- if left == int_:
- return True
- return False
diff --git a/.venv/lib/python3.12/site-packages/idna/package_data.py b/.venv/lib/python3.12/site-packages/idna/package_data.py
deleted file mode 100644
index ed81113..0000000
--- a/.venv/lib/python3.12/site-packages/idna/package_data.py
+++ /dev/null
@@ -1,2 +0,0 @@
-__version__ = '3.7'
-
diff --git a/.venv/lib/python3.12/site-packages/idna/py.typed b/.venv/lib/python3.12/site-packages/idna/py.typed
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/idna/uts46data.py b/.venv/lib/python3.12/site-packages/idna/uts46data.py
deleted file mode 100644
index 6a1eddb..0000000
--- a/.venv/lib/python3.12/site-packages/idna/uts46data.py
+++ /dev/null
@@ -1,8598 +0,0 @@
-# This file is automatically generated by tools/idna-data
-# vim: set fileencoding=utf-8 :
-
-from typing import List, Tuple, Union
-
-
-"""IDNA Mapping Table from UTS46."""
-
-
-__version__ = '15.1.0'
-def _seg_0() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x0, '3'),
- (0x1, '3'),
- (0x2, '3'),
- (0x3, '3'),
- (0x4, '3'),
- (0x5, '3'),
- (0x6, '3'),
- (0x7, '3'),
- (0x8, '3'),
- (0x9, '3'),
- (0xA, '3'),
- (0xB, '3'),
- (0xC, '3'),
- (0xD, '3'),
- (0xE, '3'),
- (0xF, '3'),
- (0x10, '3'),
- (0x11, '3'),
- (0x12, '3'),
- (0x13, '3'),
- (0x14, '3'),
- (0x15, '3'),
- (0x16, '3'),
- (0x17, '3'),
- (0x18, '3'),
- (0x19, '3'),
- (0x1A, '3'),
- (0x1B, '3'),
- (0x1C, '3'),
- (0x1D, '3'),
- (0x1E, '3'),
- (0x1F, '3'),
- (0x20, '3'),
- (0x21, '3'),
- (0x22, '3'),
- (0x23, '3'),
- (0x24, '3'),
- (0x25, '3'),
- (0x26, '3'),
- (0x27, '3'),
- (0x28, '3'),
- (0x29, '3'),
- (0x2A, '3'),
- (0x2B, '3'),
- (0x2C, '3'),
- (0x2D, 'V'),
- (0x2E, 'V'),
- (0x2F, '3'),
- (0x30, 'V'),
- (0x31, 'V'),
- (0x32, 'V'),
- (0x33, 'V'),
- (0x34, 'V'),
- (0x35, 'V'),
- (0x36, 'V'),
- (0x37, 'V'),
- (0x38, 'V'),
- (0x39, 'V'),
- (0x3A, '3'),
- (0x3B, '3'),
- (0x3C, '3'),
- (0x3D, '3'),
- (0x3E, '3'),
- (0x3F, '3'),
- (0x40, '3'),
- (0x41, 'M', 'a'),
- (0x42, 'M', 'b'),
- (0x43, 'M', 'c'),
- (0x44, 'M', 'd'),
- (0x45, 'M', 'e'),
- (0x46, 'M', 'f'),
- (0x47, 'M', 'g'),
- (0x48, 'M', 'h'),
- (0x49, 'M', 'i'),
- (0x4A, 'M', 'j'),
- (0x4B, 'M', 'k'),
- (0x4C, 'M', 'l'),
- (0x4D, 'M', 'm'),
- (0x4E, 'M', 'n'),
- (0x4F, 'M', 'o'),
- (0x50, 'M', 'p'),
- (0x51, 'M', 'q'),
- (0x52, 'M', 'r'),
- (0x53, 'M', 's'),
- (0x54, 'M', 't'),
- (0x55, 'M', 'u'),
- (0x56, 'M', 'v'),
- (0x57, 'M', 'w'),
- (0x58, 'M', 'x'),
- (0x59, 'M', 'y'),
- (0x5A, 'M', 'z'),
- (0x5B, '3'),
- (0x5C, '3'),
- (0x5D, '3'),
- (0x5E, '3'),
- (0x5F, '3'),
- (0x60, '3'),
- (0x61, 'V'),
- (0x62, 'V'),
- (0x63, 'V'),
- ]
-
-def _seg_1() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x64, 'V'),
- (0x65, 'V'),
- (0x66, 'V'),
- (0x67, 'V'),
- (0x68, 'V'),
- (0x69, 'V'),
- (0x6A, 'V'),
- (0x6B, 'V'),
- (0x6C, 'V'),
- (0x6D, 'V'),
- (0x6E, 'V'),
- (0x6F, 'V'),
- (0x70, 'V'),
- (0x71, 'V'),
- (0x72, 'V'),
- (0x73, 'V'),
- (0x74, 'V'),
- (0x75, 'V'),
- (0x76, 'V'),
- (0x77, 'V'),
- (0x78, 'V'),
- (0x79, 'V'),
- (0x7A, 'V'),
- (0x7B, '3'),
- (0x7C, '3'),
- (0x7D, '3'),
- (0x7E, '3'),
- (0x7F, '3'),
- (0x80, 'X'),
- (0x81, 'X'),
- (0x82, 'X'),
- (0x83, 'X'),
- (0x84, 'X'),
- (0x85, 'X'),
- (0x86, 'X'),
- (0x87, 'X'),
- (0x88, 'X'),
- (0x89, 'X'),
- (0x8A, 'X'),
- (0x8B, 'X'),
- (0x8C, 'X'),
- (0x8D, 'X'),
- (0x8E, 'X'),
- (0x8F, 'X'),
- (0x90, 'X'),
- (0x91, 'X'),
- (0x92, 'X'),
- (0x93, 'X'),
- (0x94, 'X'),
- (0x95, 'X'),
- (0x96, 'X'),
- (0x97, 'X'),
- (0x98, 'X'),
- (0x99, 'X'),
- (0x9A, 'X'),
- (0x9B, 'X'),
- (0x9C, 'X'),
- (0x9D, 'X'),
- (0x9E, 'X'),
- (0x9F, 'X'),
- (0xA0, '3', ' '),
- (0xA1, 'V'),
- (0xA2, 'V'),
- (0xA3, 'V'),
- (0xA4, 'V'),
- (0xA5, 'V'),
- (0xA6, 'V'),
- (0xA7, 'V'),
- (0xA8, '3', ' ̈'),
- (0xA9, 'V'),
- (0xAA, 'M', 'a'),
- (0xAB, 'V'),
- (0xAC, 'V'),
- (0xAD, 'I'),
- (0xAE, 'V'),
- (0xAF, '3', ' ̄'),
- (0xB0, 'V'),
- (0xB1, 'V'),
- (0xB2, 'M', '2'),
- (0xB3, 'M', '3'),
- (0xB4, '3', ' ́'),
- (0xB5, 'M', 'μ'),
- (0xB6, 'V'),
- (0xB7, 'V'),
- (0xB8, '3', ' ̧'),
- (0xB9, 'M', '1'),
- (0xBA, 'M', 'o'),
- (0xBB, 'V'),
- (0xBC, 'M', '1⁄4'),
- (0xBD, 'M', '1⁄2'),
- (0xBE, 'M', '3⁄4'),
- (0xBF, 'V'),
- (0xC0, 'M', 'à'),
- (0xC1, 'M', 'á'),
- (0xC2, 'M', 'â'),
- (0xC3, 'M', 'ã'),
- (0xC4, 'M', 'ä'),
- (0xC5, 'M', 'å'),
- (0xC6, 'M', 'æ'),
- (0xC7, 'M', 'ç'),
- ]
-
-def _seg_2() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xC8, 'M', 'è'),
- (0xC9, 'M', 'é'),
- (0xCA, 'M', 'ê'),
- (0xCB, 'M', 'ë'),
- (0xCC, 'M', 'ì'),
- (0xCD, 'M', 'í'),
- (0xCE, 'M', 'î'),
- (0xCF, 'M', 'ï'),
- (0xD0, 'M', 'ð'),
- (0xD1, 'M', 'ñ'),
- (0xD2, 'M', 'ò'),
- (0xD3, 'M', 'ó'),
- (0xD4, 'M', 'ô'),
- (0xD5, 'M', 'õ'),
- (0xD6, 'M', 'ö'),
- (0xD7, 'V'),
- (0xD8, 'M', 'ø'),
- (0xD9, 'M', 'ù'),
- (0xDA, 'M', 'ú'),
- (0xDB, 'M', 'û'),
- (0xDC, 'M', 'ü'),
- (0xDD, 'M', 'ý'),
- (0xDE, 'M', 'þ'),
- (0xDF, 'D', 'ss'),
- (0xE0, 'V'),
- (0xE1, 'V'),
- (0xE2, 'V'),
- (0xE3, 'V'),
- (0xE4, 'V'),
- (0xE5, 'V'),
- (0xE6, 'V'),
- (0xE7, 'V'),
- (0xE8, 'V'),
- (0xE9, 'V'),
- (0xEA, 'V'),
- (0xEB, 'V'),
- (0xEC, 'V'),
- (0xED, 'V'),
- (0xEE, 'V'),
- (0xEF, 'V'),
- (0xF0, 'V'),
- (0xF1, 'V'),
- (0xF2, 'V'),
- (0xF3, 'V'),
- (0xF4, 'V'),
- (0xF5, 'V'),
- (0xF6, 'V'),
- (0xF7, 'V'),
- (0xF8, 'V'),
- (0xF9, 'V'),
- (0xFA, 'V'),
- (0xFB, 'V'),
- (0xFC, 'V'),
- (0xFD, 'V'),
- (0xFE, 'V'),
- (0xFF, 'V'),
- (0x100, 'M', 'ā'),
- (0x101, 'V'),
- (0x102, 'M', 'ă'),
- (0x103, 'V'),
- (0x104, 'M', 'ą'),
- (0x105, 'V'),
- (0x106, 'M', 'ć'),
- (0x107, 'V'),
- (0x108, 'M', 'ĉ'),
- (0x109, 'V'),
- (0x10A, 'M', 'ċ'),
- (0x10B, 'V'),
- (0x10C, 'M', 'č'),
- (0x10D, 'V'),
- (0x10E, 'M', 'ď'),
- (0x10F, 'V'),
- (0x110, 'M', 'đ'),
- (0x111, 'V'),
- (0x112, 'M', 'ē'),
- (0x113, 'V'),
- (0x114, 'M', 'ĕ'),
- (0x115, 'V'),
- (0x116, 'M', 'ė'),
- (0x117, 'V'),
- (0x118, 'M', 'ę'),
- (0x119, 'V'),
- (0x11A, 'M', 'ě'),
- (0x11B, 'V'),
- (0x11C, 'M', 'ĝ'),
- (0x11D, 'V'),
- (0x11E, 'M', 'ğ'),
- (0x11F, 'V'),
- (0x120, 'M', 'ġ'),
- (0x121, 'V'),
- (0x122, 'M', 'ģ'),
- (0x123, 'V'),
- (0x124, 'M', 'ĥ'),
- (0x125, 'V'),
- (0x126, 'M', 'ħ'),
- (0x127, 'V'),
- (0x128, 'M', 'ĩ'),
- (0x129, 'V'),
- (0x12A, 'M', 'ī'),
- (0x12B, 'V'),
- ]
-
-def _seg_3() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x12C, 'M', 'ĭ'),
- (0x12D, 'V'),
- (0x12E, 'M', 'į'),
- (0x12F, 'V'),
- (0x130, 'M', 'i̇'),
- (0x131, 'V'),
- (0x132, 'M', 'ij'),
- (0x134, 'M', 'ĵ'),
- (0x135, 'V'),
- (0x136, 'M', 'ķ'),
- (0x137, 'V'),
- (0x139, 'M', 'ĺ'),
- (0x13A, 'V'),
- (0x13B, 'M', 'ļ'),
- (0x13C, 'V'),
- (0x13D, 'M', 'ľ'),
- (0x13E, 'V'),
- (0x13F, 'M', 'l·'),
- (0x141, 'M', 'ł'),
- (0x142, 'V'),
- (0x143, 'M', 'ń'),
- (0x144, 'V'),
- (0x145, 'M', 'ņ'),
- (0x146, 'V'),
- (0x147, 'M', 'ň'),
- (0x148, 'V'),
- (0x149, 'M', 'ʼn'),
- (0x14A, 'M', 'ŋ'),
- (0x14B, 'V'),
- (0x14C, 'M', 'ō'),
- (0x14D, 'V'),
- (0x14E, 'M', 'ŏ'),
- (0x14F, 'V'),
- (0x150, 'M', 'ő'),
- (0x151, 'V'),
- (0x152, 'M', 'œ'),
- (0x153, 'V'),
- (0x154, 'M', 'ŕ'),
- (0x155, 'V'),
- (0x156, 'M', 'ŗ'),
- (0x157, 'V'),
- (0x158, 'M', 'ř'),
- (0x159, 'V'),
- (0x15A, 'M', 'ś'),
- (0x15B, 'V'),
- (0x15C, 'M', 'ŝ'),
- (0x15D, 'V'),
- (0x15E, 'M', 'ş'),
- (0x15F, 'V'),
- (0x160, 'M', 'š'),
- (0x161, 'V'),
- (0x162, 'M', 'ţ'),
- (0x163, 'V'),
- (0x164, 'M', 'ť'),
- (0x165, 'V'),
- (0x166, 'M', 'ŧ'),
- (0x167, 'V'),
- (0x168, 'M', 'ũ'),
- (0x169, 'V'),
- (0x16A, 'M', 'ū'),
- (0x16B, 'V'),
- (0x16C, 'M', 'ŭ'),
- (0x16D, 'V'),
- (0x16E, 'M', 'ů'),
- (0x16F, 'V'),
- (0x170, 'M', 'ű'),
- (0x171, 'V'),
- (0x172, 'M', 'ų'),
- (0x173, 'V'),
- (0x174, 'M', 'ŵ'),
- (0x175, 'V'),
- (0x176, 'M', 'ŷ'),
- (0x177, 'V'),
- (0x178, 'M', 'ÿ'),
- (0x179, 'M', 'ź'),
- (0x17A, 'V'),
- (0x17B, 'M', 'ż'),
- (0x17C, 'V'),
- (0x17D, 'M', 'ž'),
- (0x17E, 'V'),
- (0x17F, 'M', 's'),
- (0x180, 'V'),
- (0x181, 'M', 'ɓ'),
- (0x182, 'M', 'ƃ'),
- (0x183, 'V'),
- (0x184, 'M', 'ƅ'),
- (0x185, 'V'),
- (0x186, 'M', 'ɔ'),
- (0x187, 'M', 'ƈ'),
- (0x188, 'V'),
- (0x189, 'M', 'ɖ'),
- (0x18A, 'M', 'ɗ'),
- (0x18B, 'M', 'ƌ'),
- (0x18C, 'V'),
- (0x18E, 'M', 'ǝ'),
- (0x18F, 'M', 'ə'),
- (0x190, 'M', 'ɛ'),
- (0x191, 'M', 'ƒ'),
- (0x192, 'V'),
- (0x193, 'M', 'ɠ'),
- ]
-
-def _seg_4() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x194, 'M', 'ɣ'),
- (0x195, 'V'),
- (0x196, 'M', 'ɩ'),
- (0x197, 'M', 'ɨ'),
- (0x198, 'M', 'ƙ'),
- (0x199, 'V'),
- (0x19C, 'M', 'ɯ'),
- (0x19D, 'M', 'ɲ'),
- (0x19E, 'V'),
- (0x19F, 'M', 'ɵ'),
- (0x1A0, 'M', 'ơ'),
- (0x1A1, 'V'),
- (0x1A2, 'M', 'ƣ'),
- (0x1A3, 'V'),
- (0x1A4, 'M', 'ƥ'),
- (0x1A5, 'V'),
- (0x1A6, 'M', 'ʀ'),
- (0x1A7, 'M', 'ƨ'),
- (0x1A8, 'V'),
- (0x1A9, 'M', 'ʃ'),
- (0x1AA, 'V'),
- (0x1AC, 'M', 'ƭ'),
- (0x1AD, 'V'),
- (0x1AE, 'M', 'ʈ'),
- (0x1AF, 'M', 'ư'),
- (0x1B0, 'V'),
- (0x1B1, 'M', 'ʊ'),
- (0x1B2, 'M', 'ʋ'),
- (0x1B3, 'M', 'ƴ'),
- (0x1B4, 'V'),
- (0x1B5, 'M', 'ƶ'),
- (0x1B6, 'V'),
- (0x1B7, 'M', 'ʒ'),
- (0x1B8, 'M', 'ƹ'),
- (0x1B9, 'V'),
- (0x1BC, 'M', 'ƽ'),
- (0x1BD, 'V'),
- (0x1C4, 'M', 'dž'),
- (0x1C7, 'M', 'lj'),
- (0x1CA, 'M', 'nj'),
- (0x1CD, 'M', 'ǎ'),
- (0x1CE, 'V'),
- (0x1CF, 'M', 'ǐ'),
- (0x1D0, 'V'),
- (0x1D1, 'M', 'ǒ'),
- (0x1D2, 'V'),
- (0x1D3, 'M', 'ǔ'),
- (0x1D4, 'V'),
- (0x1D5, 'M', 'ǖ'),
- (0x1D6, 'V'),
- (0x1D7, 'M', 'ǘ'),
- (0x1D8, 'V'),
- (0x1D9, 'M', 'ǚ'),
- (0x1DA, 'V'),
- (0x1DB, 'M', 'ǜ'),
- (0x1DC, 'V'),
- (0x1DE, 'M', 'ǟ'),
- (0x1DF, 'V'),
- (0x1E0, 'M', 'ǡ'),
- (0x1E1, 'V'),
- (0x1E2, 'M', 'ǣ'),
- (0x1E3, 'V'),
- (0x1E4, 'M', 'ǥ'),
- (0x1E5, 'V'),
- (0x1E6, 'M', 'ǧ'),
- (0x1E7, 'V'),
- (0x1E8, 'M', 'ǩ'),
- (0x1E9, 'V'),
- (0x1EA, 'M', 'ǫ'),
- (0x1EB, 'V'),
- (0x1EC, 'M', 'ǭ'),
- (0x1ED, 'V'),
- (0x1EE, 'M', 'ǯ'),
- (0x1EF, 'V'),
- (0x1F1, 'M', 'dz'),
- (0x1F4, 'M', 'ǵ'),
- (0x1F5, 'V'),
- (0x1F6, 'M', 'ƕ'),
- (0x1F7, 'M', 'ƿ'),
- (0x1F8, 'M', 'ǹ'),
- (0x1F9, 'V'),
- (0x1FA, 'M', 'ǻ'),
- (0x1FB, 'V'),
- (0x1FC, 'M', 'ǽ'),
- (0x1FD, 'V'),
- (0x1FE, 'M', 'ǿ'),
- (0x1FF, 'V'),
- (0x200, 'M', 'ȁ'),
- (0x201, 'V'),
- (0x202, 'M', 'ȃ'),
- (0x203, 'V'),
- (0x204, 'M', 'ȅ'),
- (0x205, 'V'),
- (0x206, 'M', 'ȇ'),
- (0x207, 'V'),
- (0x208, 'M', 'ȉ'),
- (0x209, 'V'),
- (0x20A, 'M', 'ȋ'),
- (0x20B, 'V'),
- (0x20C, 'M', 'ȍ'),
- ]
-
-def _seg_5() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x20D, 'V'),
- (0x20E, 'M', 'ȏ'),
- (0x20F, 'V'),
- (0x210, 'M', 'ȑ'),
- (0x211, 'V'),
- (0x212, 'M', 'ȓ'),
- (0x213, 'V'),
- (0x214, 'M', 'ȕ'),
- (0x215, 'V'),
- (0x216, 'M', 'ȗ'),
- (0x217, 'V'),
- (0x218, 'M', 'ș'),
- (0x219, 'V'),
- (0x21A, 'M', 'ț'),
- (0x21B, 'V'),
- (0x21C, 'M', 'ȝ'),
- (0x21D, 'V'),
- (0x21E, 'M', 'ȟ'),
- (0x21F, 'V'),
- (0x220, 'M', 'ƞ'),
- (0x221, 'V'),
- (0x222, 'M', 'ȣ'),
- (0x223, 'V'),
- (0x224, 'M', 'ȥ'),
- (0x225, 'V'),
- (0x226, 'M', 'ȧ'),
- (0x227, 'V'),
- (0x228, 'M', 'ȩ'),
- (0x229, 'V'),
- (0x22A, 'M', 'ȫ'),
- (0x22B, 'V'),
- (0x22C, 'M', 'ȭ'),
- (0x22D, 'V'),
- (0x22E, 'M', 'ȯ'),
- (0x22F, 'V'),
- (0x230, 'M', 'ȱ'),
- (0x231, 'V'),
- (0x232, 'M', 'ȳ'),
- (0x233, 'V'),
- (0x23A, 'M', 'ⱥ'),
- (0x23B, 'M', 'ȼ'),
- (0x23C, 'V'),
- (0x23D, 'M', 'ƚ'),
- (0x23E, 'M', 'ⱦ'),
- (0x23F, 'V'),
- (0x241, 'M', 'ɂ'),
- (0x242, 'V'),
- (0x243, 'M', 'ƀ'),
- (0x244, 'M', 'ʉ'),
- (0x245, 'M', 'ʌ'),
- (0x246, 'M', 'ɇ'),
- (0x247, 'V'),
- (0x248, 'M', 'ɉ'),
- (0x249, 'V'),
- (0x24A, 'M', 'ɋ'),
- (0x24B, 'V'),
- (0x24C, 'M', 'ɍ'),
- (0x24D, 'V'),
- (0x24E, 'M', 'ɏ'),
- (0x24F, 'V'),
- (0x2B0, 'M', 'h'),
- (0x2B1, 'M', 'ɦ'),
- (0x2B2, 'M', 'j'),
- (0x2B3, 'M', 'r'),
- (0x2B4, 'M', 'ɹ'),
- (0x2B5, 'M', 'ɻ'),
- (0x2B6, 'M', 'ʁ'),
- (0x2B7, 'M', 'w'),
- (0x2B8, 'M', 'y'),
- (0x2B9, 'V'),
- (0x2D8, '3', ' ̆'),
- (0x2D9, '3', ' ̇'),
- (0x2DA, '3', ' ̊'),
- (0x2DB, '3', ' ̨'),
- (0x2DC, '3', ' ̃'),
- (0x2DD, '3', ' ̋'),
- (0x2DE, 'V'),
- (0x2E0, 'M', 'ɣ'),
- (0x2E1, 'M', 'l'),
- (0x2E2, 'M', 's'),
- (0x2E3, 'M', 'x'),
- (0x2E4, 'M', 'ʕ'),
- (0x2E5, 'V'),
- (0x340, 'M', '̀'),
- (0x341, 'M', '́'),
- (0x342, 'V'),
- (0x343, 'M', '̓'),
- (0x344, 'M', '̈́'),
- (0x345, 'M', 'ι'),
- (0x346, 'V'),
- (0x34F, 'I'),
- (0x350, 'V'),
- (0x370, 'M', 'ͱ'),
- (0x371, 'V'),
- (0x372, 'M', 'ͳ'),
- (0x373, 'V'),
- (0x374, 'M', 'ʹ'),
- (0x375, 'V'),
- (0x376, 'M', 'ͷ'),
- (0x377, 'V'),
- ]
-
-def _seg_6() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x378, 'X'),
- (0x37A, '3', ' ι'),
- (0x37B, 'V'),
- (0x37E, '3', ';'),
- (0x37F, 'M', 'ϳ'),
- (0x380, 'X'),
- (0x384, '3', ' ́'),
- (0x385, '3', ' ̈́'),
- (0x386, 'M', 'ά'),
- (0x387, 'M', '·'),
- (0x388, 'M', 'έ'),
- (0x389, 'M', 'ή'),
- (0x38A, 'M', 'ί'),
- (0x38B, 'X'),
- (0x38C, 'M', 'ό'),
- (0x38D, 'X'),
- (0x38E, 'M', 'ύ'),
- (0x38F, 'M', 'ώ'),
- (0x390, 'V'),
- (0x391, 'M', 'α'),
- (0x392, 'M', 'β'),
- (0x393, 'M', 'γ'),
- (0x394, 'M', 'δ'),
- (0x395, 'M', 'ε'),
- (0x396, 'M', 'ζ'),
- (0x397, 'M', 'η'),
- (0x398, 'M', 'θ'),
- (0x399, 'M', 'ι'),
- (0x39A, 'M', 'κ'),
- (0x39B, 'M', 'λ'),
- (0x39C, 'M', 'μ'),
- (0x39D, 'M', 'ν'),
- (0x39E, 'M', 'ξ'),
- (0x39F, 'M', 'ο'),
- (0x3A0, 'M', 'π'),
- (0x3A1, 'M', 'ρ'),
- (0x3A2, 'X'),
- (0x3A3, 'M', 'σ'),
- (0x3A4, 'M', 'τ'),
- (0x3A5, 'M', 'υ'),
- (0x3A6, 'M', 'φ'),
- (0x3A7, 'M', 'χ'),
- (0x3A8, 'M', 'ψ'),
- (0x3A9, 'M', 'ω'),
- (0x3AA, 'M', 'ϊ'),
- (0x3AB, 'M', 'ϋ'),
- (0x3AC, 'V'),
- (0x3C2, 'D', 'σ'),
- (0x3C3, 'V'),
- (0x3CF, 'M', 'ϗ'),
- (0x3D0, 'M', 'β'),
- (0x3D1, 'M', 'θ'),
- (0x3D2, 'M', 'υ'),
- (0x3D3, 'M', 'ύ'),
- (0x3D4, 'M', 'ϋ'),
- (0x3D5, 'M', 'φ'),
- (0x3D6, 'M', 'π'),
- (0x3D7, 'V'),
- (0x3D8, 'M', 'ϙ'),
- (0x3D9, 'V'),
- (0x3DA, 'M', 'ϛ'),
- (0x3DB, 'V'),
- (0x3DC, 'M', 'ϝ'),
- (0x3DD, 'V'),
- (0x3DE, 'M', 'ϟ'),
- (0x3DF, 'V'),
- (0x3E0, 'M', 'ϡ'),
- (0x3E1, 'V'),
- (0x3E2, 'M', 'ϣ'),
- (0x3E3, 'V'),
- (0x3E4, 'M', 'ϥ'),
- (0x3E5, 'V'),
- (0x3E6, 'M', 'ϧ'),
- (0x3E7, 'V'),
- (0x3E8, 'M', 'ϩ'),
- (0x3E9, 'V'),
- (0x3EA, 'M', 'ϫ'),
- (0x3EB, 'V'),
- (0x3EC, 'M', 'ϭ'),
- (0x3ED, 'V'),
- (0x3EE, 'M', 'ϯ'),
- (0x3EF, 'V'),
- (0x3F0, 'M', 'κ'),
- (0x3F1, 'M', 'ρ'),
- (0x3F2, 'M', 'σ'),
- (0x3F3, 'V'),
- (0x3F4, 'M', 'θ'),
- (0x3F5, 'M', 'ε'),
- (0x3F6, 'V'),
- (0x3F7, 'M', 'ϸ'),
- (0x3F8, 'V'),
- (0x3F9, 'M', 'σ'),
- (0x3FA, 'M', 'ϻ'),
- (0x3FB, 'V'),
- (0x3FD, 'M', 'ͻ'),
- (0x3FE, 'M', 'ͼ'),
- (0x3FF, 'M', 'ͽ'),
- (0x400, 'M', 'ѐ'),
- (0x401, 'M', 'ё'),
- (0x402, 'M', 'ђ'),
- ]
-
-def _seg_7() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x403, 'M', 'ѓ'),
- (0x404, 'M', 'є'),
- (0x405, 'M', 'ѕ'),
- (0x406, 'M', 'і'),
- (0x407, 'M', 'ї'),
- (0x408, 'M', 'ј'),
- (0x409, 'M', 'љ'),
- (0x40A, 'M', 'њ'),
- (0x40B, 'M', 'ћ'),
- (0x40C, 'M', 'ќ'),
- (0x40D, 'M', 'ѝ'),
- (0x40E, 'M', 'ў'),
- (0x40F, 'M', 'џ'),
- (0x410, 'M', 'а'),
- (0x411, 'M', 'б'),
- (0x412, 'M', 'в'),
- (0x413, 'M', 'г'),
- (0x414, 'M', 'д'),
- (0x415, 'M', 'е'),
- (0x416, 'M', 'ж'),
- (0x417, 'M', 'з'),
- (0x418, 'M', 'и'),
- (0x419, 'M', 'й'),
- (0x41A, 'M', 'к'),
- (0x41B, 'M', 'л'),
- (0x41C, 'M', 'м'),
- (0x41D, 'M', 'н'),
- (0x41E, 'M', 'о'),
- (0x41F, 'M', 'п'),
- (0x420, 'M', 'р'),
- (0x421, 'M', 'с'),
- (0x422, 'M', 'т'),
- (0x423, 'M', 'у'),
- (0x424, 'M', 'ф'),
- (0x425, 'M', 'х'),
- (0x426, 'M', 'ц'),
- (0x427, 'M', 'ч'),
- (0x428, 'M', 'ш'),
- (0x429, 'M', 'щ'),
- (0x42A, 'M', 'ъ'),
- (0x42B, 'M', 'ы'),
- (0x42C, 'M', 'ь'),
- (0x42D, 'M', 'э'),
- (0x42E, 'M', 'ю'),
- (0x42F, 'M', 'я'),
- (0x430, 'V'),
- (0x460, 'M', 'ѡ'),
- (0x461, 'V'),
- (0x462, 'M', 'ѣ'),
- (0x463, 'V'),
- (0x464, 'M', 'ѥ'),
- (0x465, 'V'),
- (0x466, 'M', 'ѧ'),
- (0x467, 'V'),
- (0x468, 'M', 'ѩ'),
- (0x469, 'V'),
- (0x46A, 'M', 'ѫ'),
- (0x46B, 'V'),
- (0x46C, 'M', 'ѭ'),
- (0x46D, 'V'),
- (0x46E, 'M', 'ѯ'),
- (0x46F, 'V'),
- (0x470, 'M', 'ѱ'),
- (0x471, 'V'),
- (0x472, 'M', 'ѳ'),
- (0x473, 'V'),
- (0x474, 'M', 'ѵ'),
- (0x475, 'V'),
- (0x476, 'M', 'ѷ'),
- (0x477, 'V'),
- (0x478, 'M', 'ѹ'),
- (0x479, 'V'),
- (0x47A, 'M', 'ѻ'),
- (0x47B, 'V'),
- (0x47C, 'M', 'ѽ'),
- (0x47D, 'V'),
- (0x47E, 'M', 'ѿ'),
- (0x47F, 'V'),
- (0x480, 'M', 'ҁ'),
- (0x481, 'V'),
- (0x48A, 'M', 'ҋ'),
- (0x48B, 'V'),
- (0x48C, 'M', 'ҍ'),
- (0x48D, 'V'),
- (0x48E, 'M', 'ҏ'),
- (0x48F, 'V'),
- (0x490, 'M', 'ґ'),
- (0x491, 'V'),
- (0x492, 'M', 'ғ'),
- (0x493, 'V'),
- (0x494, 'M', 'ҕ'),
- (0x495, 'V'),
- (0x496, 'M', 'җ'),
- (0x497, 'V'),
- (0x498, 'M', 'ҙ'),
- (0x499, 'V'),
- (0x49A, 'M', 'қ'),
- (0x49B, 'V'),
- (0x49C, 'M', 'ҝ'),
- (0x49D, 'V'),
- ]
-
-def _seg_8() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x49E, 'M', 'ҟ'),
- (0x49F, 'V'),
- (0x4A0, 'M', 'ҡ'),
- (0x4A1, 'V'),
- (0x4A2, 'M', 'ң'),
- (0x4A3, 'V'),
- (0x4A4, 'M', 'ҥ'),
- (0x4A5, 'V'),
- (0x4A6, 'M', 'ҧ'),
- (0x4A7, 'V'),
- (0x4A8, 'M', 'ҩ'),
- (0x4A9, 'V'),
- (0x4AA, 'M', 'ҫ'),
- (0x4AB, 'V'),
- (0x4AC, 'M', 'ҭ'),
- (0x4AD, 'V'),
- (0x4AE, 'M', 'ү'),
- (0x4AF, 'V'),
- (0x4B0, 'M', 'ұ'),
- (0x4B1, 'V'),
- (0x4B2, 'M', 'ҳ'),
- (0x4B3, 'V'),
- (0x4B4, 'M', 'ҵ'),
- (0x4B5, 'V'),
- (0x4B6, 'M', 'ҷ'),
- (0x4B7, 'V'),
- (0x4B8, 'M', 'ҹ'),
- (0x4B9, 'V'),
- (0x4BA, 'M', 'һ'),
- (0x4BB, 'V'),
- (0x4BC, 'M', 'ҽ'),
- (0x4BD, 'V'),
- (0x4BE, 'M', 'ҿ'),
- (0x4BF, 'V'),
- (0x4C0, 'X'),
- (0x4C1, 'M', 'ӂ'),
- (0x4C2, 'V'),
- (0x4C3, 'M', 'ӄ'),
- (0x4C4, 'V'),
- (0x4C5, 'M', 'ӆ'),
- (0x4C6, 'V'),
- (0x4C7, 'M', 'ӈ'),
- (0x4C8, 'V'),
- (0x4C9, 'M', 'ӊ'),
- (0x4CA, 'V'),
- (0x4CB, 'M', 'ӌ'),
- (0x4CC, 'V'),
- (0x4CD, 'M', 'ӎ'),
- (0x4CE, 'V'),
- (0x4D0, 'M', 'ӑ'),
- (0x4D1, 'V'),
- (0x4D2, 'M', 'ӓ'),
- (0x4D3, 'V'),
- (0x4D4, 'M', 'ӕ'),
- (0x4D5, 'V'),
- (0x4D6, 'M', 'ӗ'),
- (0x4D7, 'V'),
- (0x4D8, 'M', 'ә'),
- (0x4D9, 'V'),
- (0x4DA, 'M', 'ӛ'),
- (0x4DB, 'V'),
- (0x4DC, 'M', 'ӝ'),
- (0x4DD, 'V'),
- (0x4DE, 'M', 'ӟ'),
- (0x4DF, 'V'),
- (0x4E0, 'M', 'ӡ'),
- (0x4E1, 'V'),
- (0x4E2, 'M', 'ӣ'),
- (0x4E3, 'V'),
- (0x4E4, 'M', 'ӥ'),
- (0x4E5, 'V'),
- (0x4E6, 'M', 'ӧ'),
- (0x4E7, 'V'),
- (0x4E8, 'M', 'ө'),
- (0x4E9, 'V'),
- (0x4EA, 'M', 'ӫ'),
- (0x4EB, 'V'),
- (0x4EC, 'M', 'ӭ'),
- (0x4ED, 'V'),
- (0x4EE, 'M', 'ӯ'),
- (0x4EF, 'V'),
- (0x4F0, 'M', 'ӱ'),
- (0x4F1, 'V'),
- (0x4F2, 'M', 'ӳ'),
- (0x4F3, 'V'),
- (0x4F4, 'M', 'ӵ'),
- (0x4F5, 'V'),
- (0x4F6, 'M', 'ӷ'),
- (0x4F7, 'V'),
- (0x4F8, 'M', 'ӹ'),
- (0x4F9, 'V'),
- (0x4FA, 'M', 'ӻ'),
- (0x4FB, 'V'),
- (0x4FC, 'M', 'ӽ'),
- (0x4FD, 'V'),
- (0x4FE, 'M', 'ӿ'),
- (0x4FF, 'V'),
- (0x500, 'M', 'ԁ'),
- (0x501, 'V'),
- (0x502, 'M', 'ԃ'),
- ]
-
-def _seg_9() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x503, 'V'),
- (0x504, 'M', 'ԅ'),
- (0x505, 'V'),
- (0x506, 'M', 'ԇ'),
- (0x507, 'V'),
- (0x508, 'M', 'ԉ'),
- (0x509, 'V'),
- (0x50A, 'M', 'ԋ'),
- (0x50B, 'V'),
- (0x50C, 'M', 'ԍ'),
- (0x50D, 'V'),
- (0x50E, 'M', 'ԏ'),
- (0x50F, 'V'),
- (0x510, 'M', 'ԑ'),
- (0x511, 'V'),
- (0x512, 'M', 'ԓ'),
- (0x513, 'V'),
- (0x514, 'M', 'ԕ'),
- (0x515, 'V'),
- (0x516, 'M', 'ԗ'),
- (0x517, 'V'),
- (0x518, 'M', 'ԙ'),
- (0x519, 'V'),
- (0x51A, 'M', 'ԛ'),
- (0x51B, 'V'),
- (0x51C, 'M', 'ԝ'),
- (0x51D, 'V'),
- (0x51E, 'M', 'ԟ'),
- (0x51F, 'V'),
- (0x520, 'M', 'ԡ'),
- (0x521, 'V'),
- (0x522, 'M', 'ԣ'),
- (0x523, 'V'),
- (0x524, 'M', 'ԥ'),
- (0x525, 'V'),
- (0x526, 'M', 'ԧ'),
- (0x527, 'V'),
- (0x528, 'M', 'ԩ'),
- (0x529, 'V'),
- (0x52A, 'M', 'ԫ'),
- (0x52B, 'V'),
- (0x52C, 'M', 'ԭ'),
- (0x52D, 'V'),
- (0x52E, 'M', 'ԯ'),
- (0x52F, 'V'),
- (0x530, 'X'),
- (0x531, 'M', 'ա'),
- (0x532, 'M', 'բ'),
- (0x533, 'M', 'գ'),
- (0x534, 'M', 'դ'),
- (0x535, 'M', 'ե'),
- (0x536, 'M', 'զ'),
- (0x537, 'M', 'է'),
- (0x538, 'M', 'ը'),
- (0x539, 'M', 'թ'),
- (0x53A, 'M', 'ժ'),
- (0x53B, 'M', 'ի'),
- (0x53C, 'M', 'լ'),
- (0x53D, 'M', 'խ'),
- (0x53E, 'M', 'ծ'),
- (0x53F, 'M', 'կ'),
- (0x540, 'M', 'հ'),
- (0x541, 'M', 'ձ'),
- (0x542, 'M', 'ղ'),
- (0x543, 'M', 'ճ'),
- (0x544, 'M', 'մ'),
- (0x545, 'M', 'յ'),
- (0x546, 'M', 'ն'),
- (0x547, 'M', 'շ'),
- (0x548, 'M', 'ո'),
- (0x549, 'M', 'չ'),
- (0x54A, 'M', 'պ'),
- (0x54B, 'M', 'ջ'),
- (0x54C, 'M', 'ռ'),
- (0x54D, 'M', 'ս'),
- (0x54E, 'M', 'վ'),
- (0x54F, 'M', 'տ'),
- (0x550, 'M', 'ր'),
- (0x551, 'M', 'ց'),
- (0x552, 'M', 'ւ'),
- (0x553, 'M', 'փ'),
- (0x554, 'M', 'ք'),
- (0x555, 'M', 'օ'),
- (0x556, 'M', 'ֆ'),
- (0x557, 'X'),
- (0x559, 'V'),
- (0x587, 'M', 'եւ'),
- (0x588, 'V'),
- (0x58B, 'X'),
- (0x58D, 'V'),
- (0x590, 'X'),
- (0x591, 'V'),
- (0x5C8, 'X'),
- (0x5D0, 'V'),
- (0x5EB, 'X'),
- (0x5EF, 'V'),
- (0x5F5, 'X'),
- (0x606, 'V'),
- (0x61C, 'X'),
- (0x61D, 'V'),
- ]
-
-def _seg_10() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x675, 'M', 'اٴ'),
- (0x676, 'M', 'وٴ'),
- (0x677, 'M', 'ۇٴ'),
- (0x678, 'M', 'يٴ'),
- (0x679, 'V'),
- (0x6DD, 'X'),
- (0x6DE, 'V'),
- (0x70E, 'X'),
- (0x710, 'V'),
- (0x74B, 'X'),
- (0x74D, 'V'),
- (0x7B2, 'X'),
- (0x7C0, 'V'),
- (0x7FB, 'X'),
- (0x7FD, 'V'),
- (0x82E, 'X'),
- (0x830, 'V'),
- (0x83F, 'X'),
- (0x840, 'V'),
- (0x85C, 'X'),
- (0x85E, 'V'),
- (0x85F, 'X'),
- (0x860, 'V'),
- (0x86B, 'X'),
- (0x870, 'V'),
- (0x88F, 'X'),
- (0x898, 'V'),
- (0x8E2, 'X'),
- (0x8E3, 'V'),
- (0x958, 'M', 'क़'),
- (0x959, 'M', 'ख़'),
- (0x95A, 'M', 'ग़'),
- (0x95B, 'M', 'ज़'),
- (0x95C, 'M', 'ड़'),
- (0x95D, 'M', 'ढ़'),
- (0x95E, 'M', 'फ़'),
- (0x95F, 'M', 'य़'),
- (0x960, 'V'),
- (0x984, 'X'),
- (0x985, 'V'),
- (0x98D, 'X'),
- (0x98F, 'V'),
- (0x991, 'X'),
- (0x993, 'V'),
- (0x9A9, 'X'),
- (0x9AA, 'V'),
- (0x9B1, 'X'),
- (0x9B2, 'V'),
- (0x9B3, 'X'),
- (0x9B6, 'V'),
- (0x9BA, 'X'),
- (0x9BC, 'V'),
- (0x9C5, 'X'),
- (0x9C7, 'V'),
- (0x9C9, 'X'),
- (0x9CB, 'V'),
- (0x9CF, 'X'),
- (0x9D7, 'V'),
- (0x9D8, 'X'),
- (0x9DC, 'M', 'ড়'),
- (0x9DD, 'M', 'ঢ়'),
- (0x9DE, 'X'),
- (0x9DF, 'M', 'য়'),
- (0x9E0, 'V'),
- (0x9E4, 'X'),
- (0x9E6, 'V'),
- (0x9FF, 'X'),
- (0xA01, 'V'),
- (0xA04, 'X'),
- (0xA05, 'V'),
- (0xA0B, 'X'),
- (0xA0F, 'V'),
- (0xA11, 'X'),
- (0xA13, 'V'),
- (0xA29, 'X'),
- (0xA2A, 'V'),
- (0xA31, 'X'),
- (0xA32, 'V'),
- (0xA33, 'M', 'ਲ਼'),
- (0xA34, 'X'),
- (0xA35, 'V'),
- (0xA36, 'M', 'ਸ਼'),
- (0xA37, 'X'),
- (0xA38, 'V'),
- (0xA3A, 'X'),
- (0xA3C, 'V'),
- (0xA3D, 'X'),
- (0xA3E, 'V'),
- (0xA43, 'X'),
- (0xA47, 'V'),
- (0xA49, 'X'),
- (0xA4B, 'V'),
- (0xA4E, 'X'),
- (0xA51, 'V'),
- (0xA52, 'X'),
- (0xA59, 'M', 'ਖ਼'),
- (0xA5A, 'M', 'ਗ਼'),
- (0xA5B, 'M', 'ਜ਼'),
- (0xA5C, 'V'),
- (0xA5D, 'X'),
- ]
-
-def _seg_11() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xA5E, 'M', 'ਫ਼'),
- (0xA5F, 'X'),
- (0xA66, 'V'),
- (0xA77, 'X'),
- (0xA81, 'V'),
- (0xA84, 'X'),
- (0xA85, 'V'),
- (0xA8E, 'X'),
- (0xA8F, 'V'),
- (0xA92, 'X'),
- (0xA93, 'V'),
- (0xAA9, 'X'),
- (0xAAA, 'V'),
- (0xAB1, 'X'),
- (0xAB2, 'V'),
- (0xAB4, 'X'),
- (0xAB5, 'V'),
- (0xABA, 'X'),
- (0xABC, 'V'),
- (0xAC6, 'X'),
- (0xAC7, 'V'),
- (0xACA, 'X'),
- (0xACB, 'V'),
- (0xACE, 'X'),
- (0xAD0, 'V'),
- (0xAD1, 'X'),
- (0xAE0, 'V'),
- (0xAE4, 'X'),
- (0xAE6, 'V'),
- (0xAF2, 'X'),
- (0xAF9, 'V'),
- (0xB00, 'X'),
- (0xB01, 'V'),
- (0xB04, 'X'),
- (0xB05, 'V'),
- (0xB0D, 'X'),
- (0xB0F, 'V'),
- (0xB11, 'X'),
- (0xB13, 'V'),
- (0xB29, 'X'),
- (0xB2A, 'V'),
- (0xB31, 'X'),
- (0xB32, 'V'),
- (0xB34, 'X'),
- (0xB35, 'V'),
- (0xB3A, 'X'),
- (0xB3C, 'V'),
- (0xB45, 'X'),
- (0xB47, 'V'),
- (0xB49, 'X'),
- (0xB4B, 'V'),
- (0xB4E, 'X'),
- (0xB55, 'V'),
- (0xB58, 'X'),
- (0xB5C, 'M', 'ଡ଼'),
- (0xB5D, 'M', 'ଢ଼'),
- (0xB5E, 'X'),
- (0xB5F, 'V'),
- (0xB64, 'X'),
- (0xB66, 'V'),
- (0xB78, 'X'),
- (0xB82, 'V'),
- (0xB84, 'X'),
- (0xB85, 'V'),
- (0xB8B, 'X'),
- (0xB8E, 'V'),
- (0xB91, 'X'),
- (0xB92, 'V'),
- (0xB96, 'X'),
- (0xB99, 'V'),
- (0xB9B, 'X'),
- (0xB9C, 'V'),
- (0xB9D, 'X'),
- (0xB9E, 'V'),
- (0xBA0, 'X'),
- (0xBA3, 'V'),
- (0xBA5, 'X'),
- (0xBA8, 'V'),
- (0xBAB, 'X'),
- (0xBAE, 'V'),
- (0xBBA, 'X'),
- (0xBBE, 'V'),
- (0xBC3, 'X'),
- (0xBC6, 'V'),
- (0xBC9, 'X'),
- (0xBCA, 'V'),
- (0xBCE, 'X'),
- (0xBD0, 'V'),
- (0xBD1, 'X'),
- (0xBD7, 'V'),
- (0xBD8, 'X'),
- (0xBE6, 'V'),
- (0xBFB, 'X'),
- (0xC00, 'V'),
- (0xC0D, 'X'),
- (0xC0E, 'V'),
- (0xC11, 'X'),
- (0xC12, 'V'),
- (0xC29, 'X'),
- (0xC2A, 'V'),
- ]
-
-def _seg_12() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xC3A, 'X'),
- (0xC3C, 'V'),
- (0xC45, 'X'),
- (0xC46, 'V'),
- (0xC49, 'X'),
- (0xC4A, 'V'),
- (0xC4E, 'X'),
- (0xC55, 'V'),
- (0xC57, 'X'),
- (0xC58, 'V'),
- (0xC5B, 'X'),
- (0xC5D, 'V'),
- (0xC5E, 'X'),
- (0xC60, 'V'),
- (0xC64, 'X'),
- (0xC66, 'V'),
- (0xC70, 'X'),
- (0xC77, 'V'),
- (0xC8D, 'X'),
- (0xC8E, 'V'),
- (0xC91, 'X'),
- (0xC92, 'V'),
- (0xCA9, 'X'),
- (0xCAA, 'V'),
- (0xCB4, 'X'),
- (0xCB5, 'V'),
- (0xCBA, 'X'),
- (0xCBC, 'V'),
- (0xCC5, 'X'),
- (0xCC6, 'V'),
- (0xCC9, 'X'),
- (0xCCA, 'V'),
- (0xCCE, 'X'),
- (0xCD5, 'V'),
- (0xCD7, 'X'),
- (0xCDD, 'V'),
- (0xCDF, 'X'),
- (0xCE0, 'V'),
- (0xCE4, 'X'),
- (0xCE6, 'V'),
- (0xCF0, 'X'),
- (0xCF1, 'V'),
- (0xCF4, 'X'),
- (0xD00, 'V'),
- (0xD0D, 'X'),
- (0xD0E, 'V'),
- (0xD11, 'X'),
- (0xD12, 'V'),
- (0xD45, 'X'),
- (0xD46, 'V'),
- (0xD49, 'X'),
- (0xD4A, 'V'),
- (0xD50, 'X'),
- (0xD54, 'V'),
- (0xD64, 'X'),
- (0xD66, 'V'),
- (0xD80, 'X'),
- (0xD81, 'V'),
- (0xD84, 'X'),
- (0xD85, 'V'),
- (0xD97, 'X'),
- (0xD9A, 'V'),
- (0xDB2, 'X'),
- (0xDB3, 'V'),
- (0xDBC, 'X'),
- (0xDBD, 'V'),
- (0xDBE, 'X'),
- (0xDC0, 'V'),
- (0xDC7, 'X'),
- (0xDCA, 'V'),
- (0xDCB, 'X'),
- (0xDCF, 'V'),
- (0xDD5, 'X'),
- (0xDD6, 'V'),
- (0xDD7, 'X'),
- (0xDD8, 'V'),
- (0xDE0, 'X'),
- (0xDE6, 'V'),
- (0xDF0, 'X'),
- (0xDF2, 'V'),
- (0xDF5, 'X'),
- (0xE01, 'V'),
- (0xE33, 'M', 'ํา'),
- (0xE34, 'V'),
- (0xE3B, 'X'),
- (0xE3F, 'V'),
- (0xE5C, 'X'),
- (0xE81, 'V'),
- (0xE83, 'X'),
- (0xE84, 'V'),
- (0xE85, 'X'),
- (0xE86, 'V'),
- (0xE8B, 'X'),
- (0xE8C, 'V'),
- (0xEA4, 'X'),
- (0xEA5, 'V'),
- (0xEA6, 'X'),
- (0xEA7, 'V'),
- (0xEB3, 'M', 'ໍາ'),
- (0xEB4, 'V'),
- ]
-
-def _seg_13() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xEBE, 'X'),
- (0xEC0, 'V'),
- (0xEC5, 'X'),
- (0xEC6, 'V'),
- (0xEC7, 'X'),
- (0xEC8, 'V'),
- (0xECF, 'X'),
- (0xED0, 'V'),
- (0xEDA, 'X'),
- (0xEDC, 'M', 'ຫນ'),
- (0xEDD, 'M', 'ຫມ'),
- (0xEDE, 'V'),
- (0xEE0, 'X'),
- (0xF00, 'V'),
- (0xF0C, 'M', '་'),
- (0xF0D, 'V'),
- (0xF43, 'M', 'གྷ'),
- (0xF44, 'V'),
- (0xF48, 'X'),
- (0xF49, 'V'),
- (0xF4D, 'M', 'ཌྷ'),
- (0xF4E, 'V'),
- (0xF52, 'M', 'དྷ'),
- (0xF53, 'V'),
- (0xF57, 'M', 'བྷ'),
- (0xF58, 'V'),
- (0xF5C, 'M', 'ཛྷ'),
- (0xF5D, 'V'),
- (0xF69, 'M', 'ཀྵ'),
- (0xF6A, 'V'),
- (0xF6D, 'X'),
- (0xF71, 'V'),
- (0xF73, 'M', 'ཱི'),
- (0xF74, 'V'),
- (0xF75, 'M', 'ཱུ'),
- (0xF76, 'M', 'ྲྀ'),
- (0xF77, 'M', 'ྲཱྀ'),
- (0xF78, 'M', 'ླྀ'),
- (0xF79, 'M', 'ླཱྀ'),
- (0xF7A, 'V'),
- (0xF81, 'M', 'ཱྀ'),
- (0xF82, 'V'),
- (0xF93, 'M', 'ྒྷ'),
- (0xF94, 'V'),
- (0xF98, 'X'),
- (0xF99, 'V'),
- (0xF9D, 'M', 'ྜྷ'),
- (0xF9E, 'V'),
- (0xFA2, 'M', 'ྡྷ'),
- (0xFA3, 'V'),
- (0xFA7, 'M', 'ྦྷ'),
- (0xFA8, 'V'),
- (0xFAC, 'M', 'ྫྷ'),
- (0xFAD, 'V'),
- (0xFB9, 'M', 'ྐྵ'),
- (0xFBA, 'V'),
- (0xFBD, 'X'),
- (0xFBE, 'V'),
- (0xFCD, 'X'),
- (0xFCE, 'V'),
- (0xFDB, 'X'),
- (0x1000, 'V'),
- (0x10A0, 'X'),
- (0x10C7, 'M', 'ⴧ'),
- (0x10C8, 'X'),
- (0x10CD, 'M', 'ⴭ'),
- (0x10CE, 'X'),
- (0x10D0, 'V'),
- (0x10FC, 'M', 'ნ'),
- (0x10FD, 'V'),
- (0x115F, 'X'),
- (0x1161, 'V'),
- (0x1249, 'X'),
- (0x124A, 'V'),
- (0x124E, 'X'),
- (0x1250, 'V'),
- (0x1257, 'X'),
- (0x1258, 'V'),
- (0x1259, 'X'),
- (0x125A, 'V'),
- (0x125E, 'X'),
- (0x1260, 'V'),
- (0x1289, 'X'),
- (0x128A, 'V'),
- (0x128E, 'X'),
- (0x1290, 'V'),
- (0x12B1, 'X'),
- (0x12B2, 'V'),
- (0x12B6, 'X'),
- (0x12B8, 'V'),
- (0x12BF, 'X'),
- (0x12C0, 'V'),
- (0x12C1, 'X'),
- (0x12C2, 'V'),
- (0x12C6, 'X'),
- (0x12C8, 'V'),
- (0x12D7, 'X'),
- (0x12D8, 'V'),
- (0x1311, 'X'),
- (0x1312, 'V'),
- ]
-
-def _seg_14() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1316, 'X'),
- (0x1318, 'V'),
- (0x135B, 'X'),
- (0x135D, 'V'),
- (0x137D, 'X'),
- (0x1380, 'V'),
- (0x139A, 'X'),
- (0x13A0, 'V'),
- (0x13F6, 'X'),
- (0x13F8, 'M', 'Ᏸ'),
- (0x13F9, 'M', 'Ᏹ'),
- (0x13FA, 'M', 'Ᏺ'),
- (0x13FB, 'M', 'Ᏻ'),
- (0x13FC, 'M', 'Ᏼ'),
- (0x13FD, 'M', 'Ᏽ'),
- (0x13FE, 'X'),
- (0x1400, 'V'),
- (0x1680, 'X'),
- (0x1681, 'V'),
- (0x169D, 'X'),
- (0x16A0, 'V'),
- (0x16F9, 'X'),
- (0x1700, 'V'),
- (0x1716, 'X'),
- (0x171F, 'V'),
- (0x1737, 'X'),
- (0x1740, 'V'),
- (0x1754, 'X'),
- (0x1760, 'V'),
- (0x176D, 'X'),
- (0x176E, 'V'),
- (0x1771, 'X'),
- (0x1772, 'V'),
- (0x1774, 'X'),
- (0x1780, 'V'),
- (0x17B4, 'X'),
- (0x17B6, 'V'),
- (0x17DE, 'X'),
- (0x17E0, 'V'),
- (0x17EA, 'X'),
- (0x17F0, 'V'),
- (0x17FA, 'X'),
- (0x1800, 'V'),
- (0x1806, 'X'),
- (0x1807, 'V'),
- (0x180B, 'I'),
- (0x180E, 'X'),
- (0x180F, 'I'),
- (0x1810, 'V'),
- (0x181A, 'X'),
- (0x1820, 'V'),
- (0x1879, 'X'),
- (0x1880, 'V'),
- (0x18AB, 'X'),
- (0x18B0, 'V'),
- (0x18F6, 'X'),
- (0x1900, 'V'),
- (0x191F, 'X'),
- (0x1920, 'V'),
- (0x192C, 'X'),
- (0x1930, 'V'),
- (0x193C, 'X'),
- (0x1940, 'V'),
- (0x1941, 'X'),
- (0x1944, 'V'),
- (0x196E, 'X'),
- (0x1970, 'V'),
- (0x1975, 'X'),
- (0x1980, 'V'),
- (0x19AC, 'X'),
- (0x19B0, 'V'),
- (0x19CA, 'X'),
- (0x19D0, 'V'),
- (0x19DB, 'X'),
- (0x19DE, 'V'),
- (0x1A1C, 'X'),
- (0x1A1E, 'V'),
- (0x1A5F, 'X'),
- (0x1A60, 'V'),
- (0x1A7D, 'X'),
- (0x1A7F, 'V'),
- (0x1A8A, 'X'),
- (0x1A90, 'V'),
- (0x1A9A, 'X'),
- (0x1AA0, 'V'),
- (0x1AAE, 'X'),
- (0x1AB0, 'V'),
- (0x1ACF, 'X'),
- (0x1B00, 'V'),
- (0x1B4D, 'X'),
- (0x1B50, 'V'),
- (0x1B7F, 'X'),
- (0x1B80, 'V'),
- (0x1BF4, 'X'),
- (0x1BFC, 'V'),
- (0x1C38, 'X'),
- (0x1C3B, 'V'),
- (0x1C4A, 'X'),
- (0x1C4D, 'V'),
- (0x1C80, 'M', 'в'),
- ]
-
-def _seg_15() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1C81, 'M', 'д'),
- (0x1C82, 'M', 'о'),
- (0x1C83, 'M', 'с'),
- (0x1C84, 'M', 'т'),
- (0x1C86, 'M', 'ъ'),
- (0x1C87, 'M', 'ѣ'),
- (0x1C88, 'M', 'ꙋ'),
- (0x1C89, 'X'),
- (0x1C90, 'M', 'ა'),
- (0x1C91, 'M', 'ბ'),
- (0x1C92, 'M', 'გ'),
- (0x1C93, 'M', 'დ'),
- (0x1C94, 'M', 'ე'),
- (0x1C95, 'M', 'ვ'),
- (0x1C96, 'M', 'ზ'),
- (0x1C97, 'M', 'თ'),
- (0x1C98, 'M', 'ი'),
- (0x1C99, 'M', 'კ'),
- (0x1C9A, 'M', 'ლ'),
- (0x1C9B, 'M', 'მ'),
- (0x1C9C, 'M', 'ნ'),
- (0x1C9D, 'M', 'ო'),
- (0x1C9E, 'M', 'პ'),
- (0x1C9F, 'M', 'ჟ'),
- (0x1CA0, 'M', 'რ'),
- (0x1CA1, 'M', 'ს'),
- (0x1CA2, 'M', 'ტ'),
- (0x1CA3, 'M', 'უ'),
- (0x1CA4, 'M', 'ფ'),
- (0x1CA5, 'M', 'ქ'),
- (0x1CA6, 'M', 'ღ'),
- (0x1CA7, 'M', 'ყ'),
- (0x1CA8, 'M', 'შ'),
- (0x1CA9, 'M', 'ჩ'),
- (0x1CAA, 'M', 'ც'),
- (0x1CAB, 'M', 'ძ'),
- (0x1CAC, 'M', 'წ'),
- (0x1CAD, 'M', 'ჭ'),
- (0x1CAE, 'M', 'ხ'),
- (0x1CAF, 'M', 'ჯ'),
- (0x1CB0, 'M', 'ჰ'),
- (0x1CB1, 'M', 'ჱ'),
- (0x1CB2, 'M', 'ჲ'),
- (0x1CB3, 'M', 'ჳ'),
- (0x1CB4, 'M', 'ჴ'),
- (0x1CB5, 'M', 'ჵ'),
- (0x1CB6, 'M', 'ჶ'),
- (0x1CB7, 'M', 'ჷ'),
- (0x1CB8, 'M', 'ჸ'),
- (0x1CB9, 'M', 'ჹ'),
- (0x1CBA, 'M', 'ჺ'),
- (0x1CBB, 'X'),
- (0x1CBD, 'M', 'ჽ'),
- (0x1CBE, 'M', 'ჾ'),
- (0x1CBF, 'M', 'ჿ'),
- (0x1CC0, 'V'),
- (0x1CC8, 'X'),
- (0x1CD0, 'V'),
- (0x1CFB, 'X'),
- (0x1D00, 'V'),
- (0x1D2C, 'M', 'a'),
- (0x1D2D, 'M', 'æ'),
- (0x1D2E, 'M', 'b'),
- (0x1D2F, 'V'),
- (0x1D30, 'M', 'd'),
- (0x1D31, 'M', 'e'),
- (0x1D32, 'M', 'ǝ'),
- (0x1D33, 'M', 'g'),
- (0x1D34, 'M', 'h'),
- (0x1D35, 'M', 'i'),
- (0x1D36, 'M', 'j'),
- (0x1D37, 'M', 'k'),
- (0x1D38, 'M', 'l'),
- (0x1D39, 'M', 'm'),
- (0x1D3A, 'M', 'n'),
- (0x1D3B, 'V'),
- (0x1D3C, 'M', 'o'),
- (0x1D3D, 'M', 'ȣ'),
- (0x1D3E, 'M', 'p'),
- (0x1D3F, 'M', 'r'),
- (0x1D40, 'M', 't'),
- (0x1D41, 'M', 'u'),
- (0x1D42, 'M', 'w'),
- (0x1D43, 'M', 'a'),
- (0x1D44, 'M', 'ɐ'),
- (0x1D45, 'M', 'ɑ'),
- (0x1D46, 'M', 'ᴂ'),
- (0x1D47, 'M', 'b'),
- (0x1D48, 'M', 'd'),
- (0x1D49, 'M', 'e'),
- (0x1D4A, 'M', 'ə'),
- (0x1D4B, 'M', 'ɛ'),
- (0x1D4C, 'M', 'ɜ'),
- (0x1D4D, 'M', 'g'),
- (0x1D4E, 'V'),
- (0x1D4F, 'M', 'k'),
- (0x1D50, 'M', 'm'),
- (0x1D51, 'M', 'ŋ'),
- (0x1D52, 'M', 'o'),
- (0x1D53, 'M', 'ɔ'),
- ]
-
-def _seg_16() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D54, 'M', 'ᴖ'),
- (0x1D55, 'M', 'ᴗ'),
- (0x1D56, 'M', 'p'),
- (0x1D57, 'M', 't'),
- (0x1D58, 'M', 'u'),
- (0x1D59, 'M', 'ᴝ'),
- (0x1D5A, 'M', 'ɯ'),
- (0x1D5B, 'M', 'v'),
- (0x1D5C, 'M', 'ᴥ'),
- (0x1D5D, 'M', 'β'),
- (0x1D5E, 'M', 'γ'),
- (0x1D5F, 'M', 'δ'),
- (0x1D60, 'M', 'φ'),
- (0x1D61, 'M', 'χ'),
- (0x1D62, 'M', 'i'),
- (0x1D63, 'M', 'r'),
- (0x1D64, 'M', 'u'),
- (0x1D65, 'M', 'v'),
- (0x1D66, 'M', 'β'),
- (0x1D67, 'M', 'γ'),
- (0x1D68, 'M', 'ρ'),
- (0x1D69, 'M', 'φ'),
- (0x1D6A, 'M', 'χ'),
- (0x1D6B, 'V'),
- (0x1D78, 'M', 'н'),
- (0x1D79, 'V'),
- (0x1D9B, 'M', 'ɒ'),
- (0x1D9C, 'M', 'c'),
- (0x1D9D, 'M', 'ɕ'),
- (0x1D9E, 'M', 'ð'),
- (0x1D9F, 'M', 'ɜ'),
- (0x1DA0, 'M', 'f'),
- (0x1DA1, 'M', 'ɟ'),
- (0x1DA2, 'M', 'ɡ'),
- (0x1DA3, 'M', 'ɥ'),
- (0x1DA4, 'M', 'ɨ'),
- (0x1DA5, 'M', 'ɩ'),
- (0x1DA6, 'M', 'ɪ'),
- (0x1DA7, 'M', 'ᵻ'),
- (0x1DA8, 'M', 'ʝ'),
- (0x1DA9, 'M', 'ɭ'),
- (0x1DAA, 'M', 'ᶅ'),
- (0x1DAB, 'M', 'ʟ'),
- (0x1DAC, 'M', 'ɱ'),
- (0x1DAD, 'M', 'ɰ'),
- (0x1DAE, 'M', 'ɲ'),
- (0x1DAF, 'M', 'ɳ'),
- (0x1DB0, 'M', 'ɴ'),
- (0x1DB1, 'M', 'ɵ'),
- (0x1DB2, 'M', 'ɸ'),
- (0x1DB3, 'M', 'ʂ'),
- (0x1DB4, 'M', 'ʃ'),
- (0x1DB5, 'M', 'ƫ'),
- (0x1DB6, 'M', 'ʉ'),
- (0x1DB7, 'M', 'ʊ'),
- (0x1DB8, 'M', 'ᴜ'),
- (0x1DB9, 'M', 'ʋ'),
- (0x1DBA, 'M', 'ʌ'),
- (0x1DBB, 'M', 'z'),
- (0x1DBC, 'M', 'ʐ'),
- (0x1DBD, 'M', 'ʑ'),
- (0x1DBE, 'M', 'ʒ'),
- (0x1DBF, 'M', 'θ'),
- (0x1DC0, 'V'),
- (0x1E00, 'M', 'ḁ'),
- (0x1E01, 'V'),
- (0x1E02, 'M', 'ḃ'),
- (0x1E03, 'V'),
- (0x1E04, 'M', 'ḅ'),
- (0x1E05, 'V'),
- (0x1E06, 'M', 'ḇ'),
- (0x1E07, 'V'),
- (0x1E08, 'M', 'ḉ'),
- (0x1E09, 'V'),
- (0x1E0A, 'M', 'ḋ'),
- (0x1E0B, 'V'),
- (0x1E0C, 'M', 'ḍ'),
- (0x1E0D, 'V'),
- (0x1E0E, 'M', 'ḏ'),
- (0x1E0F, 'V'),
- (0x1E10, 'M', 'ḑ'),
- (0x1E11, 'V'),
- (0x1E12, 'M', 'ḓ'),
- (0x1E13, 'V'),
- (0x1E14, 'M', 'ḕ'),
- (0x1E15, 'V'),
- (0x1E16, 'M', 'ḗ'),
- (0x1E17, 'V'),
- (0x1E18, 'M', 'ḙ'),
- (0x1E19, 'V'),
- (0x1E1A, 'M', 'ḛ'),
- (0x1E1B, 'V'),
- (0x1E1C, 'M', 'ḝ'),
- (0x1E1D, 'V'),
- (0x1E1E, 'M', 'ḟ'),
- (0x1E1F, 'V'),
- (0x1E20, 'M', 'ḡ'),
- (0x1E21, 'V'),
- (0x1E22, 'M', 'ḣ'),
- (0x1E23, 'V'),
- ]
-
-def _seg_17() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1E24, 'M', 'ḥ'),
- (0x1E25, 'V'),
- (0x1E26, 'M', 'ḧ'),
- (0x1E27, 'V'),
- (0x1E28, 'M', 'ḩ'),
- (0x1E29, 'V'),
- (0x1E2A, 'M', 'ḫ'),
- (0x1E2B, 'V'),
- (0x1E2C, 'M', 'ḭ'),
- (0x1E2D, 'V'),
- (0x1E2E, 'M', 'ḯ'),
- (0x1E2F, 'V'),
- (0x1E30, 'M', 'ḱ'),
- (0x1E31, 'V'),
- (0x1E32, 'M', 'ḳ'),
- (0x1E33, 'V'),
- (0x1E34, 'M', 'ḵ'),
- (0x1E35, 'V'),
- (0x1E36, 'M', 'ḷ'),
- (0x1E37, 'V'),
- (0x1E38, 'M', 'ḹ'),
- (0x1E39, 'V'),
- (0x1E3A, 'M', 'ḻ'),
- (0x1E3B, 'V'),
- (0x1E3C, 'M', 'ḽ'),
- (0x1E3D, 'V'),
- (0x1E3E, 'M', 'ḿ'),
- (0x1E3F, 'V'),
- (0x1E40, 'M', 'ṁ'),
- (0x1E41, 'V'),
- (0x1E42, 'M', 'ṃ'),
- (0x1E43, 'V'),
- (0x1E44, 'M', 'ṅ'),
- (0x1E45, 'V'),
- (0x1E46, 'M', 'ṇ'),
- (0x1E47, 'V'),
- (0x1E48, 'M', 'ṉ'),
- (0x1E49, 'V'),
- (0x1E4A, 'M', 'ṋ'),
- (0x1E4B, 'V'),
- (0x1E4C, 'M', 'ṍ'),
- (0x1E4D, 'V'),
- (0x1E4E, 'M', 'ṏ'),
- (0x1E4F, 'V'),
- (0x1E50, 'M', 'ṑ'),
- (0x1E51, 'V'),
- (0x1E52, 'M', 'ṓ'),
- (0x1E53, 'V'),
- (0x1E54, 'M', 'ṕ'),
- (0x1E55, 'V'),
- (0x1E56, 'M', 'ṗ'),
- (0x1E57, 'V'),
- (0x1E58, 'M', 'ṙ'),
- (0x1E59, 'V'),
- (0x1E5A, 'M', 'ṛ'),
- (0x1E5B, 'V'),
- (0x1E5C, 'M', 'ṝ'),
- (0x1E5D, 'V'),
- (0x1E5E, 'M', 'ṟ'),
- (0x1E5F, 'V'),
- (0x1E60, 'M', 'ṡ'),
- (0x1E61, 'V'),
- (0x1E62, 'M', 'ṣ'),
- (0x1E63, 'V'),
- (0x1E64, 'M', 'ṥ'),
- (0x1E65, 'V'),
- (0x1E66, 'M', 'ṧ'),
- (0x1E67, 'V'),
- (0x1E68, 'M', 'ṩ'),
- (0x1E69, 'V'),
- (0x1E6A, 'M', 'ṫ'),
- (0x1E6B, 'V'),
- (0x1E6C, 'M', 'ṭ'),
- (0x1E6D, 'V'),
- (0x1E6E, 'M', 'ṯ'),
- (0x1E6F, 'V'),
- (0x1E70, 'M', 'ṱ'),
- (0x1E71, 'V'),
- (0x1E72, 'M', 'ṳ'),
- (0x1E73, 'V'),
- (0x1E74, 'M', 'ṵ'),
- (0x1E75, 'V'),
- (0x1E76, 'M', 'ṷ'),
- (0x1E77, 'V'),
- (0x1E78, 'M', 'ṹ'),
- (0x1E79, 'V'),
- (0x1E7A, 'M', 'ṻ'),
- (0x1E7B, 'V'),
- (0x1E7C, 'M', 'ṽ'),
- (0x1E7D, 'V'),
- (0x1E7E, 'M', 'ṿ'),
- (0x1E7F, 'V'),
- (0x1E80, 'M', 'ẁ'),
- (0x1E81, 'V'),
- (0x1E82, 'M', 'ẃ'),
- (0x1E83, 'V'),
- (0x1E84, 'M', 'ẅ'),
- (0x1E85, 'V'),
- (0x1E86, 'M', 'ẇ'),
- (0x1E87, 'V'),
- ]
-
-def _seg_18() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1E88, 'M', 'ẉ'),
- (0x1E89, 'V'),
- (0x1E8A, 'M', 'ẋ'),
- (0x1E8B, 'V'),
- (0x1E8C, 'M', 'ẍ'),
- (0x1E8D, 'V'),
- (0x1E8E, 'M', 'ẏ'),
- (0x1E8F, 'V'),
- (0x1E90, 'M', 'ẑ'),
- (0x1E91, 'V'),
- (0x1E92, 'M', 'ẓ'),
- (0x1E93, 'V'),
- (0x1E94, 'M', 'ẕ'),
- (0x1E95, 'V'),
- (0x1E9A, 'M', 'aʾ'),
- (0x1E9B, 'M', 'ṡ'),
- (0x1E9C, 'V'),
- (0x1E9E, 'M', 'ß'),
- (0x1E9F, 'V'),
- (0x1EA0, 'M', 'ạ'),
- (0x1EA1, 'V'),
- (0x1EA2, 'M', 'ả'),
- (0x1EA3, 'V'),
- (0x1EA4, 'M', 'ấ'),
- (0x1EA5, 'V'),
- (0x1EA6, 'M', 'ầ'),
- (0x1EA7, 'V'),
- (0x1EA8, 'M', 'ẩ'),
- (0x1EA9, 'V'),
- (0x1EAA, 'M', 'ẫ'),
- (0x1EAB, 'V'),
- (0x1EAC, 'M', 'ậ'),
- (0x1EAD, 'V'),
- (0x1EAE, 'M', 'ắ'),
- (0x1EAF, 'V'),
- (0x1EB0, 'M', 'ằ'),
- (0x1EB1, 'V'),
- (0x1EB2, 'M', 'ẳ'),
- (0x1EB3, 'V'),
- (0x1EB4, 'M', 'ẵ'),
- (0x1EB5, 'V'),
- (0x1EB6, 'M', 'ặ'),
- (0x1EB7, 'V'),
- (0x1EB8, 'M', 'ẹ'),
- (0x1EB9, 'V'),
- (0x1EBA, 'M', 'ẻ'),
- (0x1EBB, 'V'),
- (0x1EBC, 'M', 'ẽ'),
- (0x1EBD, 'V'),
- (0x1EBE, 'M', 'ế'),
- (0x1EBF, 'V'),
- (0x1EC0, 'M', 'ề'),
- (0x1EC1, 'V'),
- (0x1EC2, 'M', 'ể'),
- (0x1EC3, 'V'),
- (0x1EC4, 'M', 'ễ'),
- (0x1EC5, 'V'),
- (0x1EC6, 'M', 'ệ'),
- (0x1EC7, 'V'),
- (0x1EC8, 'M', 'ỉ'),
- (0x1EC9, 'V'),
- (0x1ECA, 'M', 'ị'),
- (0x1ECB, 'V'),
- (0x1ECC, 'M', 'ọ'),
- (0x1ECD, 'V'),
- (0x1ECE, 'M', 'ỏ'),
- (0x1ECF, 'V'),
- (0x1ED0, 'M', 'ố'),
- (0x1ED1, 'V'),
- (0x1ED2, 'M', 'ồ'),
- (0x1ED3, 'V'),
- (0x1ED4, 'M', 'ổ'),
- (0x1ED5, 'V'),
- (0x1ED6, 'M', 'ỗ'),
- (0x1ED7, 'V'),
- (0x1ED8, 'M', 'ộ'),
- (0x1ED9, 'V'),
- (0x1EDA, 'M', 'ớ'),
- (0x1EDB, 'V'),
- (0x1EDC, 'M', 'ờ'),
- (0x1EDD, 'V'),
- (0x1EDE, 'M', 'ở'),
- (0x1EDF, 'V'),
- (0x1EE0, 'M', 'ỡ'),
- (0x1EE1, 'V'),
- (0x1EE2, 'M', 'ợ'),
- (0x1EE3, 'V'),
- (0x1EE4, 'M', 'ụ'),
- (0x1EE5, 'V'),
- (0x1EE6, 'M', 'ủ'),
- (0x1EE7, 'V'),
- (0x1EE8, 'M', 'ứ'),
- (0x1EE9, 'V'),
- (0x1EEA, 'M', 'ừ'),
- (0x1EEB, 'V'),
- (0x1EEC, 'M', 'ử'),
- (0x1EED, 'V'),
- (0x1EEE, 'M', 'ữ'),
- (0x1EEF, 'V'),
- (0x1EF0, 'M', 'ự'),
- ]
-
-def _seg_19() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1EF1, 'V'),
- (0x1EF2, 'M', 'ỳ'),
- (0x1EF3, 'V'),
- (0x1EF4, 'M', 'ỵ'),
- (0x1EF5, 'V'),
- (0x1EF6, 'M', 'ỷ'),
- (0x1EF7, 'V'),
- (0x1EF8, 'M', 'ỹ'),
- (0x1EF9, 'V'),
- (0x1EFA, 'M', 'ỻ'),
- (0x1EFB, 'V'),
- (0x1EFC, 'M', 'ỽ'),
- (0x1EFD, 'V'),
- (0x1EFE, 'M', 'ỿ'),
- (0x1EFF, 'V'),
- (0x1F08, 'M', 'ἀ'),
- (0x1F09, 'M', 'ἁ'),
- (0x1F0A, 'M', 'ἂ'),
- (0x1F0B, 'M', 'ἃ'),
- (0x1F0C, 'M', 'ἄ'),
- (0x1F0D, 'M', 'ἅ'),
- (0x1F0E, 'M', 'ἆ'),
- (0x1F0F, 'M', 'ἇ'),
- (0x1F10, 'V'),
- (0x1F16, 'X'),
- (0x1F18, 'M', 'ἐ'),
- (0x1F19, 'M', 'ἑ'),
- (0x1F1A, 'M', 'ἒ'),
- (0x1F1B, 'M', 'ἓ'),
- (0x1F1C, 'M', 'ἔ'),
- (0x1F1D, 'M', 'ἕ'),
- (0x1F1E, 'X'),
- (0x1F20, 'V'),
- (0x1F28, 'M', 'ἠ'),
- (0x1F29, 'M', 'ἡ'),
- (0x1F2A, 'M', 'ἢ'),
- (0x1F2B, 'M', 'ἣ'),
- (0x1F2C, 'M', 'ἤ'),
- (0x1F2D, 'M', 'ἥ'),
- (0x1F2E, 'M', 'ἦ'),
- (0x1F2F, 'M', 'ἧ'),
- (0x1F30, 'V'),
- (0x1F38, 'M', 'ἰ'),
- (0x1F39, 'M', 'ἱ'),
- (0x1F3A, 'M', 'ἲ'),
- (0x1F3B, 'M', 'ἳ'),
- (0x1F3C, 'M', 'ἴ'),
- (0x1F3D, 'M', 'ἵ'),
- (0x1F3E, 'M', 'ἶ'),
- (0x1F3F, 'M', 'ἷ'),
- (0x1F40, 'V'),
- (0x1F46, 'X'),
- (0x1F48, 'M', 'ὀ'),
- (0x1F49, 'M', 'ὁ'),
- (0x1F4A, 'M', 'ὂ'),
- (0x1F4B, 'M', 'ὃ'),
- (0x1F4C, 'M', 'ὄ'),
- (0x1F4D, 'M', 'ὅ'),
- (0x1F4E, 'X'),
- (0x1F50, 'V'),
- (0x1F58, 'X'),
- (0x1F59, 'M', 'ὑ'),
- (0x1F5A, 'X'),
- (0x1F5B, 'M', 'ὓ'),
- (0x1F5C, 'X'),
- (0x1F5D, 'M', 'ὕ'),
- (0x1F5E, 'X'),
- (0x1F5F, 'M', 'ὗ'),
- (0x1F60, 'V'),
- (0x1F68, 'M', 'ὠ'),
- (0x1F69, 'M', 'ὡ'),
- (0x1F6A, 'M', 'ὢ'),
- (0x1F6B, 'M', 'ὣ'),
- (0x1F6C, 'M', 'ὤ'),
- (0x1F6D, 'M', 'ὥ'),
- (0x1F6E, 'M', 'ὦ'),
- (0x1F6F, 'M', 'ὧ'),
- (0x1F70, 'V'),
- (0x1F71, 'M', 'ά'),
- (0x1F72, 'V'),
- (0x1F73, 'M', 'έ'),
- (0x1F74, 'V'),
- (0x1F75, 'M', 'ή'),
- (0x1F76, 'V'),
- (0x1F77, 'M', 'ί'),
- (0x1F78, 'V'),
- (0x1F79, 'M', 'ό'),
- (0x1F7A, 'V'),
- (0x1F7B, 'M', 'ύ'),
- (0x1F7C, 'V'),
- (0x1F7D, 'M', 'ώ'),
- (0x1F7E, 'X'),
- (0x1F80, 'M', 'ἀι'),
- (0x1F81, 'M', 'ἁι'),
- (0x1F82, 'M', 'ἂι'),
- (0x1F83, 'M', 'ἃι'),
- (0x1F84, 'M', 'ἄι'),
- (0x1F85, 'M', 'ἅι'),
- (0x1F86, 'M', 'ἆι'),
- (0x1F87, 'M', 'ἇι'),
- ]
-
-def _seg_20() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1F88, 'M', 'ἀι'),
- (0x1F89, 'M', 'ἁι'),
- (0x1F8A, 'M', 'ἂι'),
- (0x1F8B, 'M', 'ἃι'),
- (0x1F8C, 'M', 'ἄι'),
- (0x1F8D, 'M', 'ἅι'),
- (0x1F8E, 'M', 'ἆι'),
- (0x1F8F, 'M', 'ἇι'),
- (0x1F90, 'M', 'ἠι'),
- (0x1F91, 'M', 'ἡι'),
- (0x1F92, 'M', 'ἢι'),
- (0x1F93, 'M', 'ἣι'),
- (0x1F94, 'M', 'ἤι'),
- (0x1F95, 'M', 'ἥι'),
- (0x1F96, 'M', 'ἦι'),
- (0x1F97, 'M', 'ἧι'),
- (0x1F98, 'M', 'ἠι'),
- (0x1F99, 'M', 'ἡι'),
- (0x1F9A, 'M', 'ἢι'),
- (0x1F9B, 'M', 'ἣι'),
- (0x1F9C, 'M', 'ἤι'),
- (0x1F9D, 'M', 'ἥι'),
- (0x1F9E, 'M', 'ἦι'),
- (0x1F9F, 'M', 'ἧι'),
- (0x1FA0, 'M', 'ὠι'),
- (0x1FA1, 'M', 'ὡι'),
- (0x1FA2, 'M', 'ὢι'),
- (0x1FA3, 'M', 'ὣι'),
- (0x1FA4, 'M', 'ὤι'),
- (0x1FA5, 'M', 'ὥι'),
- (0x1FA6, 'M', 'ὦι'),
- (0x1FA7, 'M', 'ὧι'),
- (0x1FA8, 'M', 'ὠι'),
- (0x1FA9, 'M', 'ὡι'),
- (0x1FAA, 'M', 'ὢι'),
- (0x1FAB, 'M', 'ὣι'),
- (0x1FAC, 'M', 'ὤι'),
- (0x1FAD, 'M', 'ὥι'),
- (0x1FAE, 'M', 'ὦι'),
- (0x1FAF, 'M', 'ὧι'),
- (0x1FB0, 'V'),
- (0x1FB2, 'M', 'ὰι'),
- (0x1FB3, 'M', 'αι'),
- (0x1FB4, 'M', 'άι'),
- (0x1FB5, 'X'),
- (0x1FB6, 'V'),
- (0x1FB7, 'M', 'ᾶι'),
- (0x1FB8, 'M', 'ᾰ'),
- (0x1FB9, 'M', 'ᾱ'),
- (0x1FBA, 'M', 'ὰ'),
- (0x1FBB, 'M', 'ά'),
- (0x1FBC, 'M', 'αι'),
- (0x1FBD, '3', ' ̓'),
- (0x1FBE, 'M', 'ι'),
- (0x1FBF, '3', ' ̓'),
- (0x1FC0, '3', ' ͂'),
- (0x1FC1, '3', ' ̈͂'),
- (0x1FC2, 'M', 'ὴι'),
- (0x1FC3, 'M', 'ηι'),
- (0x1FC4, 'M', 'ήι'),
- (0x1FC5, 'X'),
- (0x1FC6, 'V'),
- (0x1FC7, 'M', 'ῆι'),
- (0x1FC8, 'M', 'ὲ'),
- (0x1FC9, 'M', 'έ'),
- (0x1FCA, 'M', 'ὴ'),
- (0x1FCB, 'M', 'ή'),
- (0x1FCC, 'M', 'ηι'),
- (0x1FCD, '3', ' ̓̀'),
- (0x1FCE, '3', ' ̓́'),
- (0x1FCF, '3', ' ̓͂'),
- (0x1FD0, 'V'),
- (0x1FD3, 'M', 'ΐ'),
- (0x1FD4, 'X'),
- (0x1FD6, 'V'),
- (0x1FD8, 'M', 'ῐ'),
- (0x1FD9, 'M', 'ῑ'),
- (0x1FDA, 'M', 'ὶ'),
- (0x1FDB, 'M', 'ί'),
- (0x1FDC, 'X'),
- (0x1FDD, '3', ' ̔̀'),
- (0x1FDE, '3', ' ̔́'),
- (0x1FDF, '3', ' ̔͂'),
- (0x1FE0, 'V'),
- (0x1FE3, 'M', 'ΰ'),
- (0x1FE4, 'V'),
- (0x1FE8, 'M', 'ῠ'),
- (0x1FE9, 'M', 'ῡ'),
- (0x1FEA, 'M', 'ὺ'),
- (0x1FEB, 'M', 'ύ'),
- (0x1FEC, 'M', 'ῥ'),
- (0x1FED, '3', ' ̈̀'),
- (0x1FEE, '3', ' ̈́'),
- (0x1FEF, '3', '`'),
- (0x1FF0, 'X'),
- (0x1FF2, 'M', 'ὼι'),
- (0x1FF3, 'M', 'ωι'),
- (0x1FF4, 'M', 'ώι'),
- (0x1FF5, 'X'),
- (0x1FF6, 'V'),
- ]
-
-def _seg_21() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1FF7, 'M', 'ῶι'),
- (0x1FF8, 'M', 'ὸ'),
- (0x1FF9, 'M', 'ό'),
- (0x1FFA, 'M', 'ὼ'),
- (0x1FFB, 'M', 'ώ'),
- (0x1FFC, 'M', 'ωι'),
- (0x1FFD, '3', ' ́'),
- (0x1FFE, '3', ' ̔'),
- (0x1FFF, 'X'),
- (0x2000, '3', ' '),
- (0x200B, 'I'),
- (0x200C, 'D', ''),
- (0x200E, 'X'),
- (0x2010, 'V'),
- (0x2011, 'M', '‐'),
- (0x2012, 'V'),
- (0x2017, '3', ' ̳'),
- (0x2018, 'V'),
- (0x2024, 'X'),
- (0x2027, 'V'),
- (0x2028, 'X'),
- (0x202F, '3', ' '),
- (0x2030, 'V'),
- (0x2033, 'M', '′′'),
- (0x2034, 'M', '′′′'),
- (0x2035, 'V'),
- (0x2036, 'M', '‵‵'),
- (0x2037, 'M', '‵‵‵'),
- (0x2038, 'V'),
- (0x203C, '3', '!!'),
- (0x203D, 'V'),
- (0x203E, '3', ' ̅'),
- (0x203F, 'V'),
- (0x2047, '3', '??'),
- (0x2048, '3', '?!'),
- (0x2049, '3', '!?'),
- (0x204A, 'V'),
- (0x2057, 'M', '′′′′'),
- (0x2058, 'V'),
- (0x205F, '3', ' '),
- (0x2060, 'I'),
- (0x2061, 'X'),
- (0x2064, 'I'),
- (0x2065, 'X'),
- (0x2070, 'M', '0'),
- (0x2071, 'M', 'i'),
- (0x2072, 'X'),
- (0x2074, 'M', '4'),
- (0x2075, 'M', '5'),
- (0x2076, 'M', '6'),
- (0x2077, 'M', '7'),
- (0x2078, 'M', '8'),
- (0x2079, 'M', '9'),
- (0x207A, '3', '+'),
- (0x207B, 'M', '−'),
- (0x207C, '3', '='),
- (0x207D, '3', '('),
- (0x207E, '3', ')'),
- (0x207F, 'M', 'n'),
- (0x2080, 'M', '0'),
- (0x2081, 'M', '1'),
- (0x2082, 'M', '2'),
- (0x2083, 'M', '3'),
- (0x2084, 'M', '4'),
- (0x2085, 'M', '5'),
- (0x2086, 'M', '6'),
- (0x2087, 'M', '7'),
- (0x2088, 'M', '8'),
- (0x2089, 'M', '9'),
- (0x208A, '3', '+'),
- (0x208B, 'M', '−'),
- (0x208C, '3', '='),
- (0x208D, '3', '('),
- (0x208E, '3', ')'),
- (0x208F, 'X'),
- (0x2090, 'M', 'a'),
- (0x2091, 'M', 'e'),
- (0x2092, 'M', 'o'),
- (0x2093, 'M', 'x'),
- (0x2094, 'M', 'ə'),
- (0x2095, 'M', 'h'),
- (0x2096, 'M', 'k'),
- (0x2097, 'M', 'l'),
- (0x2098, 'M', 'm'),
- (0x2099, 'M', 'n'),
- (0x209A, 'M', 'p'),
- (0x209B, 'M', 's'),
- (0x209C, 'M', 't'),
- (0x209D, 'X'),
- (0x20A0, 'V'),
- (0x20A8, 'M', 'rs'),
- (0x20A9, 'V'),
- (0x20C1, 'X'),
- (0x20D0, 'V'),
- (0x20F1, 'X'),
- (0x2100, '3', 'a/c'),
- (0x2101, '3', 'a/s'),
- (0x2102, 'M', 'c'),
- (0x2103, 'M', '°c'),
- (0x2104, 'V'),
- ]
-
-def _seg_22() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2105, '3', 'c/o'),
- (0x2106, '3', 'c/u'),
- (0x2107, 'M', 'ɛ'),
- (0x2108, 'V'),
- (0x2109, 'M', '°f'),
- (0x210A, 'M', 'g'),
- (0x210B, 'M', 'h'),
- (0x210F, 'M', 'ħ'),
- (0x2110, 'M', 'i'),
- (0x2112, 'M', 'l'),
- (0x2114, 'V'),
- (0x2115, 'M', 'n'),
- (0x2116, 'M', 'no'),
- (0x2117, 'V'),
- (0x2119, 'M', 'p'),
- (0x211A, 'M', 'q'),
- (0x211B, 'M', 'r'),
- (0x211E, 'V'),
- (0x2120, 'M', 'sm'),
- (0x2121, 'M', 'tel'),
- (0x2122, 'M', 'tm'),
- (0x2123, 'V'),
- (0x2124, 'M', 'z'),
- (0x2125, 'V'),
- (0x2126, 'M', 'ω'),
- (0x2127, 'V'),
- (0x2128, 'M', 'z'),
- (0x2129, 'V'),
- (0x212A, 'M', 'k'),
- (0x212B, 'M', 'å'),
- (0x212C, 'M', 'b'),
- (0x212D, 'M', 'c'),
- (0x212E, 'V'),
- (0x212F, 'M', 'e'),
- (0x2131, 'M', 'f'),
- (0x2132, 'X'),
- (0x2133, 'M', 'm'),
- (0x2134, 'M', 'o'),
- (0x2135, 'M', 'א'),
- (0x2136, 'M', 'ב'),
- (0x2137, 'M', 'ג'),
- (0x2138, 'M', 'ד'),
- (0x2139, 'M', 'i'),
- (0x213A, 'V'),
- (0x213B, 'M', 'fax'),
- (0x213C, 'M', 'π'),
- (0x213D, 'M', 'γ'),
- (0x213F, 'M', 'π'),
- (0x2140, 'M', '∑'),
- (0x2141, 'V'),
- (0x2145, 'M', 'd'),
- (0x2147, 'M', 'e'),
- (0x2148, 'M', 'i'),
- (0x2149, 'M', 'j'),
- (0x214A, 'V'),
- (0x2150, 'M', '1⁄7'),
- (0x2151, 'M', '1⁄9'),
- (0x2152, 'M', '1⁄10'),
- (0x2153, 'M', '1⁄3'),
- (0x2154, 'M', '2⁄3'),
- (0x2155, 'M', '1⁄5'),
- (0x2156, 'M', '2⁄5'),
- (0x2157, 'M', '3⁄5'),
- (0x2158, 'M', '4⁄5'),
- (0x2159, 'M', '1⁄6'),
- (0x215A, 'M', '5⁄6'),
- (0x215B, 'M', '1⁄8'),
- (0x215C, 'M', '3⁄8'),
- (0x215D, 'M', '5⁄8'),
- (0x215E, 'M', '7⁄8'),
- (0x215F, 'M', '1⁄'),
- (0x2160, 'M', 'i'),
- (0x2161, 'M', 'ii'),
- (0x2162, 'M', 'iii'),
- (0x2163, 'M', 'iv'),
- (0x2164, 'M', 'v'),
- (0x2165, 'M', 'vi'),
- (0x2166, 'M', 'vii'),
- (0x2167, 'M', 'viii'),
- (0x2168, 'M', 'ix'),
- (0x2169, 'M', 'x'),
- (0x216A, 'M', 'xi'),
- (0x216B, 'M', 'xii'),
- (0x216C, 'M', 'l'),
- (0x216D, 'M', 'c'),
- (0x216E, 'M', 'd'),
- (0x216F, 'M', 'm'),
- (0x2170, 'M', 'i'),
- (0x2171, 'M', 'ii'),
- (0x2172, 'M', 'iii'),
- (0x2173, 'M', 'iv'),
- (0x2174, 'M', 'v'),
- (0x2175, 'M', 'vi'),
- (0x2176, 'M', 'vii'),
- (0x2177, 'M', 'viii'),
- (0x2178, 'M', 'ix'),
- (0x2179, 'M', 'x'),
- (0x217A, 'M', 'xi'),
- (0x217B, 'M', 'xii'),
- (0x217C, 'M', 'l'),
- ]
-
-def _seg_23() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x217D, 'M', 'c'),
- (0x217E, 'M', 'd'),
- (0x217F, 'M', 'm'),
- (0x2180, 'V'),
- (0x2183, 'X'),
- (0x2184, 'V'),
- (0x2189, 'M', '0⁄3'),
- (0x218A, 'V'),
- (0x218C, 'X'),
- (0x2190, 'V'),
- (0x222C, 'M', '∫∫'),
- (0x222D, 'M', '∫∫∫'),
- (0x222E, 'V'),
- (0x222F, 'M', '∮∮'),
- (0x2230, 'M', '∮∮∮'),
- (0x2231, 'V'),
- (0x2329, 'M', '〈'),
- (0x232A, 'M', '〉'),
- (0x232B, 'V'),
- (0x2427, 'X'),
- (0x2440, 'V'),
- (0x244B, 'X'),
- (0x2460, 'M', '1'),
- (0x2461, 'M', '2'),
- (0x2462, 'M', '3'),
- (0x2463, 'M', '4'),
- (0x2464, 'M', '5'),
- (0x2465, 'M', '6'),
- (0x2466, 'M', '7'),
- (0x2467, 'M', '8'),
- (0x2468, 'M', '9'),
- (0x2469, 'M', '10'),
- (0x246A, 'M', '11'),
- (0x246B, 'M', '12'),
- (0x246C, 'M', '13'),
- (0x246D, 'M', '14'),
- (0x246E, 'M', '15'),
- (0x246F, 'M', '16'),
- (0x2470, 'M', '17'),
- (0x2471, 'M', '18'),
- (0x2472, 'M', '19'),
- (0x2473, 'M', '20'),
- (0x2474, '3', '(1)'),
- (0x2475, '3', '(2)'),
- (0x2476, '3', '(3)'),
- (0x2477, '3', '(4)'),
- (0x2478, '3', '(5)'),
- (0x2479, '3', '(6)'),
- (0x247A, '3', '(7)'),
- (0x247B, '3', '(8)'),
- (0x247C, '3', '(9)'),
- (0x247D, '3', '(10)'),
- (0x247E, '3', '(11)'),
- (0x247F, '3', '(12)'),
- (0x2480, '3', '(13)'),
- (0x2481, '3', '(14)'),
- (0x2482, '3', '(15)'),
- (0x2483, '3', '(16)'),
- (0x2484, '3', '(17)'),
- (0x2485, '3', '(18)'),
- (0x2486, '3', '(19)'),
- (0x2487, '3', '(20)'),
- (0x2488, 'X'),
- (0x249C, '3', '(a)'),
- (0x249D, '3', '(b)'),
- (0x249E, '3', '(c)'),
- (0x249F, '3', '(d)'),
- (0x24A0, '3', '(e)'),
- (0x24A1, '3', '(f)'),
- (0x24A2, '3', '(g)'),
- (0x24A3, '3', '(h)'),
- (0x24A4, '3', '(i)'),
- (0x24A5, '3', '(j)'),
- (0x24A6, '3', '(k)'),
- (0x24A7, '3', '(l)'),
- (0x24A8, '3', '(m)'),
- (0x24A9, '3', '(n)'),
- (0x24AA, '3', '(o)'),
- (0x24AB, '3', '(p)'),
- (0x24AC, '3', '(q)'),
- (0x24AD, '3', '(r)'),
- (0x24AE, '3', '(s)'),
- (0x24AF, '3', '(t)'),
- (0x24B0, '3', '(u)'),
- (0x24B1, '3', '(v)'),
- (0x24B2, '3', '(w)'),
- (0x24B3, '3', '(x)'),
- (0x24B4, '3', '(y)'),
- (0x24B5, '3', '(z)'),
- (0x24B6, 'M', 'a'),
- (0x24B7, 'M', 'b'),
- (0x24B8, 'M', 'c'),
- (0x24B9, 'M', 'd'),
- (0x24BA, 'M', 'e'),
- (0x24BB, 'M', 'f'),
- (0x24BC, 'M', 'g'),
- (0x24BD, 'M', 'h'),
- (0x24BE, 'M', 'i'),
- (0x24BF, 'M', 'j'),
- (0x24C0, 'M', 'k'),
- ]
-
-def _seg_24() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x24C1, 'M', 'l'),
- (0x24C2, 'M', 'm'),
- (0x24C3, 'M', 'n'),
- (0x24C4, 'M', 'o'),
- (0x24C5, 'M', 'p'),
- (0x24C6, 'M', 'q'),
- (0x24C7, 'M', 'r'),
- (0x24C8, 'M', 's'),
- (0x24C9, 'M', 't'),
- (0x24CA, 'M', 'u'),
- (0x24CB, 'M', 'v'),
- (0x24CC, 'M', 'w'),
- (0x24CD, 'M', 'x'),
- (0x24CE, 'M', 'y'),
- (0x24CF, 'M', 'z'),
- (0x24D0, 'M', 'a'),
- (0x24D1, 'M', 'b'),
- (0x24D2, 'M', 'c'),
- (0x24D3, 'M', 'd'),
- (0x24D4, 'M', 'e'),
- (0x24D5, 'M', 'f'),
- (0x24D6, 'M', 'g'),
- (0x24D7, 'M', 'h'),
- (0x24D8, 'M', 'i'),
- (0x24D9, 'M', 'j'),
- (0x24DA, 'M', 'k'),
- (0x24DB, 'M', 'l'),
- (0x24DC, 'M', 'm'),
- (0x24DD, 'M', 'n'),
- (0x24DE, 'M', 'o'),
- (0x24DF, 'M', 'p'),
- (0x24E0, 'M', 'q'),
- (0x24E1, 'M', 'r'),
- (0x24E2, 'M', 's'),
- (0x24E3, 'M', 't'),
- (0x24E4, 'M', 'u'),
- (0x24E5, 'M', 'v'),
- (0x24E6, 'M', 'w'),
- (0x24E7, 'M', 'x'),
- (0x24E8, 'M', 'y'),
- (0x24E9, 'M', 'z'),
- (0x24EA, 'M', '0'),
- (0x24EB, 'V'),
- (0x2A0C, 'M', '∫∫∫∫'),
- (0x2A0D, 'V'),
- (0x2A74, '3', '::='),
- (0x2A75, '3', '=='),
- (0x2A76, '3', '==='),
- (0x2A77, 'V'),
- (0x2ADC, 'M', '⫝̸'),
- (0x2ADD, 'V'),
- (0x2B74, 'X'),
- (0x2B76, 'V'),
- (0x2B96, 'X'),
- (0x2B97, 'V'),
- (0x2C00, 'M', 'ⰰ'),
- (0x2C01, 'M', 'ⰱ'),
- (0x2C02, 'M', 'ⰲ'),
- (0x2C03, 'M', 'ⰳ'),
- (0x2C04, 'M', 'ⰴ'),
- (0x2C05, 'M', 'ⰵ'),
- (0x2C06, 'M', 'ⰶ'),
- (0x2C07, 'M', 'ⰷ'),
- (0x2C08, 'M', 'ⰸ'),
- (0x2C09, 'M', 'ⰹ'),
- (0x2C0A, 'M', 'ⰺ'),
- (0x2C0B, 'M', 'ⰻ'),
- (0x2C0C, 'M', 'ⰼ'),
- (0x2C0D, 'M', 'ⰽ'),
- (0x2C0E, 'M', 'ⰾ'),
- (0x2C0F, 'M', 'ⰿ'),
- (0x2C10, 'M', 'ⱀ'),
- (0x2C11, 'M', 'ⱁ'),
- (0x2C12, 'M', 'ⱂ'),
- (0x2C13, 'M', 'ⱃ'),
- (0x2C14, 'M', 'ⱄ'),
- (0x2C15, 'M', 'ⱅ'),
- (0x2C16, 'M', 'ⱆ'),
- (0x2C17, 'M', 'ⱇ'),
- (0x2C18, 'M', 'ⱈ'),
- (0x2C19, 'M', 'ⱉ'),
- (0x2C1A, 'M', 'ⱊ'),
- (0x2C1B, 'M', 'ⱋ'),
- (0x2C1C, 'M', 'ⱌ'),
- (0x2C1D, 'M', 'ⱍ'),
- (0x2C1E, 'M', 'ⱎ'),
- (0x2C1F, 'M', 'ⱏ'),
- (0x2C20, 'M', 'ⱐ'),
- (0x2C21, 'M', 'ⱑ'),
- (0x2C22, 'M', 'ⱒ'),
- (0x2C23, 'M', 'ⱓ'),
- (0x2C24, 'M', 'ⱔ'),
- (0x2C25, 'M', 'ⱕ'),
- (0x2C26, 'M', 'ⱖ'),
- (0x2C27, 'M', 'ⱗ'),
- (0x2C28, 'M', 'ⱘ'),
- (0x2C29, 'M', 'ⱙ'),
- (0x2C2A, 'M', 'ⱚ'),
- (0x2C2B, 'M', 'ⱛ'),
- (0x2C2C, 'M', 'ⱜ'),
- ]
-
-def _seg_25() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2C2D, 'M', 'ⱝ'),
- (0x2C2E, 'M', 'ⱞ'),
- (0x2C2F, 'M', 'ⱟ'),
- (0x2C30, 'V'),
- (0x2C60, 'M', 'ⱡ'),
- (0x2C61, 'V'),
- (0x2C62, 'M', 'ɫ'),
- (0x2C63, 'M', 'ᵽ'),
- (0x2C64, 'M', 'ɽ'),
- (0x2C65, 'V'),
- (0x2C67, 'M', 'ⱨ'),
- (0x2C68, 'V'),
- (0x2C69, 'M', 'ⱪ'),
- (0x2C6A, 'V'),
- (0x2C6B, 'M', 'ⱬ'),
- (0x2C6C, 'V'),
- (0x2C6D, 'M', 'ɑ'),
- (0x2C6E, 'M', 'ɱ'),
- (0x2C6F, 'M', 'ɐ'),
- (0x2C70, 'M', 'ɒ'),
- (0x2C71, 'V'),
- (0x2C72, 'M', 'ⱳ'),
- (0x2C73, 'V'),
- (0x2C75, 'M', 'ⱶ'),
- (0x2C76, 'V'),
- (0x2C7C, 'M', 'j'),
- (0x2C7D, 'M', 'v'),
- (0x2C7E, 'M', 'ȿ'),
- (0x2C7F, 'M', 'ɀ'),
- (0x2C80, 'M', 'ⲁ'),
- (0x2C81, 'V'),
- (0x2C82, 'M', 'ⲃ'),
- (0x2C83, 'V'),
- (0x2C84, 'M', 'ⲅ'),
- (0x2C85, 'V'),
- (0x2C86, 'M', 'ⲇ'),
- (0x2C87, 'V'),
- (0x2C88, 'M', 'ⲉ'),
- (0x2C89, 'V'),
- (0x2C8A, 'M', 'ⲋ'),
- (0x2C8B, 'V'),
- (0x2C8C, 'M', 'ⲍ'),
- (0x2C8D, 'V'),
- (0x2C8E, 'M', 'ⲏ'),
- (0x2C8F, 'V'),
- (0x2C90, 'M', 'ⲑ'),
- (0x2C91, 'V'),
- (0x2C92, 'M', 'ⲓ'),
- (0x2C93, 'V'),
- (0x2C94, 'M', 'ⲕ'),
- (0x2C95, 'V'),
- (0x2C96, 'M', 'ⲗ'),
- (0x2C97, 'V'),
- (0x2C98, 'M', 'ⲙ'),
- (0x2C99, 'V'),
- (0x2C9A, 'M', 'ⲛ'),
- (0x2C9B, 'V'),
- (0x2C9C, 'M', 'ⲝ'),
- (0x2C9D, 'V'),
- (0x2C9E, 'M', 'ⲟ'),
- (0x2C9F, 'V'),
- (0x2CA0, 'M', 'ⲡ'),
- (0x2CA1, 'V'),
- (0x2CA2, 'M', 'ⲣ'),
- (0x2CA3, 'V'),
- (0x2CA4, 'M', 'ⲥ'),
- (0x2CA5, 'V'),
- (0x2CA6, 'M', 'ⲧ'),
- (0x2CA7, 'V'),
- (0x2CA8, 'M', 'ⲩ'),
- (0x2CA9, 'V'),
- (0x2CAA, 'M', 'ⲫ'),
- (0x2CAB, 'V'),
- (0x2CAC, 'M', 'ⲭ'),
- (0x2CAD, 'V'),
- (0x2CAE, 'M', 'ⲯ'),
- (0x2CAF, 'V'),
- (0x2CB0, 'M', 'ⲱ'),
- (0x2CB1, 'V'),
- (0x2CB2, 'M', 'ⲳ'),
- (0x2CB3, 'V'),
- (0x2CB4, 'M', 'ⲵ'),
- (0x2CB5, 'V'),
- (0x2CB6, 'M', 'ⲷ'),
- (0x2CB7, 'V'),
- (0x2CB8, 'M', 'ⲹ'),
- (0x2CB9, 'V'),
- (0x2CBA, 'M', 'ⲻ'),
- (0x2CBB, 'V'),
- (0x2CBC, 'M', 'ⲽ'),
- (0x2CBD, 'V'),
- (0x2CBE, 'M', 'ⲿ'),
- (0x2CBF, 'V'),
- (0x2CC0, 'M', 'ⳁ'),
- (0x2CC1, 'V'),
- (0x2CC2, 'M', 'ⳃ'),
- (0x2CC3, 'V'),
- (0x2CC4, 'M', 'ⳅ'),
- (0x2CC5, 'V'),
- (0x2CC6, 'M', 'ⳇ'),
- ]
-
-def _seg_26() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2CC7, 'V'),
- (0x2CC8, 'M', 'ⳉ'),
- (0x2CC9, 'V'),
- (0x2CCA, 'M', 'ⳋ'),
- (0x2CCB, 'V'),
- (0x2CCC, 'M', 'ⳍ'),
- (0x2CCD, 'V'),
- (0x2CCE, 'M', 'ⳏ'),
- (0x2CCF, 'V'),
- (0x2CD0, 'M', 'ⳑ'),
- (0x2CD1, 'V'),
- (0x2CD2, 'M', 'ⳓ'),
- (0x2CD3, 'V'),
- (0x2CD4, 'M', 'ⳕ'),
- (0x2CD5, 'V'),
- (0x2CD6, 'M', 'ⳗ'),
- (0x2CD7, 'V'),
- (0x2CD8, 'M', 'ⳙ'),
- (0x2CD9, 'V'),
- (0x2CDA, 'M', 'ⳛ'),
- (0x2CDB, 'V'),
- (0x2CDC, 'M', 'ⳝ'),
- (0x2CDD, 'V'),
- (0x2CDE, 'M', 'ⳟ'),
- (0x2CDF, 'V'),
- (0x2CE0, 'M', 'ⳡ'),
- (0x2CE1, 'V'),
- (0x2CE2, 'M', 'ⳣ'),
- (0x2CE3, 'V'),
- (0x2CEB, 'M', 'ⳬ'),
- (0x2CEC, 'V'),
- (0x2CED, 'M', 'ⳮ'),
- (0x2CEE, 'V'),
- (0x2CF2, 'M', 'ⳳ'),
- (0x2CF3, 'V'),
- (0x2CF4, 'X'),
- (0x2CF9, 'V'),
- (0x2D26, 'X'),
- (0x2D27, 'V'),
- (0x2D28, 'X'),
- (0x2D2D, 'V'),
- (0x2D2E, 'X'),
- (0x2D30, 'V'),
- (0x2D68, 'X'),
- (0x2D6F, 'M', 'ⵡ'),
- (0x2D70, 'V'),
- (0x2D71, 'X'),
- (0x2D7F, 'V'),
- (0x2D97, 'X'),
- (0x2DA0, 'V'),
- (0x2DA7, 'X'),
- (0x2DA8, 'V'),
- (0x2DAF, 'X'),
- (0x2DB0, 'V'),
- (0x2DB7, 'X'),
- (0x2DB8, 'V'),
- (0x2DBF, 'X'),
- (0x2DC0, 'V'),
- (0x2DC7, 'X'),
- (0x2DC8, 'V'),
- (0x2DCF, 'X'),
- (0x2DD0, 'V'),
- (0x2DD7, 'X'),
- (0x2DD8, 'V'),
- (0x2DDF, 'X'),
- (0x2DE0, 'V'),
- (0x2E5E, 'X'),
- (0x2E80, 'V'),
- (0x2E9A, 'X'),
- (0x2E9B, 'V'),
- (0x2E9F, 'M', '母'),
- (0x2EA0, 'V'),
- (0x2EF3, 'M', '龟'),
- (0x2EF4, 'X'),
- (0x2F00, 'M', '一'),
- (0x2F01, 'M', '丨'),
- (0x2F02, 'M', '丶'),
- (0x2F03, 'M', '丿'),
- (0x2F04, 'M', '乙'),
- (0x2F05, 'M', '亅'),
- (0x2F06, 'M', '二'),
- (0x2F07, 'M', '亠'),
- (0x2F08, 'M', '人'),
- (0x2F09, 'M', '儿'),
- (0x2F0A, 'M', '入'),
- (0x2F0B, 'M', '八'),
- (0x2F0C, 'M', '冂'),
- (0x2F0D, 'M', '冖'),
- (0x2F0E, 'M', '冫'),
- (0x2F0F, 'M', '几'),
- (0x2F10, 'M', '凵'),
- (0x2F11, 'M', '刀'),
- (0x2F12, 'M', '力'),
- (0x2F13, 'M', '勹'),
- (0x2F14, 'M', '匕'),
- (0x2F15, 'M', '匚'),
- (0x2F16, 'M', '匸'),
- (0x2F17, 'M', '十'),
- (0x2F18, 'M', '卜'),
- (0x2F19, 'M', '卩'),
- ]
-
-def _seg_27() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F1A, 'M', '厂'),
- (0x2F1B, 'M', '厶'),
- (0x2F1C, 'M', '又'),
- (0x2F1D, 'M', '口'),
- (0x2F1E, 'M', '囗'),
- (0x2F1F, 'M', '土'),
- (0x2F20, 'M', '士'),
- (0x2F21, 'M', '夂'),
- (0x2F22, 'M', '夊'),
- (0x2F23, 'M', '夕'),
- (0x2F24, 'M', '大'),
- (0x2F25, 'M', '女'),
- (0x2F26, 'M', '子'),
- (0x2F27, 'M', '宀'),
- (0x2F28, 'M', '寸'),
- (0x2F29, 'M', '小'),
- (0x2F2A, 'M', '尢'),
- (0x2F2B, 'M', '尸'),
- (0x2F2C, 'M', '屮'),
- (0x2F2D, 'M', '山'),
- (0x2F2E, 'M', '巛'),
- (0x2F2F, 'M', '工'),
- (0x2F30, 'M', '己'),
- (0x2F31, 'M', '巾'),
- (0x2F32, 'M', '干'),
- (0x2F33, 'M', '幺'),
- (0x2F34, 'M', '广'),
- (0x2F35, 'M', '廴'),
- (0x2F36, 'M', '廾'),
- (0x2F37, 'M', '弋'),
- (0x2F38, 'M', '弓'),
- (0x2F39, 'M', '彐'),
- (0x2F3A, 'M', '彡'),
- (0x2F3B, 'M', '彳'),
- (0x2F3C, 'M', '心'),
- (0x2F3D, 'M', '戈'),
- (0x2F3E, 'M', '戶'),
- (0x2F3F, 'M', '手'),
- (0x2F40, 'M', '支'),
- (0x2F41, 'M', '攴'),
- (0x2F42, 'M', '文'),
- (0x2F43, 'M', '斗'),
- (0x2F44, 'M', '斤'),
- (0x2F45, 'M', '方'),
- (0x2F46, 'M', '无'),
- (0x2F47, 'M', '日'),
- (0x2F48, 'M', '曰'),
- (0x2F49, 'M', '月'),
- (0x2F4A, 'M', '木'),
- (0x2F4B, 'M', '欠'),
- (0x2F4C, 'M', '止'),
- (0x2F4D, 'M', '歹'),
- (0x2F4E, 'M', '殳'),
- (0x2F4F, 'M', '毋'),
- (0x2F50, 'M', '比'),
- (0x2F51, 'M', '毛'),
- (0x2F52, 'M', '氏'),
- (0x2F53, 'M', '气'),
- (0x2F54, 'M', '水'),
- (0x2F55, 'M', '火'),
- (0x2F56, 'M', '爪'),
- (0x2F57, 'M', '父'),
- (0x2F58, 'M', '爻'),
- (0x2F59, 'M', '爿'),
- (0x2F5A, 'M', '片'),
- (0x2F5B, 'M', '牙'),
- (0x2F5C, 'M', '牛'),
- (0x2F5D, 'M', '犬'),
- (0x2F5E, 'M', '玄'),
- (0x2F5F, 'M', '玉'),
- (0x2F60, 'M', '瓜'),
- (0x2F61, 'M', '瓦'),
- (0x2F62, 'M', '甘'),
- (0x2F63, 'M', '生'),
- (0x2F64, 'M', '用'),
- (0x2F65, 'M', '田'),
- (0x2F66, 'M', '疋'),
- (0x2F67, 'M', '疒'),
- (0x2F68, 'M', '癶'),
- (0x2F69, 'M', '白'),
- (0x2F6A, 'M', '皮'),
- (0x2F6B, 'M', '皿'),
- (0x2F6C, 'M', '目'),
- (0x2F6D, 'M', '矛'),
- (0x2F6E, 'M', '矢'),
- (0x2F6F, 'M', '石'),
- (0x2F70, 'M', '示'),
- (0x2F71, 'M', '禸'),
- (0x2F72, 'M', '禾'),
- (0x2F73, 'M', '穴'),
- (0x2F74, 'M', '立'),
- (0x2F75, 'M', '竹'),
- (0x2F76, 'M', '米'),
- (0x2F77, 'M', '糸'),
- (0x2F78, 'M', '缶'),
- (0x2F79, 'M', '网'),
- (0x2F7A, 'M', '羊'),
- (0x2F7B, 'M', '羽'),
- (0x2F7C, 'M', '老'),
- (0x2F7D, 'M', '而'),
- ]
-
-def _seg_28() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F7E, 'M', '耒'),
- (0x2F7F, 'M', '耳'),
- (0x2F80, 'M', '聿'),
- (0x2F81, 'M', '肉'),
- (0x2F82, 'M', '臣'),
- (0x2F83, 'M', '自'),
- (0x2F84, 'M', '至'),
- (0x2F85, 'M', '臼'),
- (0x2F86, 'M', '舌'),
- (0x2F87, 'M', '舛'),
- (0x2F88, 'M', '舟'),
- (0x2F89, 'M', '艮'),
- (0x2F8A, 'M', '色'),
- (0x2F8B, 'M', '艸'),
- (0x2F8C, 'M', '虍'),
- (0x2F8D, 'M', '虫'),
- (0x2F8E, 'M', '血'),
- (0x2F8F, 'M', '行'),
- (0x2F90, 'M', '衣'),
- (0x2F91, 'M', '襾'),
- (0x2F92, 'M', '見'),
- (0x2F93, 'M', '角'),
- (0x2F94, 'M', '言'),
- (0x2F95, 'M', '谷'),
- (0x2F96, 'M', '豆'),
- (0x2F97, 'M', '豕'),
- (0x2F98, 'M', '豸'),
- (0x2F99, 'M', '貝'),
- (0x2F9A, 'M', '赤'),
- (0x2F9B, 'M', '走'),
- (0x2F9C, 'M', '足'),
- (0x2F9D, 'M', '身'),
- (0x2F9E, 'M', '車'),
- (0x2F9F, 'M', '辛'),
- (0x2FA0, 'M', '辰'),
- (0x2FA1, 'M', '辵'),
- (0x2FA2, 'M', '邑'),
- (0x2FA3, 'M', '酉'),
- (0x2FA4, 'M', '釆'),
- (0x2FA5, 'M', '里'),
- (0x2FA6, 'M', '金'),
- (0x2FA7, 'M', '長'),
- (0x2FA8, 'M', '門'),
- (0x2FA9, 'M', '阜'),
- (0x2FAA, 'M', '隶'),
- (0x2FAB, 'M', '隹'),
- (0x2FAC, 'M', '雨'),
- (0x2FAD, 'M', '靑'),
- (0x2FAE, 'M', '非'),
- (0x2FAF, 'M', '面'),
- (0x2FB0, 'M', '革'),
- (0x2FB1, 'M', '韋'),
- (0x2FB2, 'M', '韭'),
- (0x2FB3, 'M', '音'),
- (0x2FB4, 'M', '頁'),
- (0x2FB5, 'M', '風'),
- (0x2FB6, 'M', '飛'),
- (0x2FB7, 'M', '食'),
- (0x2FB8, 'M', '首'),
- (0x2FB9, 'M', '香'),
- (0x2FBA, 'M', '馬'),
- (0x2FBB, 'M', '骨'),
- (0x2FBC, 'M', '高'),
- (0x2FBD, 'M', '髟'),
- (0x2FBE, 'M', '鬥'),
- (0x2FBF, 'M', '鬯'),
- (0x2FC0, 'M', '鬲'),
- (0x2FC1, 'M', '鬼'),
- (0x2FC2, 'M', '魚'),
- (0x2FC3, 'M', '鳥'),
- (0x2FC4, 'M', '鹵'),
- (0x2FC5, 'M', '鹿'),
- (0x2FC6, 'M', '麥'),
- (0x2FC7, 'M', '麻'),
- (0x2FC8, 'M', '黃'),
- (0x2FC9, 'M', '黍'),
- (0x2FCA, 'M', '黑'),
- (0x2FCB, 'M', '黹'),
- (0x2FCC, 'M', '黽'),
- (0x2FCD, 'M', '鼎'),
- (0x2FCE, 'M', '鼓'),
- (0x2FCF, 'M', '鼠'),
- (0x2FD0, 'M', '鼻'),
- (0x2FD1, 'M', '齊'),
- (0x2FD2, 'M', '齒'),
- (0x2FD3, 'M', '龍'),
- (0x2FD4, 'M', '龜'),
- (0x2FD5, 'M', '龠'),
- (0x2FD6, 'X'),
- (0x3000, '3', ' '),
- (0x3001, 'V'),
- (0x3002, 'M', '.'),
- (0x3003, 'V'),
- (0x3036, 'M', '〒'),
- (0x3037, 'V'),
- (0x3038, 'M', '十'),
- (0x3039, 'M', '卄'),
- (0x303A, 'M', '卅'),
- (0x303B, 'V'),
- (0x3040, 'X'),
- ]
-
-def _seg_29() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x3041, 'V'),
- (0x3097, 'X'),
- (0x3099, 'V'),
- (0x309B, '3', ' ゙'),
- (0x309C, '3', ' ゚'),
- (0x309D, 'V'),
- (0x309F, 'M', 'より'),
- (0x30A0, 'V'),
- (0x30FF, 'M', 'コト'),
- (0x3100, 'X'),
- (0x3105, 'V'),
- (0x3130, 'X'),
- (0x3131, 'M', 'ᄀ'),
- (0x3132, 'M', 'ᄁ'),
- (0x3133, 'M', 'ᆪ'),
- (0x3134, 'M', 'ᄂ'),
- (0x3135, 'M', 'ᆬ'),
- (0x3136, 'M', 'ᆭ'),
- (0x3137, 'M', 'ᄃ'),
- (0x3138, 'M', 'ᄄ'),
- (0x3139, 'M', 'ᄅ'),
- (0x313A, 'M', 'ᆰ'),
- (0x313B, 'M', 'ᆱ'),
- (0x313C, 'M', 'ᆲ'),
- (0x313D, 'M', 'ᆳ'),
- (0x313E, 'M', 'ᆴ'),
- (0x313F, 'M', 'ᆵ'),
- (0x3140, 'M', 'ᄚ'),
- (0x3141, 'M', 'ᄆ'),
- (0x3142, 'M', 'ᄇ'),
- (0x3143, 'M', 'ᄈ'),
- (0x3144, 'M', 'ᄡ'),
- (0x3145, 'M', 'ᄉ'),
- (0x3146, 'M', 'ᄊ'),
- (0x3147, 'M', 'ᄋ'),
- (0x3148, 'M', 'ᄌ'),
- (0x3149, 'M', 'ᄍ'),
- (0x314A, 'M', 'ᄎ'),
- (0x314B, 'M', 'ᄏ'),
- (0x314C, 'M', 'ᄐ'),
- (0x314D, 'M', 'ᄑ'),
- (0x314E, 'M', 'ᄒ'),
- (0x314F, 'M', 'ᅡ'),
- (0x3150, 'M', 'ᅢ'),
- (0x3151, 'M', 'ᅣ'),
- (0x3152, 'M', 'ᅤ'),
- (0x3153, 'M', 'ᅥ'),
- (0x3154, 'M', 'ᅦ'),
- (0x3155, 'M', 'ᅧ'),
- (0x3156, 'M', 'ᅨ'),
- (0x3157, 'M', 'ᅩ'),
- (0x3158, 'M', 'ᅪ'),
- (0x3159, 'M', 'ᅫ'),
- (0x315A, 'M', 'ᅬ'),
- (0x315B, 'M', 'ᅭ'),
- (0x315C, 'M', 'ᅮ'),
- (0x315D, 'M', 'ᅯ'),
- (0x315E, 'M', 'ᅰ'),
- (0x315F, 'M', 'ᅱ'),
- (0x3160, 'M', 'ᅲ'),
- (0x3161, 'M', 'ᅳ'),
- (0x3162, 'M', 'ᅴ'),
- (0x3163, 'M', 'ᅵ'),
- (0x3164, 'X'),
- (0x3165, 'M', 'ᄔ'),
- (0x3166, 'M', 'ᄕ'),
- (0x3167, 'M', 'ᇇ'),
- (0x3168, 'M', 'ᇈ'),
- (0x3169, 'M', 'ᇌ'),
- (0x316A, 'M', 'ᇎ'),
- (0x316B, 'M', 'ᇓ'),
- (0x316C, 'M', 'ᇗ'),
- (0x316D, 'M', 'ᇙ'),
- (0x316E, 'M', 'ᄜ'),
- (0x316F, 'M', 'ᇝ'),
- (0x3170, 'M', 'ᇟ'),
- (0x3171, 'M', 'ᄝ'),
- (0x3172, 'M', 'ᄞ'),
- (0x3173, 'M', 'ᄠ'),
- (0x3174, 'M', 'ᄢ'),
- (0x3175, 'M', 'ᄣ'),
- (0x3176, 'M', 'ᄧ'),
- (0x3177, 'M', 'ᄩ'),
- (0x3178, 'M', 'ᄫ'),
- (0x3179, 'M', 'ᄬ'),
- (0x317A, 'M', 'ᄭ'),
- (0x317B, 'M', 'ᄮ'),
- (0x317C, 'M', 'ᄯ'),
- (0x317D, 'M', 'ᄲ'),
- (0x317E, 'M', 'ᄶ'),
- (0x317F, 'M', 'ᅀ'),
- (0x3180, 'M', 'ᅇ'),
- (0x3181, 'M', 'ᅌ'),
- (0x3182, 'M', 'ᇱ'),
- (0x3183, 'M', 'ᇲ'),
- (0x3184, 'M', 'ᅗ'),
- (0x3185, 'M', 'ᅘ'),
- (0x3186, 'M', 'ᅙ'),
- (0x3187, 'M', 'ᆄ'),
- (0x3188, 'M', 'ᆅ'),
- ]
-
-def _seg_30() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x3189, 'M', 'ᆈ'),
- (0x318A, 'M', 'ᆑ'),
- (0x318B, 'M', 'ᆒ'),
- (0x318C, 'M', 'ᆔ'),
- (0x318D, 'M', 'ᆞ'),
- (0x318E, 'M', 'ᆡ'),
- (0x318F, 'X'),
- (0x3190, 'V'),
- (0x3192, 'M', '一'),
- (0x3193, 'M', '二'),
- (0x3194, 'M', '三'),
- (0x3195, 'M', '四'),
- (0x3196, 'M', '上'),
- (0x3197, 'M', '中'),
- (0x3198, 'M', '下'),
- (0x3199, 'M', '甲'),
- (0x319A, 'M', '乙'),
- (0x319B, 'M', '丙'),
- (0x319C, 'M', '丁'),
- (0x319D, 'M', '天'),
- (0x319E, 'M', '地'),
- (0x319F, 'M', '人'),
- (0x31A0, 'V'),
- (0x31E4, 'X'),
- (0x31F0, 'V'),
- (0x3200, '3', '(ᄀ)'),
- (0x3201, '3', '(ᄂ)'),
- (0x3202, '3', '(ᄃ)'),
- (0x3203, '3', '(ᄅ)'),
- (0x3204, '3', '(ᄆ)'),
- (0x3205, '3', '(ᄇ)'),
- (0x3206, '3', '(ᄉ)'),
- (0x3207, '3', '(ᄋ)'),
- (0x3208, '3', '(ᄌ)'),
- (0x3209, '3', '(ᄎ)'),
- (0x320A, '3', '(ᄏ)'),
- (0x320B, '3', '(ᄐ)'),
- (0x320C, '3', '(ᄑ)'),
- (0x320D, '3', '(ᄒ)'),
- (0x320E, '3', '(가)'),
- (0x320F, '3', '(나)'),
- (0x3210, '3', '(다)'),
- (0x3211, '3', '(라)'),
- (0x3212, '3', '(마)'),
- (0x3213, '3', '(바)'),
- (0x3214, '3', '(사)'),
- (0x3215, '3', '(아)'),
- (0x3216, '3', '(자)'),
- (0x3217, '3', '(차)'),
- (0x3218, '3', '(카)'),
- (0x3219, '3', '(타)'),
- (0x321A, '3', '(파)'),
- (0x321B, '3', '(하)'),
- (0x321C, '3', '(주)'),
- (0x321D, '3', '(오전)'),
- (0x321E, '3', '(오후)'),
- (0x321F, 'X'),
- (0x3220, '3', '(一)'),
- (0x3221, '3', '(二)'),
- (0x3222, '3', '(三)'),
- (0x3223, '3', '(四)'),
- (0x3224, '3', '(五)'),
- (0x3225, '3', '(六)'),
- (0x3226, '3', '(七)'),
- (0x3227, '3', '(八)'),
- (0x3228, '3', '(九)'),
- (0x3229, '3', '(十)'),
- (0x322A, '3', '(月)'),
- (0x322B, '3', '(火)'),
- (0x322C, '3', '(水)'),
- (0x322D, '3', '(木)'),
- (0x322E, '3', '(金)'),
- (0x322F, '3', '(土)'),
- (0x3230, '3', '(日)'),
- (0x3231, '3', '(株)'),
- (0x3232, '3', '(有)'),
- (0x3233, '3', '(社)'),
- (0x3234, '3', '(名)'),
- (0x3235, '3', '(特)'),
- (0x3236, '3', '(財)'),
- (0x3237, '3', '(祝)'),
- (0x3238, '3', '(労)'),
- (0x3239, '3', '(代)'),
- (0x323A, '3', '(呼)'),
- (0x323B, '3', '(学)'),
- (0x323C, '3', '(監)'),
- (0x323D, '3', '(企)'),
- (0x323E, '3', '(資)'),
- (0x323F, '3', '(協)'),
- (0x3240, '3', '(祭)'),
- (0x3241, '3', '(休)'),
- (0x3242, '3', '(自)'),
- (0x3243, '3', '(至)'),
- (0x3244, 'M', '問'),
- (0x3245, 'M', '幼'),
- (0x3246, 'M', '文'),
- (0x3247, 'M', '箏'),
- (0x3248, 'V'),
- (0x3250, 'M', 'pte'),
- (0x3251, 'M', '21'),
- ]
-
-def _seg_31() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x3252, 'M', '22'),
- (0x3253, 'M', '23'),
- (0x3254, 'M', '24'),
- (0x3255, 'M', '25'),
- (0x3256, 'M', '26'),
- (0x3257, 'M', '27'),
- (0x3258, 'M', '28'),
- (0x3259, 'M', '29'),
- (0x325A, 'M', '30'),
- (0x325B, 'M', '31'),
- (0x325C, 'M', '32'),
- (0x325D, 'M', '33'),
- (0x325E, 'M', '34'),
- (0x325F, 'M', '35'),
- (0x3260, 'M', 'ᄀ'),
- (0x3261, 'M', 'ᄂ'),
- (0x3262, 'M', 'ᄃ'),
- (0x3263, 'M', 'ᄅ'),
- (0x3264, 'M', 'ᄆ'),
- (0x3265, 'M', 'ᄇ'),
- (0x3266, 'M', 'ᄉ'),
- (0x3267, 'M', 'ᄋ'),
- (0x3268, 'M', 'ᄌ'),
- (0x3269, 'M', 'ᄎ'),
- (0x326A, 'M', 'ᄏ'),
- (0x326B, 'M', 'ᄐ'),
- (0x326C, 'M', 'ᄑ'),
- (0x326D, 'M', 'ᄒ'),
- (0x326E, 'M', '가'),
- (0x326F, 'M', '나'),
- (0x3270, 'M', '다'),
- (0x3271, 'M', '라'),
- (0x3272, 'M', '마'),
- (0x3273, 'M', '바'),
- (0x3274, 'M', '사'),
- (0x3275, 'M', '아'),
- (0x3276, 'M', '자'),
- (0x3277, 'M', '차'),
- (0x3278, 'M', '카'),
- (0x3279, 'M', '타'),
- (0x327A, 'M', '파'),
- (0x327B, 'M', '하'),
- (0x327C, 'M', '참고'),
- (0x327D, 'M', '주의'),
- (0x327E, 'M', '우'),
- (0x327F, 'V'),
- (0x3280, 'M', '一'),
- (0x3281, 'M', '二'),
- (0x3282, 'M', '三'),
- (0x3283, 'M', '四'),
- (0x3284, 'M', '五'),
- (0x3285, 'M', '六'),
- (0x3286, 'M', '七'),
- (0x3287, 'M', '八'),
- (0x3288, 'M', '九'),
- (0x3289, 'M', '十'),
- (0x328A, 'M', '月'),
- (0x328B, 'M', '火'),
- (0x328C, 'M', '水'),
- (0x328D, 'M', '木'),
- (0x328E, 'M', '金'),
- (0x328F, 'M', '土'),
- (0x3290, 'M', '日'),
- (0x3291, 'M', '株'),
- (0x3292, 'M', '有'),
- (0x3293, 'M', '社'),
- (0x3294, 'M', '名'),
- (0x3295, 'M', '特'),
- (0x3296, 'M', '財'),
- (0x3297, 'M', '祝'),
- (0x3298, 'M', '労'),
- (0x3299, 'M', '秘'),
- (0x329A, 'M', '男'),
- (0x329B, 'M', '女'),
- (0x329C, 'M', '適'),
- (0x329D, 'M', '優'),
- (0x329E, 'M', '印'),
- (0x329F, 'M', '注'),
- (0x32A0, 'M', '項'),
- (0x32A1, 'M', '休'),
- (0x32A2, 'M', '写'),
- (0x32A3, 'M', '正'),
- (0x32A4, 'M', '上'),
- (0x32A5, 'M', '中'),
- (0x32A6, 'M', '下'),
- (0x32A7, 'M', '左'),
- (0x32A8, 'M', '右'),
- (0x32A9, 'M', '医'),
- (0x32AA, 'M', '宗'),
- (0x32AB, 'M', '学'),
- (0x32AC, 'M', '監'),
- (0x32AD, 'M', '企'),
- (0x32AE, 'M', '資'),
- (0x32AF, 'M', '協'),
- (0x32B0, 'M', '夜'),
- (0x32B1, 'M', '36'),
- (0x32B2, 'M', '37'),
- (0x32B3, 'M', '38'),
- (0x32B4, 'M', '39'),
- (0x32B5, 'M', '40'),
- ]
-
-def _seg_32() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x32B6, 'M', '41'),
- (0x32B7, 'M', '42'),
- (0x32B8, 'M', '43'),
- (0x32B9, 'M', '44'),
- (0x32BA, 'M', '45'),
- (0x32BB, 'M', '46'),
- (0x32BC, 'M', '47'),
- (0x32BD, 'M', '48'),
- (0x32BE, 'M', '49'),
- (0x32BF, 'M', '50'),
- (0x32C0, 'M', '1月'),
- (0x32C1, 'M', '2月'),
- (0x32C2, 'M', '3月'),
- (0x32C3, 'M', '4月'),
- (0x32C4, 'M', '5月'),
- (0x32C5, 'M', '6月'),
- (0x32C6, 'M', '7月'),
- (0x32C7, 'M', '8月'),
- (0x32C8, 'M', '9月'),
- (0x32C9, 'M', '10月'),
- (0x32CA, 'M', '11月'),
- (0x32CB, 'M', '12月'),
- (0x32CC, 'M', 'hg'),
- (0x32CD, 'M', 'erg'),
- (0x32CE, 'M', 'ev'),
- (0x32CF, 'M', 'ltd'),
- (0x32D0, 'M', 'ア'),
- (0x32D1, 'M', 'イ'),
- (0x32D2, 'M', 'ウ'),
- (0x32D3, 'M', 'エ'),
- (0x32D4, 'M', 'オ'),
- (0x32D5, 'M', 'カ'),
- (0x32D6, 'M', 'キ'),
- (0x32D7, 'M', 'ク'),
- (0x32D8, 'M', 'ケ'),
- (0x32D9, 'M', 'コ'),
- (0x32DA, 'M', 'サ'),
- (0x32DB, 'M', 'シ'),
- (0x32DC, 'M', 'ス'),
- (0x32DD, 'M', 'セ'),
- (0x32DE, 'M', 'ソ'),
- (0x32DF, 'M', 'タ'),
- (0x32E0, 'M', 'チ'),
- (0x32E1, 'M', 'ツ'),
- (0x32E2, 'M', 'テ'),
- (0x32E3, 'M', 'ト'),
- (0x32E4, 'M', 'ナ'),
- (0x32E5, 'M', 'ニ'),
- (0x32E6, 'M', 'ヌ'),
- (0x32E7, 'M', 'ネ'),
- (0x32E8, 'M', 'ノ'),
- (0x32E9, 'M', 'ハ'),
- (0x32EA, 'M', 'ヒ'),
- (0x32EB, 'M', 'フ'),
- (0x32EC, 'M', 'ヘ'),
- (0x32ED, 'M', 'ホ'),
- (0x32EE, 'M', 'マ'),
- (0x32EF, 'M', 'ミ'),
- (0x32F0, 'M', 'ム'),
- (0x32F1, 'M', 'メ'),
- (0x32F2, 'M', 'モ'),
- (0x32F3, 'M', 'ヤ'),
- (0x32F4, 'M', 'ユ'),
- (0x32F5, 'M', 'ヨ'),
- (0x32F6, 'M', 'ラ'),
- (0x32F7, 'M', 'リ'),
- (0x32F8, 'M', 'ル'),
- (0x32F9, 'M', 'レ'),
- (0x32FA, 'M', 'ロ'),
- (0x32FB, 'M', 'ワ'),
- (0x32FC, 'M', 'ヰ'),
- (0x32FD, 'M', 'ヱ'),
- (0x32FE, 'M', 'ヲ'),
- (0x32FF, 'M', '令和'),
- (0x3300, 'M', 'アパート'),
- (0x3301, 'M', 'アルファ'),
- (0x3302, 'M', 'アンペア'),
- (0x3303, 'M', 'アール'),
- (0x3304, 'M', 'イニング'),
- (0x3305, 'M', 'インチ'),
- (0x3306, 'M', 'ウォン'),
- (0x3307, 'M', 'エスクード'),
- (0x3308, 'M', 'エーカー'),
- (0x3309, 'M', 'オンス'),
- (0x330A, 'M', 'オーム'),
- (0x330B, 'M', 'カイリ'),
- (0x330C, 'M', 'カラット'),
- (0x330D, 'M', 'カロリー'),
- (0x330E, 'M', 'ガロン'),
- (0x330F, 'M', 'ガンマ'),
- (0x3310, 'M', 'ギガ'),
- (0x3311, 'M', 'ギニー'),
- (0x3312, 'M', 'キュリー'),
- (0x3313, 'M', 'ギルダー'),
- (0x3314, 'M', 'キロ'),
- (0x3315, 'M', 'キログラム'),
- (0x3316, 'M', 'キロメートル'),
- (0x3317, 'M', 'キロワット'),
- (0x3318, 'M', 'グラム'),
- (0x3319, 'M', 'グラムトン'),
- ]
-
-def _seg_33() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x331A, 'M', 'クルゼイロ'),
- (0x331B, 'M', 'クローネ'),
- (0x331C, 'M', 'ケース'),
- (0x331D, 'M', 'コルナ'),
- (0x331E, 'M', 'コーポ'),
- (0x331F, 'M', 'サイクル'),
- (0x3320, 'M', 'サンチーム'),
- (0x3321, 'M', 'シリング'),
- (0x3322, 'M', 'センチ'),
- (0x3323, 'M', 'セント'),
- (0x3324, 'M', 'ダース'),
- (0x3325, 'M', 'デシ'),
- (0x3326, 'M', 'ドル'),
- (0x3327, 'M', 'トン'),
- (0x3328, 'M', 'ナノ'),
- (0x3329, 'M', 'ノット'),
- (0x332A, 'M', 'ハイツ'),
- (0x332B, 'M', 'パーセント'),
- (0x332C, 'M', 'パーツ'),
- (0x332D, 'M', 'バーレル'),
- (0x332E, 'M', 'ピアストル'),
- (0x332F, 'M', 'ピクル'),
- (0x3330, 'M', 'ピコ'),
- (0x3331, 'M', 'ビル'),
- (0x3332, 'M', 'ファラッド'),
- (0x3333, 'M', 'フィート'),
- (0x3334, 'M', 'ブッシェル'),
- (0x3335, 'M', 'フラン'),
- (0x3336, 'M', 'ヘクタール'),
- (0x3337, 'M', 'ペソ'),
- (0x3338, 'M', 'ペニヒ'),
- (0x3339, 'M', 'ヘルツ'),
- (0x333A, 'M', 'ペンス'),
- (0x333B, 'M', 'ページ'),
- (0x333C, 'M', 'ベータ'),
- (0x333D, 'M', 'ポイント'),
- (0x333E, 'M', 'ボルト'),
- (0x333F, 'M', 'ホン'),
- (0x3340, 'M', 'ポンド'),
- (0x3341, 'M', 'ホール'),
- (0x3342, 'M', 'ホーン'),
- (0x3343, 'M', 'マイクロ'),
- (0x3344, 'M', 'マイル'),
- (0x3345, 'M', 'マッハ'),
- (0x3346, 'M', 'マルク'),
- (0x3347, 'M', 'マンション'),
- (0x3348, 'M', 'ミクロン'),
- (0x3349, 'M', 'ミリ'),
- (0x334A, 'M', 'ミリバール'),
- (0x334B, 'M', 'メガ'),
- (0x334C, 'M', 'メガトン'),
- (0x334D, 'M', 'メートル'),
- (0x334E, 'M', 'ヤード'),
- (0x334F, 'M', 'ヤール'),
- (0x3350, 'M', 'ユアン'),
- (0x3351, 'M', 'リットル'),
- (0x3352, 'M', 'リラ'),
- (0x3353, 'M', 'ルピー'),
- (0x3354, 'M', 'ルーブル'),
- (0x3355, 'M', 'レム'),
- (0x3356, 'M', 'レントゲン'),
- (0x3357, 'M', 'ワット'),
- (0x3358, 'M', '0点'),
- (0x3359, 'M', '1点'),
- (0x335A, 'M', '2点'),
- (0x335B, 'M', '3点'),
- (0x335C, 'M', '4点'),
- (0x335D, 'M', '5点'),
- (0x335E, 'M', '6点'),
- (0x335F, 'M', '7点'),
- (0x3360, 'M', '8点'),
- (0x3361, 'M', '9点'),
- (0x3362, 'M', '10点'),
- (0x3363, 'M', '11点'),
- (0x3364, 'M', '12点'),
- (0x3365, 'M', '13点'),
- (0x3366, 'M', '14点'),
- (0x3367, 'M', '15点'),
- (0x3368, 'M', '16点'),
- (0x3369, 'M', '17点'),
- (0x336A, 'M', '18点'),
- (0x336B, 'M', '19点'),
- (0x336C, 'M', '20点'),
- (0x336D, 'M', '21点'),
- (0x336E, 'M', '22点'),
- (0x336F, 'M', '23点'),
- (0x3370, 'M', '24点'),
- (0x3371, 'M', 'hpa'),
- (0x3372, 'M', 'da'),
- (0x3373, 'M', 'au'),
- (0x3374, 'M', 'bar'),
- (0x3375, 'M', 'ov'),
- (0x3376, 'M', 'pc'),
- (0x3377, 'M', 'dm'),
- (0x3378, 'M', 'dm2'),
- (0x3379, 'M', 'dm3'),
- (0x337A, 'M', 'iu'),
- (0x337B, 'M', '平成'),
- (0x337C, 'M', '昭和'),
- (0x337D, 'M', '大正'),
- ]
-
-def _seg_34() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x337E, 'M', '明治'),
- (0x337F, 'M', '株式会社'),
- (0x3380, 'M', 'pa'),
- (0x3381, 'M', 'na'),
- (0x3382, 'M', 'μa'),
- (0x3383, 'M', 'ma'),
- (0x3384, 'M', 'ka'),
- (0x3385, 'M', 'kb'),
- (0x3386, 'M', 'mb'),
- (0x3387, 'M', 'gb'),
- (0x3388, 'M', 'cal'),
- (0x3389, 'M', 'kcal'),
- (0x338A, 'M', 'pf'),
- (0x338B, 'M', 'nf'),
- (0x338C, 'M', 'μf'),
- (0x338D, 'M', 'μg'),
- (0x338E, 'M', 'mg'),
- (0x338F, 'M', 'kg'),
- (0x3390, 'M', 'hz'),
- (0x3391, 'M', 'khz'),
- (0x3392, 'M', 'mhz'),
- (0x3393, 'M', 'ghz'),
- (0x3394, 'M', 'thz'),
- (0x3395, 'M', 'μl'),
- (0x3396, 'M', 'ml'),
- (0x3397, 'M', 'dl'),
- (0x3398, 'M', 'kl'),
- (0x3399, 'M', 'fm'),
- (0x339A, 'M', 'nm'),
- (0x339B, 'M', 'μm'),
- (0x339C, 'M', 'mm'),
- (0x339D, 'M', 'cm'),
- (0x339E, 'M', 'km'),
- (0x339F, 'M', 'mm2'),
- (0x33A0, 'M', 'cm2'),
- (0x33A1, 'M', 'm2'),
- (0x33A2, 'M', 'km2'),
- (0x33A3, 'M', 'mm3'),
- (0x33A4, 'M', 'cm3'),
- (0x33A5, 'M', 'm3'),
- (0x33A6, 'M', 'km3'),
- (0x33A7, 'M', 'm∕s'),
- (0x33A8, 'M', 'm∕s2'),
- (0x33A9, 'M', 'pa'),
- (0x33AA, 'M', 'kpa'),
- (0x33AB, 'M', 'mpa'),
- (0x33AC, 'M', 'gpa'),
- (0x33AD, 'M', 'rad'),
- (0x33AE, 'M', 'rad∕s'),
- (0x33AF, 'M', 'rad∕s2'),
- (0x33B0, 'M', 'ps'),
- (0x33B1, 'M', 'ns'),
- (0x33B2, 'M', 'μs'),
- (0x33B3, 'M', 'ms'),
- (0x33B4, 'M', 'pv'),
- (0x33B5, 'M', 'nv'),
- (0x33B6, 'M', 'μv'),
- (0x33B7, 'M', 'mv'),
- (0x33B8, 'M', 'kv'),
- (0x33B9, 'M', 'mv'),
- (0x33BA, 'M', 'pw'),
- (0x33BB, 'M', 'nw'),
- (0x33BC, 'M', 'μw'),
- (0x33BD, 'M', 'mw'),
- (0x33BE, 'M', 'kw'),
- (0x33BF, 'M', 'mw'),
- (0x33C0, 'M', 'kω'),
- (0x33C1, 'M', 'mω'),
- (0x33C2, 'X'),
- (0x33C3, 'M', 'bq'),
- (0x33C4, 'M', 'cc'),
- (0x33C5, 'M', 'cd'),
- (0x33C6, 'M', 'c∕kg'),
- (0x33C7, 'X'),
- (0x33C8, 'M', 'db'),
- (0x33C9, 'M', 'gy'),
- (0x33CA, 'M', 'ha'),
- (0x33CB, 'M', 'hp'),
- (0x33CC, 'M', 'in'),
- (0x33CD, 'M', 'kk'),
- (0x33CE, 'M', 'km'),
- (0x33CF, 'M', 'kt'),
- (0x33D0, 'M', 'lm'),
- (0x33D1, 'M', 'ln'),
- (0x33D2, 'M', 'log'),
- (0x33D3, 'M', 'lx'),
- (0x33D4, 'M', 'mb'),
- (0x33D5, 'M', 'mil'),
- (0x33D6, 'M', 'mol'),
- (0x33D7, 'M', 'ph'),
- (0x33D8, 'X'),
- (0x33D9, 'M', 'ppm'),
- (0x33DA, 'M', 'pr'),
- (0x33DB, 'M', 'sr'),
- (0x33DC, 'M', 'sv'),
- (0x33DD, 'M', 'wb'),
- (0x33DE, 'M', 'v∕m'),
- (0x33DF, 'M', 'a∕m'),
- (0x33E0, 'M', '1日'),
- (0x33E1, 'M', '2日'),
- ]
-
-def _seg_35() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x33E2, 'M', '3日'),
- (0x33E3, 'M', '4日'),
- (0x33E4, 'M', '5日'),
- (0x33E5, 'M', '6日'),
- (0x33E6, 'M', '7日'),
- (0x33E7, 'M', '8日'),
- (0x33E8, 'M', '9日'),
- (0x33E9, 'M', '10日'),
- (0x33EA, 'M', '11日'),
- (0x33EB, 'M', '12日'),
- (0x33EC, 'M', '13日'),
- (0x33ED, 'M', '14日'),
- (0x33EE, 'M', '15日'),
- (0x33EF, 'M', '16日'),
- (0x33F0, 'M', '17日'),
- (0x33F1, 'M', '18日'),
- (0x33F2, 'M', '19日'),
- (0x33F3, 'M', '20日'),
- (0x33F4, 'M', '21日'),
- (0x33F5, 'M', '22日'),
- (0x33F6, 'M', '23日'),
- (0x33F7, 'M', '24日'),
- (0x33F8, 'M', '25日'),
- (0x33F9, 'M', '26日'),
- (0x33FA, 'M', '27日'),
- (0x33FB, 'M', '28日'),
- (0x33FC, 'M', '29日'),
- (0x33FD, 'M', '30日'),
- (0x33FE, 'M', '31日'),
- (0x33FF, 'M', 'gal'),
- (0x3400, 'V'),
- (0xA48D, 'X'),
- (0xA490, 'V'),
- (0xA4C7, 'X'),
- (0xA4D0, 'V'),
- (0xA62C, 'X'),
- (0xA640, 'M', 'ꙁ'),
- (0xA641, 'V'),
- (0xA642, 'M', 'ꙃ'),
- (0xA643, 'V'),
- (0xA644, 'M', 'ꙅ'),
- (0xA645, 'V'),
- (0xA646, 'M', 'ꙇ'),
- (0xA647, 'V'),
- (0xA648, 'M', 'ꙉ'),
- (0xA649, 'V'),
- (0xA64A, 'M', 'ꙋ'),
- (0xA64B, 'V'),
- (0xA64C, 'M', 'ꙍ'),
- (0xA64D, 'V'),
- (0xA64E, 'M', 'ꙏ'),
- (0xA64F, 'V'),
- (0xA650, 'M', 'ꙑ'),
- (0xA651, 'V'),
- (0xA652, 'M', 'ꙓ'),
- (0xA653, 'V'),
- (0xA654, 'M', 'ꙕ'),
- (0xA655, 'V'),
- (0xA656, 'M', 'ꙗ'),
- (0xA657, 'V'),
- (0xA658, 'M', 'ꙙ'),
- (0xA659, 'V'),
- (0xA65A, 'M', 'ꙛ'),
- (0xA65B, 'V'),
- (0xA65C, 'M', 'ꙝ'),
- (0xA65D, 'V'),
- (0xA65E, 'M', 'ꙟ'),
- (0xA65F, 'V'),
- (0xA660, 'M', 'ꙡ'),
- (0xA661, 'V'),
- (0xA662, 'M', 'ꙣ'),
- (0xA663, 'V'),
- (0xA664, 'M', 'ꙥ'),
- (0xA665, 'V'),
- (0xA666, 'M', 'ꙧ'),
- (0xA667, 'V'),
- (0xA668, 'M', 'ꙩ'),
- (0xA669, 'V'),
- (0xA66A, 'M', 'ꙫ'),
- (0xA66B, 'V'),
- (0xA66C, 'M', 'ꙭ'),
- (0xA66D, 'V'),
- (0xA680, 'M', 'ꚁ'),
- (0xA681, 'V'),
- (0xA682, 'M', 'ꚃ'),
- (0xA683, 'V'),
- (0xA684, 'M', 'ꚅ'),
- (0xA685, 'V'),
- (0xA686, 'M', 'ꚇ'),
- (0xA687, 'V'),
- (0xA688, 'M', 'ꚉ'),
- (0xA689, 'V'),
- (0xA68A, 'M', 'ꚋ'),
- (0xA68B, 'V'),
- (0xA68C, 'M', 'ꚍ'),
- (0xA68D, 'V'),
- (0xA68E, 'M', 'ꚏ'),
- (0xA68F, 'V'),
- (0xA690, 'M', 'ꚑ'),
- (0xA691, 'V'),
- ]
-
-def _seg_36() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xA692, 'M', 'ꚓ'),
- (0xA693, 'V'),
- (0xA694, 'M', 'ꚕ'),
- (0xA695, 'V'),
- (0xA696, 'M', 'ꚗ'),
- (0xA697, 'V'),
- (0xA698, 'M', 'ꚙ'),
- (0xA699, 'V'),
- (0xA69A, 'M', 'ꚛ'),
- (0xA69B, 'V'),
- (0xA69C, 'M', 'ъ'),
- (0xA69D, 'M', 'ь'),
- (0xA69E, 'V'),
- (0xA6F8, 'X'),
- (0xA700, 'V'),
- (0xA722, 'M', 'ꜣ'),
- (0xA723, 'V'),
- (0xA724, 'M', 'ꜥ'),
- (0xA725, 'V'),
- (0xA726, 'M', 'ꜧ'),
- (0xA727, 'V'),
- (0xA728, 'M', 'ꜩ'),
- (0xA729, 'V'),
- (0xA72A, 'M', 'ꜫ'),
- (0xA72B, 'V'),
- (0xA72C, 'M', 'ꜭ'),
- (0xA72D, 'V'),
- (0xA72E, 'M', 'ꜯ'),
- (0xA72F, 'V'),
- (0xA732, 'M', 'ꜳ'),
- (0xA733, 'V'),
- (0xA734, 'M', 'ꜵ'),
- (0xA735, 'V'),
- (0xA736, 'M', 'ꜷ'),
- (0xA737, 'V'),
- (0xA738, 'M', 'ꜹ'),
- (0xA739, 'V'),
- (0xA73A, 'M', 'ꜻ'),
- (0xA73B, 'V'),
- (0xA73C, 'M', 'ꜽ'),
- (0xA73D, 'V'),
- (0xA73E, 'M', 'ꜿ'),
- (0xA73F, 'V'),
- (0xA740, 'M', 'ꝁ'),
- (0xA741, 'V'),
- (0xA742, 'M', 'ꝃ'),
- (0xA743, 'V'),
- (0xA744, 'M', 'ꝅ'),
- (0xA745, 'V'),
- (0xA746, 'M', 'ꝇ'),
- (0xA747, 'V'),
- (0xA748, 'M', 'ꝉ'),
- (0xA749, 'V'),
- (0xA74A, 'M', 'ꝋ'),
- (0xA74B, 'V'),
- (0xA74C, 'M', 'ꝍ'),
- (0xA74D, 'V'),
- (0xA74E, 'M', 'ꝏ'),
- (0xA74F, 'V'),
- (0xA750, 'M', 'ꝑ'),
- (0xA751, 'V'),
- (0xA752, 'M', 'ꝓ'),
- (0xA753, 'V'),
- (0xA754, 'M', 'ꝕ'),
- (0xA755, 'V'),
- (0xA756, 'M', 'ꝗ'),
- (0xA757, 'V'),
- (0xA758, 'M', 'ꝙ'),
- (0xA759, 'V'),
- (0xA75A, 'M', 'ꝛ'),
- (0xA75B, 'V'),
- (0xA75C, 'M', 'ꝝ'),
- (0xA75D, 'V'),
- (0xA75E, 'M', 'ꝟ'),
- (0xA75F, 'V'),
- (0xA760, 'M', 'ꝡ'),
- (0xA761, 'V'),
- (0xA762, 'M', 'ꝣ'),
- (0xA763, 'V'),
- (0xA764, 'M', 'ꝥ'),
- (0xA765, 'V'),
- (0xA766, 'M', 'ꝧ'),
- (0xA767, 'V'),
- (0xA768, 'M', 'ꝩ'),
- (0xA769, 'V'),
- (0xA76A, 'M', 'ꝫ'),
- (0xA76B, 'V'),
- (0xA76C, 'M', 'ꝭ'),
- (0xA76D, 'V'),
- (0xA76E, 'M', 'ꝯ'),
- (0xA76F, 'V'),
- (0xA770, 'M', 'ꝯ'),
- (0xA771, 'V'),
- (0xA779, 'M', 'ꝺ'),
- (0xA77A, 'V'),
- (0xA77B, 'M', 'ꝼ'),
- (0xA77C, 'V'),
- (0xA77D, 'M', 'ᵹ'),
- (0xA77E, 'M', 'ꝿ'),
- (0xA77F, 'V'),
- ]
-
-def _seg_37() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xA780, 'M', 'ꞁ'),
- (0xA781, 'V'),
- (0xA782, 'M', 'ꞃ'),
- (0xA783, 'V'),
- (0xA784, 'M', 'ꞅ'),
- (0xA785, 'V'),
- (0xA786, 'M', 'ꞇ'),
- (0xA787, 'V'),
- (0xA78B, 'M', 'ꞌ'),
- (0xA78C, 'V'),
- (0xA78D, 'M', 'ɥ'),
- (0xA78E, 'V'),
- (0xA790, 'M', 'ꞑ'),
- (0xA791, 'V'),
- (0xA792, 'M', 'ꞓ'),
- (0xA793, 'V'),
- (0xA796, 'M', 'ꞗ'),
- (0xA797, 'V'),
- (0xA798, 'M', 'ꞙ'),
- (0xA799, 'V'),
- (0xA79A, 'M', 'ꞛ'),
- (0xA79B, 'V'),
- (0xA79C, 'M', 'ꞝ'),
- (0xA79D, 'V'),
- (0xA79E, 'M', 'ꞟ'),
- (0xA79F, 'V'),
- (0xA7A0, 'M', 'ꞡ'),
- (0xA7A1, 'V'),
- (0xA7A2, 'M', 'ꞣ'),
- (0xA7A3, 'V'),
- (0xA7A4, 'M', 'ꞥ'),
- (0xA7A5, 'V'),
- (0xA7A6, 'M', 'ꞧ'),
- (0xA7A7, 'V'),
- (0xA7A8, 'M', 'ꞩ'),
- (0xA7A9, 'V'),
- (0xA7AA, 'M', 'ɦ'),
- (0xA7AB, 'M', 'ɜ'),
- (0xA7AC, 'M', 'ɡ'),
- (0xA7AD, 'M', 'ɬ'),
- (0xA7AE, 'M', 'ɪ'),
- (0xA7AF, 'V'),
- (0xA7B0, 'M', 'ʞ'),
- (0xA7B1, 'M', 'ʇ'),
- (0xA7B2, 'M', 'ʝ'),
- (0xA7B3, 'M', 'ꭓ'),
- (0xA7B4, 'M', 'ꞵ'),
- (0xA7B5, 'V'),
- (0xA7B6, 'M', 'ꞷ'),
- (0xA7B7, 'V'),
- (0xA7B8, 'M', 'ꞹ'),
- (0xA7B9, 'V'),
- (0xA7BA, 'M', 'ꞻ'),
- (0xA7BB, 'V'),
- (0xA7BC, 'M', 'ꞽ'),
- (0xA7BD, 'V'),
- (0xA7BE, 'M', 'ꞿ'),
- (0xA7BF, 'V'),
- (0xA7C0, 'M', 'ꟁ'),
- (0xA7C1, 'V'),
- (0xA7C2, 'M', 'ꟃ'),
- (0xA7C3, 'V'),
- (0xA7C4, 'M', 'ꞔ'),
- (0xA7C5, 'M', 'ʂ'),
- (0xA7C6, 'M', 'ᶎ'),
- (0xA7C7, 'M', 'ꟈ'),
- (0xA7C8, 'V'),
- (0xA7C9, 'M', 'ꟊ'),
- (0xA7CA, 'V'),
- (0xA7CB, 'X'),
- (0xA7D0, 'M', 'ꟑ'),
- (0xA7D1, 'V'),
- (0xA7D2, 'X'),
- (0xA7D3, 'V'),
- (0xA7D4, 'X'),
- (0xA7D5, 'V'),
- (0xA7D6, 'M', 'ꟗ'),
- (0xA7D7, 'V'),
- (0xA7D8, 'M', 'ꟙ'),
- (0xA7D9, 'V'),
- (0xA7DA, 'X'),
- (0xA7F2, 'M', 'c'),
- (0xA7F3, 'M', 'f'),
- (0xA7F4, 'M', 'q'),
- (0xA7F5, 'M', 'ꟶ'),
- (0xA7F6, 'V'),
- (0xA7F8, 'M', 'ħ'),
- (0xA7F9, 'M', 'œ'),
- (0xA7FA, 'V'),
- (0xA82D, 'X'),
- (0xA830, 'V'),
- (0xA83A, 'X'),
- (0xA840, 'V'),
- (0xA878, 'X'),
- (0xA880, 'V'),
- (0xA8C6, 'X'),
- (0xA8CE, 'V'),
- (0xA8DA, 'X'),
- (0xA8E0, 'V'),
- (0xA954, 'X'),
- ]
-
-def _seg_38() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xA95F, 'V'),
- (0xA97D, 'X'),
- (0xA980, 'V'),
- (0xA9CE, 'X'),
- (0xA9CF, 'V'),
- (0xA9DA, 'X'),
- (0xA9DE, 'V'),
- (0xA9FF, 'X'),
- (0xAA00, 'V'),
- (0xAA37, 'X'),
- (0xAA40, 'V'),
- (0xAA4E, 'X'),
- (0xAA50, 'V'),
- (0xAA5A, 'X'),
- (0xAA5C, 'V'),
- (0xAAC3, 'X'),
- (0xAADB, 'V'),
- (0xAAF7, 'X'),
- (0xAB01, 'V'),
- (0xAB07, 'X'),
- (0xAB09, 'V'),
- (0xAB0F, 'X'),
- (0xAB11, 'V'),
- (0xAB17, 'X'),
- (0xAB20, 'V'),
- (0xAB27, 'X'),
- (0xAB28, 'V'),
- (0xAB2F, 'X'),
- (0xAB30, 'V'),
- (0xAB5C, 'M', 'ꜧ'),
- (0xAB5D, 'M', 'ꬷ'),
- (0xAB5E, 'M', 'ɫ'),
- (0xAB5F, 'M', 'ꭒ'),
- (0xAB60, 'V'),
- (0xAB69, 'M', 'ʍ'),
- (0xAB6A, 'V'),
- (0xAB6C, 'X'),
- (0xAB70, 'M', 'Ꭰ'),
- (0xAB71, 'M', 'Ꭱ'),
- (0xAB72, 'M', 'Ꭲ'),
- (0xAB73, 'M', 'Ꭳ'),
- (0xAB74, 'M', 'Ꭴ'),
- (0xAB75, 'M', 'Ꭵ'),
- (0xAB76, 'M', 'Ꭶ'),
- (0xAB77, 'M', 'Ꭷ'),
- (0xAB78, 'M', 'Ꭸ'),
- (0xAB79, 'M', 'Ꭹ'),
- (0xAB7A, 'M', 'Ꭺ'),
- (0xAB7B, 'M', 'Ꭻ'),
- (0xAB7C, 'M', 'Ꭼ'),
- (0xAB7D, 'M', 'Ꭽ'),
- (0xAB7E, 'M', 'Ꭾ'),
- (0xAB7F, 'M', 'Ꭿ'),
- (0xAB80, 'M', 'Ꮀ'),
- (0xAB81, 'M', 'Ꮁ'),
- (0xAB82, 'M', 'Ꮂ'),
- (0xAB83, 'M', 'Ꮃ'),
- (0xAB84, 'M', 'Ꮄ'),
- (0xAB85, 'M', 'Ꮅ'),
- (0xAB86, 'M', 'Ꮆ'),
- (0xAB87, 'M', 'Ꮇ'),
- (0xAB88, 'M', 'Ꮈ'),
- (0xAB89, 'M', 'Ꮉ'),
- (0xAB8A, 'M', 'Ꮊ'),
- (0xAB8B, 'M', 'Ꮋ'),
- (0xAB8C, 'M', 'Ꮌ'),
- (0xAB8D, 'M', 'Ꮍ'),
- (0xAB8E, 'M', 'Ꮎ'),
- (0xAB8F, 'M', 'Ꮏ'),
- (0xAB90, 'M', 'Ꮐ'),
- (0xAB91, 'M', 'Ꮑ'),
- (0xAB92, 'M', 'Ꮒ'),
- (0xAB93, 'M', 'Ꮓ'),
- (0xAB94, 'M', 'Ꮔ'),
- (0xAB95, 'M', 'Ꮕ'),
- (0xAB96, 'M', 'Ꮖ'),
- (0xAB97, 'M', 'Ꮗ'),
- (0xAB98, 'M', 'Ꮘ'),
- (0xAB99, 'M', 'Ꮙ'),
- (0xAB9A, 'M', 'Ꮚ'),
- (0xAB9B, 'M', 'Ꮛ'),
- (0xAB9C, 'M', 'Ꮜ'),
- (0xAB9D, 'M', 'Ꮝ'),
- (0xAB9E, 'M', 'Ꮞ'),
- (0xAB9F, 'M', 'Ꮟ'),
- (0xABA0, 'M', 'Ꮠ'),
- (0xABA1, 'M', 'Ꮡ'),
- (0xABA2, 'M', 'Ꮢ'),
- (0xABA3, 'M', 'Ꮣ'),
- (0xABA4, 'M', 'Ꮤ'),
- (0xABA5, 'M', 'Ꮥ'),
- (0xABA6, 'M', 'Ꮦ'),
- (0xABA7, 'M', 'Ꮧ'),
- (0xABA8, 'M', 'Ꮨ'),
- (0xABA9, 'M', 'Ꮩ'),
- (0xABAA, 'M', 'Ꮪ'),
- (0xABAB, 'M', 'Ꮫ'),
- (0xABAC, 'M', 'Ꮬ'),
- (0xABAD, 'M', 'Ꮭ'),
- (0xABAE, 'M', 'Ꮮ'),
- ]
-
-def _seg_39() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xABAF, 'M', 'Ꮯ'),
- (0xABB0, 'M', 'Ꮰ'),
- (0xABB1, 'M', 'Ꮱ'),
- (0xABB2, 'M', 'Ꮲ'),
- (0xABB3, 'M', 'Ꮳ'),
- (0xABB4, 'M', 'Ꮴ'),
- (0xABB5, 'M', 'Ꮵ'),
- (0xABB6, 'M', 'Ꮶ'),
- (0xABB7, 'M', 'Ꮷ'),
- (0xABB8, 'M', 'Ꮸ'),
- (0xABB9, 'M', 'Ꮹ'),
- (0xABBA, 'M', 'Ꮺ'),
- (0xABBB, 'M', 'Ꮻ'),
- (0xABBC, 'M', 'Ꮼ'),
- (0xABBD, 'M', 'Ꮽ'),
- (0xABBE, 'M', 'Ꮾ'),
- (0xABBF, 'M', 'Ꮿ'),
- (0xABC0, 'V'),
- (0xABEE, 'X'),
- (0xABF0, 'V'),
- (0xABFA, 'X'),
- (0xAC00, 'V'),
- (0xD7A4, 'X'),
- (0xD7B0, 'V'),
- (0xD7C7, 'X'),
- (0xD7CB, 'V'),
- (0xD7FC, 'X'),
- (0xF900, 'M', '豈'),
- (0xF901, 'M', '更'),
- (0xF902, 'M', '車'),
- (0xF903, 'M', '賈'),
- (0xF904, 'M', '滑'),
- (0xF905, 'M', '串'),
- (0xF906, 'M', '句'),
- (0xF907, 'M', '龜'),
- (0xF909, 'M', '契'),
- (0xF90A, 'M', '金'),
- (0xF90B, 'M', '喇'),
- (0xF90C, 'M', '奈'),
- (0xF90D, 'M', '懶'),
- (0xF90E, 'M', '癩'),
- (0xF90F, 'M', '羅'),
- (0xF910, 'M', '蘿'),
- (0xF911, 'M', '螺'),
- (0xF912, 'M', '裸'),
- (0xF913, 'M', '邏'),
- (0xF914, 'M', '樂'),
- (0xF915, 'M', '洛'),
- (0xF916, 'M', '烙'),
- (0xF917, 'M', '珞'),
- (0xF918, 'M', '落'),
- (0xF919, 'M', '酪'),
- (0xF91A, 'M', '駱'),
- (0xF91B, 'M', '亂'),
- (0xF91C, 'M', '卵'),
- (0xF91D, 'M', '欄'),
- (0xF91E, 'M', '爛'),
- (0xF91F, 'M', '蘭'),
- (0xF920, 'M', '鸞'),
- (0xF921, 'M', '嵐'),
- (0xF922, 'M', '濫'),
- (0xF923, 'M', '藍'),
- (0xF924, 'M', '襤'),
- (0xF925, 'M', '拉'),
- (0xF926, 'M', '臘'),
- (0xF927, 'M', '蠟'),
- (0xF928, 'M', '廊'),
- (0xF929, 'M', '朗'),
- (0xF92A, 'M', '浪'),
- (0xF92B, 'M', '狼'),
- (0xF92C, 'M', '郎'),
- (0xF92D, 'M', '來'),
- (0xF92E, 'M', '冷'),
- (0xF92F, 'M', '勞'),
- (0xF930, 'M', '擄'),
- (0xF931, 'M', '櫓'),
- (0xF932, 'M', '爐'),
- (0xF933, 'M', '盧'),
- (0xF934, 'M', '老'),
- (0xF935, 'M', '蘆'),
- (0xF936, 'M', '虜'),
- (0xF937, 'M', '路'),
- (0xF938, 'M', '露'),
- (0xF939, 'M', '魯'),
- (0xF93A, 'M', '鷺'),
- (0xF93B, 'M', '碌'),
- (0xF93C, 'M', '祿'),
- (0xF93D, 'M', '綠'),
- (0xF93E, 'M', '菉'),
- (0xF93F, 'M', '錄'),
- (0xF940, 'M', '鹿'),
- (0xF941, 'M', '論'),
- (0xF942, 'M', '壟'),
- (0xF943, 'M', '弄'),
- (0xF944, 'M', '籠'),
- (0xF945, 'M', '聾'),
- (0xF946, 'M', '牢'),
- (0xF947, 'M', '磊'),
- (0xF948, 'M', '賂'),
- (0xF949, 'M', '雷'),
- ]
-
-def _seg_40() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xF94A, 'M', '壘'),
- (0xF94B, 'M', '屢'),
- (0xF94C, 'M', '樓'),
- (0xF94D, 'M', '淚'),
- (0xF94E, 'M', '漏'),
- (0xF94F, 'M', '累'),
- (0xF950, 'M', '縷'),
- (0xF951, 'M', '陋'),
- (0xF952, 'M', '勒'),
- (0xF953, 'M', '肋'),
- (0xF954, 'M', '凜'),
- (0xF955, 'M', '凌'),
- (0xF956, 'M', '稜'),
- (0xF957, 'M', '綾'),
- (0xF958, 'M', '菱'),
- (0xF959, 'M', '陵'),
- (0xF95A, 'M', '讀'),
- (0xF95B, 'M', '拏'),
- (0xF95C, 'M', '樂'),
- (0xF95D, 'M', '諾'),
- (0xF95E, 'M', '丹'),
- (0xF95F, 'M', '寧'),
- (0xF960, 'M', '怒'),
- (0xF961, 'M', '率'),
- (0xF962, 'M', '異'),
- (0xF963, 'M', '北'),
- (0xF964, 'M', '磻'),
- (0xF965, 'M', '便'),
- (0xF966, 'M', '復'),
- (0xF967, 'M', '不'),
- (0xF968, 'M', '泌'),
- (0xF969, 'M', '數'),
- (0xF96A, 'M', '索'),
- (0xF96B, 'M', '參'),
- (0xF96C, 'M', '塞'),
- (0xF96D, 'M', '省'),
- (0xF96E, 'M', '葉'),
- (0xF96F, 'M', '說'),
- (0xF970, 'M', '殺'),
- (0xF971, 'M', '辰'),
- (0xF972, 'M', '沈'),
- (0xF973, 'M', '拾'),
- (0xF974, 'M', '若'),
- (0xF975, 'M', '掠'),
- (0xF976, 'M', '略'),
- (0xF977, 'M', '亮'),
- (0xF978, 'M', '兩'),
- (0xF979, 'M', '凉'),
- (0xF97A, 'M', '梁'),
- (0xF97B, 'M', '糧'),
- (0xF97C, 'M', '良'),
- (0xF97D, 'M', '諒'),
- (0xF97E, 'M', '量'),
- (0xF97F, 'M', '勵'),
- (0xF980, 'M', '呂'),
- (0xF981, 'M', '女'),
- (0xF982, 'M', '廬'),
- (0xF983, 'M', '旅'),
- (0xF984, 'M', '濾'),
- (0xF985, 'M', '礪'),
- (0xF986, 'M', '閭'),
- (0xF987, 'M', '驪'),
- (0xF988, 'M', '麗'),
- (0xF989, 'M', '黎'),
- (0xF98A, 'M', '力'),
- (0xF98B, 'M', '曆'),
- (0xF98C, 'M', '歷'),
- (0xF98D, 'M', '轢'),
- (0xF98E, 'M', '年'),
- (0xF98F, 'M', '憐'),
- (0xF990, 'M', '戀'),
- (0xF991, 'M', '撚'),
- (0xF992, 'M', '漣'),
- (0xF993, 'M', '煉'),
- (0xF994, 'M', '璉'),
- (0xF995, 'M', '秊'),
- (0xF996, 'M', '練'),
- (0xF997, 'M', '聯'),
- (0xF998, 'M', '輦'),
- (0xF999, 'M', '蓮'),
- (0xF99A, 'M', '連'),
- (0xF99B, 'M', '鍊'),
- (0xF99C, 'M', '列'),
- (0xF99D, 'M', '劣'),
- (0xF99E, 'M', '咽'),
- (0xF99F, 'M', '烈'),
- (0xF9A0, 'M', '裂'),
- (0xF9A1, 'M', '說'),
- (0xF9A2, 'M', '廉'),
- (0xF9A3, 'M', '念'),
- (0xF9A4, 'M', '捻'),
- (0xF9A5, 'M', '殮'),
- (0xF9A6, 'M', '簾'),
- (0xF9A7, 'M', '獵'),
- (0xF9A8, 'M', '令'),
- (0xF9A9, 'M', '囹'),
- (0xF9AA, 'M', '寧'),
- (0xF9AB, 'M', '嶺'),
- (0xF9AC, 'M', '怜'),
- (0xF9AD, 'M', '玲'),
- ]
-
-def _seg_41() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xF9AE, 'M', '瑩'),
- (0xF9AF, 'M', '羚'),
- (0xF9B0, 'M', '聆'),
- (0xF9B1, 'M', '鈴'),
- (0xF9B2, 'M', '零'),
- (0xF9B3, 'M', '靈'),
- (0xF9B4, 'M', '領'),
- (0xF9B5, 'M', '例'),
- (0xF9B6, 'M', '禮'),
- (0xF9B7, 'M', '醴'),
- (0xF9B8, 'M', '隸'),
- (0xF9B9, 'M', '惡'),
- (0xF9BA, 'M', '了'),
- (0xF9BB, 'M', '僚'),
- (0xF9BC, 'M', '寮'),
- (0xF9BD, 'M', '尿'),
- (0xF9BE, 'M', '料'),
- (0xF9BF, 'M', '樂'),
- (0xF9C0, 'M', '燎'),
- (0xF9C1, 'M', '療'),
- (0xF9C2, 'M', '蓼'),
- (0xF9C3, 'M', '遼'),
- (0xF9C4, 'M', '龍'),
- (0xF9C5, 'M', '暈'),
- (0xF9C6, 'M', '阮'),
- (0xF9C7, 'M', '劉'),
- (0xF9C8, 'M', '杻'),
- (0xF9C9, 'M', '柳'),
- (0xF9CA, 'M', '流'),
- (0xF9CB, 'M', '溜'),
- (0xF9CC, 'M', '琉'),
- (0xF9CD, 'M', '留'),
- (0xF9CE, 'M', '硫'),
- (0xF9CF, 'M', '紐'),
- (0xF9D0, 'M', '類'),
- (0xF9D1, 'M', '六'),
- (0xF9D2, 'M', '戮'),
- (0xF9D3, 'M', '陸'),
- (0xF9D4, 'M', '倫'),
- (0xF9D5, 'M', '崙'),
- (0xF9D6, 'M', '淪'),
- (0xF9D7, 'M', '輪'),
- (0xF9D8, 'M', '律'),
- (0xF9D9, 'M', '慄'),
- (0xF9DA, 'M', '栗'),
- (0xF9DB, 'M', '率'),
- (0xF9DC, 'M', '隆'),
- (0xF9DD, 'M', '利'),
- (0xF9DE, 'M', '吏'),
- (0xF9DF, 'M', '履'),
- (0xF9E0, 'M', '易'),
- (0xF9E1, 'M', '李'),
- (0xF9E2, 'M', '梨'),
- (0xF9E3, 'M', '泥'),
- (0xF9E4, 'M', '理'),
- (0xF9E5, 'M', '痢'),
- (0xF9E6, 'M', '罹'),
- (0xF9E7, 'M', '裏'),
- (0xF9E8, 'M', '裡'),
- (0xF9E9, 'M', '里'),
- (0xF9EA, 'M', '離'),
- (0xF9EB, 'M', '匿'),
- (0xF9EC, 'M', '溺'),
- (0xF9ED, 'M', '吝'),
- (0xF9EE, 'M', '燐'),
- (0xF9EF, 'M', '璘'),
- (0xF9F0, 'M', '藺'),
- (0xF9F1, 'M', '隣'),
- (0xF9F2, 'M', '鱗'),
- (0xF9F3, 'M', '麟'),
- (0xF9F4, 'M', '林'),
- (0xF9F5, 'M', '淋'),
- (0xF9F6, 'M', '臨'),
- (0xF9F7, 'M', '立'),
- (0xF9F8, 'M', '笠'),
- (0xF9F9, 'M', '粒'),
- (0xF9FA, 'M', '狀'),
- (0xF9FB, 'M', '炙'),
- (0xF9FC, 'M', '識'),
- (0xF9FD, 'M', '什'),
- (0xF9FE, 'M', '茶'),
- (0xF9FF, 'M', '刺'),
- (0xFA00, 'M', '切'),
- (0xFA01, 'M', '度'),
- (0xFA02, 'M', '拓'),
- (0xFA03, 'M', '糖'),
- (0xFA04, 'M', '宅'),
- (0xFA05, 'M', '洞'),
- (0xFA06, 'M', '暴'),
- (0xFA07, 'M', '輻'),
- (0xFA08, 'M', '行'),
- (0xFA09, 'M', '降'),
- (0xFA0A, 'M', '見'),
- (0xFA0B, 'M', '廓'),
- (0xFA0C, 'M', '兀'),
- (0xFA0D, 'M', '嗀'),
- (0xFA0E, 'V'),
- (0xFA10, 'M', '塚'),
- (0xFA11, 'V'),
- (0xFA12, 'M', '晴'),
- ]
-
-def _seg_42() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFA13, 'V'),
- (0xFA15, 'M', '凞'),
- (0xFA16, 'M', '猪'),
- (0xFA17, 'M', '益'),
- (0xFA18, 'M', '礼'),
- (0xFA19, 'M', '神'),
- (0xFA1A, 'M', '祥'),
- (0xFA1B, 'M', '福'),
- (0xFA1C, 'M', '靖'),
- (0xFA1D, 'M', '精'),
- (0xFA1E, 'M', '羽'),
- (0xFA1F, 'V'),
- (0xFA20, 'M', '蘒'),
- (0xFA21, 'V'),
- (0xFA22, 'M', '諸'),
- (0xFA23, 'V'),
- (0xFA25, 'M', '逸'),
- (0xFA26, 'M', '都'),
- (0xFA27, 'V'),
- (0xFA2A, 'M', '飯'),
- (0xFA2B, 'M', '飼'),
- (0xFA2C, 'M', '館'),
- (0xFA2D, 'M', '鶴'),
- (0xFA2E, 'M', '郞'),
- (0xFA2F, 'M', '隷'),
- (0xFA30, 'M', '侮'),
- (0xFA31, 'M', '僧'),
- (0xFA32, 'M', '免'),
- (0xFA33, 'M', '勉'),
- (0xFA34, 'M', '勤'),
- (0xFA35, 'M', '卑'),
- (0xFA36, 'M', '喝'),
- (0xFA37, 'M', '嘆'),
- (0xFA38, 'M', '器'),
- (0xFA39, 'M', '塀'),
- (0xFA3A, 'M', '墨'),
- (0xFA3B, 'M', '層'),
- (0xFA3C, 'M', '屮'),
- (0xFA3D, 'M', '悔'),
- (0xFA3E, 'M', '慨'),
- (0xFA3F, 'M', '憎'),
- (0xFA40, 'M', '懲'),
- (0xFA41, 'M', '敏'),
- (0xFA42, 'M', '既'),
- (0xFA43, 'M', '暑'),
- (0xFA44, 'M', '梅'),
- (0xFA45, 'M', '海'),
- (0xFA46, 'M', '渚'),
- (0xFA47, 'M', '漢'),
- (0xFA48, 'M', '煮'),
- (0xFA49, 'M', '爫'),
- (0xFA4A, 'M', '琢'),
- (0xFA4B, 'M', '碑'),
- (0xFA4C, 'M', '社'),
- (0xFA4D, 'M', '祉'),
- (0xFA4E, 'M', '祈'),
- (0xFA4F, 'M', '祐'),
- (0xFA50, 'M', '祖'),
- (0xFA51, 'M', '祝'),
- (0xFA52, 'M', '禍'),
- (0xFA53, 'M', '禎'),
- (0xFA54, 'M', '穀'),
- (0xFA55, 'M', '突'),
- (0xFA56, 'M', '節'),
- (0xFA57, 'M', '練'),
- (0xFA58, 'M', '縉'),
- (0xFA59, 'M', '繁'),
- (0xFA5A, 'M', '署'),
- (0xFA5B, 'M', '者'),
- (0xFA5C, 'M', '臭'),
- (0xFA5D, 'M', '艹'),
- (0xFA5F, 'M', '著'),
- (0xFA60, 'M', '褐'),
- (0xFA61, 'M', '視'),
- (0xFA62, 'M', '謁'),
- (0xFA63, 'M', '謹'),
- (0xFA64, 'M', '賓'),
- (0xFA65, 'M', '贈'),
- (0xFA66, 'M', '辶'),
- (0xFA67, 'M', '逸'),
- (0xFA68, 'M', '難'),
- (0xFA69, 'M', '響'),
- (0xFA6A, 'M', '頻'),
- (0xFA6B, 'M', '恵'),
- (0xFA6C, 'M', '𤋮'),
- (0xFA6D, 'M', '舘'),
- (0xFA6E, 'X'),
- (0xFA70, 'M', '並'),
- (0xFA71, 'M', '况'),
- (0xFA72, 'M', '全'),
- (0xFA73, 'M', '侀'),
- (0xFA74, 'M', '充'),
- (0xFA75, 'M', '冀'),
- (0xFA76, 'M', '勇'),
- (0xFA77, 'M', '勺'),
- (0xFA78, 'M', '喝'),
- (0xFA79, 'M', '啕'),
- (0xFA7A, 'M', '喙'),
- (0xFA7B, 'M', '嗢'),
- (0xFA7C, 'M', '塚'),
- ]
-
-def _seg_43() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFA7D, 'M', '墳'),
- (0xFA7E, 'M', '奄'),
- (0xFA7F, 'M', '奔'),
- (0xFA80, 'M', '婢'),
- (0xFA81, 'M', '嬨'),
- (0xFA82, 'M', '廒'),
- (0xFA83, 'M', '廙'),
- (0xFA84, 'M', '彩'),
- (0xFA85, 'M', '徭'),
- (0xFA86, 'M', '惘'),
- (0xFA87, 'M', '慎'),
- (0xFA88, 'M', '愈'),
- (0xFA89, 'M', '憎'),
- (0xFA8A, 'M', '慠'),
- (0xFA8B, 'M', '懲'),
- (0xFA8C, 'M', '戴'),
- (0xFA8D, 'M', '揄'),
- (0xFA8E, 'M', '搜'),
- (0xFA8F, 'M', '摒'),
- (0xFA90, 'M', '敖'),
- (0xFA91, 'M', '晴'),
- (0xFA92, 'M', '朗'),
- (0xFA93, 'M', '望'),
- (0xFA94, 'M', '杖'),
- (0xFA95, 'M', '歹'),
- (0xFA96, 'M', '殺'),
- (0xFA97, 'M', '流'),
- (0xFA98, 'M', '滛'),
- (0xFA99, 'M', '滋'),
- (0xFA9A, 'M', '漢'),
- (0xFA9B, 'M', '瀞'),
- (0xFA9C, 'M', '煮'),
- (0xFA9D, 'M', '瞧'),
- (0xFA9E, 'M', '爵'),
- (0xFA9F, 'M', '犯'),
- (0xFAA0, 'M', '猪'),
- (0xFAA1, 'M', '瑱'),
- (0xFAA2, 'M', '甆'),
- (0xFAA3, 'M', '画'),
- (0xFAA4, 'M', '瘝'),
- (0xFAA5, 'M', '瘟'),
- (0xFAA6, 'M', '益'),
- (0xFAA7, 'M', '盛'),
- (0xFAA8, 'M', '直'),
- (0xFAA9, 'M', '睊'),
- (0xFAAA, 'M', '着'),
- (0xFAAB, 'M', '磌'),
- (0xFAAC, 'M', '窱'),
- (0xFAAD, 'M', '節'),
- (0xFAAE, 'M', '类'),
- (0xFAAF, 'M', '絛'),
- (0xFAB0, 'M', '練'),
- (0xFAB1, 'M', '缾'),
- (0xFAB2, 'M', '者'),
- (0xFAB3, 'M', '荒'),
- (0xFAB4, 'M', '華'),
- (0xFAB5, 'M', '蝹'),
- (0xFAB6, 'M', '襁'),
- (0xFAB7, 'M', '覆'),
- (0xFAB8, 'M', '視'),
- (0xFAB9, 'M', '調'),
- (0xFABA, 'M', '諸'),
- (0xFABB, 'M', '請'),
- (0xFABC, 'M', '謁'),
- (0xFABD, 'M', '諾'),
- (0xFABE, 'M', '諭'),
- (0xFABF, 'M', '謹'),
- (0xFAC0, 'M', '變'),
- (0xFAC1, 'M', '贈'),
- (0xFAC2, 'M', '輸'),
- (0xFAC3, 'M', '遲'),
- (0xFAC4, 'M', '醙'),
- (0xFAC5, 'M', '鉶'),
- (0xFAC6, 'M', '陼'),
- (0xFAC7, 'M', '難'),
- (0xFAC8, 'M', '靖'),
- (0xFAC9, 'M', '韛'),
- (0xFACA, 'M', '響'),
- (0xFACB, 'M', '頋'),
- (0xFACC, 'M', '頻'),
- (0xFACD, 'M', '鬒'),
- (0xFACE, 'M', '龜'),
- (0xFACF, 'M', '𢡊'),
- (0xFAD0, 'M', '𢡄'),
- (0xFAD1, 'M', '𣏕'),
- (0xFAD2, 'M', '㮝'),
- (0xFAD3, 'M', '䀘'),
- (0xFAD4, 'M', '䀹'),
- (0xFAD5, 'M', '𥉉'),
- (0xFAD6, 'M', '𥳐'),
- (0xFAD7, 'M', '𧻓'),
- (0xFAD8, 'M', '齃'),
- (0xFAD9, 'M', '龎'),
- (0xFADA, 'X'),
- (0xFB00, 'M', 'ff'),
- (0xFB01, 'M', 'fi'),
- (0xFB02, 'M', 'fl'),
- (0xFB03, 'M', 'ffi'),
- (0xFB04, 'M', 'ffl'),
- (0xFB05, 'M', 'st'),
- ]
-
-def _seg_44() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFB07, 'X'),
- (0xFB13, 'M', 'մն'),
- (0xFB14, 'M', 'մե'),
- (0xFB15, 'M', 'մի'),
- (0xFB16, 'M', 'վն'),
- (0xFB17, 'M', 'մխ'),
- (0xFB18, 'X'),
- (0xFB1D, 'M', 'יִ'),
- (0xFB1E, 'V'),
- (0xFB1F, 'M', 'ײַ'),
- (0xFB20, 'M', 'ע'),
- (0xFB21, 'M', 'א'),
- (0xFB22, 'M', 'ד'),
- (0xFB23, 'M', 'ה'),
- (0xFB24, 'M', 'כ'),
- (0xFB25, 'M', 'ל'),
- (0xFB26, 'M', 'ם'),
- (0xFB27, 'M', 'ר'),
- (0xFB28, 'M', 'ת'),
- (0xFB29, '3', '+'),
- (0xFB2A, 'M', 'שׁ'),
- (0xFB2B, 'M', 'שׂ'),
- (0xFB2C, 'M', 'שּׁ'),
- (0xFB2D, 'M', 'שּׂ'),
- (0xFB2E, 'M', 'אַ'),
- (0xFB2F, 'M', 'אָ'),
- (0xFB30, 'M', 'אּ'),
- (0xFB31, 'M', 'בּ'),
- (0xFB32, 'M', 'גּ'),
- (0xFB33, 'M', 'דּ'),
- (0xFB34, 'M', 'הּ'),
- (0xFB35, 'M', 'וּ'),
- (0xFB36, 'M', 'זּ'),
- (0xFB37, 'X'),
- (0xFB38, 'M', 'טּ'),
- (0xFB39, 'M', 'יּ'),
- (0xFB3A, 'M', 'ךּ'),
- (0xFB3B, 'M', 'כּ'),
- (0xFB3C, 'M', 'לּ'),
- (0xFB3D, 'X'),
- (0xFB3E, 'M', 'מּ'),
- (0xFB3F, 'X'),
- (0xFB40, 'M', 'נּ'),
- (0xFB41, 'M', 'סּ'),
- (0xFB42, 'X'),
- (0xFB43, 'M', 'ףּ'),
- (0xFB44, 'M', 'פּ'),
- (0xFB45, 'X'),
- (0xFB46, 'M', 'צּ'),
- (0xFB47, 'M', 'קּ'),
- (0xFB48, 'M', 'רּ'),
- (0xFB49, 'M', 'שּ'),
- (0xFB4A, 'M', 'תּ'),
- (0xFB4B, 'M', 'וֹ'),
- (0xFB4C, 'M', 'בֿ'),
- (0xFB4D, 'M', 'כֿ'),
- (0xFB4E, 'M', 'פֿ'),
- (0xFB4F, 'M', 'אל'),
- (0xFB50, 'M', 'ٱ'),
- (0xFB52, 'M', 'ٻ'),
- (0xFB56, 'M', 'پ'),
- (0xFB5A, 'M', 'ڀ'),
- (0xFB5E, 'M', 'ٺ'),
- (0xFB62, 'M', 'ٿ'),
- (0xFB66, 'M', 'ٹ'),
- (0xFB6A, 'M', 'ڤ'),
- (0xFB6E, 'M', 'ڦ'),
- (0xFB72, 'M', 'ڄ'),
- (0xFB76, 'M', 'ڃ'),
- (0xFB7A, 'M', 'چ'),
- (0xFB7E, 'M', 'ڇ'),
- (0xFB82, 'M', 'ڍ'),
- (0xFB84, 'M', 'ڌ'),
- (0xFB86, 'M', 'ڎ'),
- (0xFB88, 'M', 'ڈ'),
- (0xFB8A, 'M', 'ژ'),
- (0xFB8C, 'M', 'ڑ'),
- (0xFB8E, 'M', 'ک'),
- (0xFB92, 'M', 'گ'),
- (0xFB96, 'M', 'ڳ'),
- (0xFB9A, 'M', 'ڱ'),
- (0xFB9E, 'M', 'ں'),
- (0xFBA0, 'M', 'ڻ'),
- (0xFBA4, 'M', 'ۀ'),
- (0xFBA6, 'M', 'ہ'),
- (0xFBAA, 'M', 'ھ'),
- (0xFBAE, 'M', 'ے'),
- (0xFBB0, 'M', 'ۓ'),
- (0xFBB2, 'V'),
- (0xFBC3, 'X'),
- (0xFBD3, 'M', 'ڭ'),
- (0xFBD7, 'M', 'ۇ'),
- (0xFBD9, 'M', 'ۆ'),
- (0xFBDB, 'M', 'ۈ'),
- (0xFBDD, 'M', 'ۇٴ'),
- (0xFBDE, 'M', 'ۋ'),
- (0xFBE0, 'M', 'ۅ'),
- (0xFBE2, 'M', 'ۉ'),
- (0xFBE4, 'M', 'ې'),
- (0xFBE8, 'M', 'ى'),
- ]
-
-def _seg_45() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFBEA, 'M', 'ئا'),
- (0xFBEC, 'M', 'ئە'),
- (0xFBEE, 'M', 'ئو'),
- (0xFBF0, 'M', 'ئۇ'),
- (0xFBF2, 'M', 'ئۆ'),
- (0xFBF4, 'M', 'ئۈ'),
- (0xFBF6, 'M', 'ئې'),
- (0xFBF9, 'M', 'ئى'),
- (0xFBFC, 'M', 'ی'),
- (0xFC00, 'M', 'ئج'),
- (0xFC01, 'M', 'ئح'),
- (0xFC02, 'M', 'ئم'),
- (0xFC03, 'M', 'ئى'),
- (0xFC04, 'M', 'ئي'),
- (0xFC05, 'M', 'بج'),
- (0xFC06, 'M', 'بح'),
- (0xFC07, 'M', 'بخ'),
- (0xFC08, 'M', 'بم'),
- (0xFC09, 'M', 'بى'),
- (0xFC0A, 'M', 'بي'),
- (0xFC0B, 'M', 'تج'),
- (0xFC0C, 'M', 'تح'),
- (0xFC0D, 'M', 'تخ'),
- (0xFC0E, 'M', 'تم'),
- (0xFC0F, 'M', 'تى'),
- (0xFC10, 'M', 'تي'),
- (0xFC11, 'M', 'ثج'),
- (0xFC12, 'M', 'ثم'),
- (0xFC13, 'M', 'ثى'),
- (0xFC14, 'M', 'ثي'),
- (0xFC15, 'M', 'جح'),
- (0xFC16, 'M', 'جم'),
- (0xFC17, 'M', 'حج'),
- (0xFC18, 'M', 'حم'),
- (0xFC19, 'M', 'خج'),
- (0xFC1A, 'M', 'خح'),
- (0xFC1B, 'M', 'خم'),
- (0xFC1C, 'M', 'سج'),
- (0xFC1D, 'M', 'سح'),
- (0xFC1E, 'M', 'سخ'),
- (0xFC1F, 'M', 'سم'),
- (0xFC20, 'M', 'صح'),
- (0xFC21, 'M', 'صم'),
- (0xFC22, 'M', 'ضج'),
- (0xFC23, 'M', 'ضح'),
- (0xFC24, 'M', 'ضخ'),
- (0xFC25, 'M', 'ضم'),
- (0xFC26, 'M', 'طح'),
- (0xFC27, 'M', 'طم'),
- (0xFC28, 'M', 'ظم'),
- (0xFC29, 'M', 'عج'),
- (0xFC2A, 'M', 'عم'),
- (0xFC2B, 'M', 'غج'),
- (0xFC2C, 'M', 'غم'),
- (0xFC2D, 'M', 'فج'),
- (0xFC2E, 'M', 'فح'),
- (0xFC2F, 'M', 'فخ'),
- (0xFC30, 'M', 'فم'),
- (0xFC31, 'M', 'فى'),
- (0xFC32, 'M', 'في'),
- (0xFC33, 'M', 'قح'),
- (0xFC34, 'M', 'قم'),
- (0xFC35, 'M', 'قى'),
- (0xFC36, 'M', 'قي'),
- (0xFC37, 'M', 'كا'),
- (0xFC38, 'M', 'كج'),
- (0xFC39, 'M', 'كح'),
- (0xFC3A, 'M', 'كخ'),
- (0xFC3B, 'M', 'كل'),
- (0xFC3C, 'M', 'كم'),
- (0xFC3D, 'M', 'كى'),
- (0xFC3E, 'M', 'كي'),
- (0xFC3F, 'M', 'لج'),
- (0xFC40, 'M', 'لح'),
- (0xFC41, 'M', 'لخ'),
- (0xFC42, 'M', 'لم'),
- (0xFC43, 'M', 'لى'),
- (0xFC44, 'M', 'لي'),
- (0xFC45, 'M', 'مج'),
- (0xFC46, 'M', 'مح'),
- (0xFC47, 'M', 'مخ'),
- (0xFC48, 'M', 'مم'),
- (0xFC49, 'M', 'مى'),
- (0xFC4A, 'M', 'مي'),
- (0xFC4B, 'M', 'نج'),
- (0xFC4C, 'M', 'نح'),
- (0xFC4D, 'M', 'نخ'),
- (0xFC4E, 'M', 'نم'),
- (0xFC4F, 'M', 'نى'),
- (0xFC50, 'M', 'ني'),
- (0xFC51, 'M', 'هج'),
- (0xFC52, 'M', 'هم'),
- (0xFC53, 'M', 'هى'),
- (0xFC54, 'M', 'هي'),
- (0xFC55, 'M', 'يج'),
- (0xFC56, 'M', 'يح'),
- (0xFC57, 'M', 'يخ'),
- (0xFC58, 'M', 'يم'),
- (0xFC59, 'M', 'يى'),
- (0xFC5A, 'M', 'يي'),
- ]
-
-def _seg_46() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFC5B, 'M', 'ذٰ'),
- (0xFC5C, 'M', 'رٰ'),
- (0xFC5D, 'M', 'ىٰ'),
- (0xFC5E, '3', ' ٌّ'),
- (0xFC5F, '3', ' ٍّ'),
- (0xFC60, '3', ' َّ'),
- (0xFC61, '3', ' ُّ'),
- (0xFC62, '3', ' ِّ'),
- (0xFC63, '3', ' ّٰ'),
- (0xFC64, 'M', 'ئر'),
- (0xFC65, 'M', 'ئز'),
- (0xFC66, 'M', 'ئم'),
- (0xFC67, 'M', 'ئن'),
- (0xFC68, 'M', 'ئى'),
- (0xFC69, 'M', 'ئي'),
- (0xFC6A, 'M', 'بر'),
- (0xFC6B, 'M', 'بز'),
- (0xFC6C, 'M', 'بم'),
- (0xFC6D, 'M', 'بن'),
- (0xFC6E, 'M', 'بى'),
- (0xFC6F, 'M', 'بي'),
- (0xFC70, 'M', 'تر'),
- (0xFC71, 'M', 'تز'),
- (0xFC72, 'M', 'تم'),
- (0xFC73, 'M', 'تن'),
- (0xFC74, 'M', 'تى'),
- (0xFC75, 'M', 'تي'),
- (0xFC76, 'M', 'ثر'),
- (0xFC77, 'M', 'ثز'),
- (0xFC78, 'M', 'ثم'),
- (0xFC79, 'M', 'ثن'),
- (0xFC7A, 'M', 'ثى'),
- (0xFC7B, 'M', 'ثي'),
- (0xFC7C, 'M', 'فى'),
- (0xFC7D, 'M', 'في'),
- (0xFC7E, 'M', 'قى'),
- (0xFC7F, 'M', 'قي'),
- (0xFC80, 'M', 'كا'),
- (0xFC81, 'M', 'كل'),
- (0xFC82, 'M', 'كم'),
- (0xFC83, 'M', 'كى'),
- (0xFC84, 'M', 'كي'),
- (0xFC85, 'M', 'لم'),
- (0xFC86, 'M', 'لى'),
- (0xFC87, 'M', 'لي'),
- (0xFC88, 'M', 'ما'),
- (0xFC89, 'M', 'مم'),
- (0xFC8A, 'M', 'نر'),
- (0xFC8B, 'M', 'نز'),
- (0xFC8C, 'M', 'نم'),
- (0xFC8D, 'M', 'نن'),
- (0xFC8E, 'M', 'نى'),
- (0xFC8F, 'M', 'ني'),
- (0xFC90, 'M', 'ىٰ'),
- (0xFC91, 'M', 'ير'),
- (0xFC92, 'M', 'يز'),
- (0xFC93, 'M', 'يم'),
- (0xFC94, 'M', 'ين'),
- (0xFC95, 'M', 'يى'),
- (0xFC96, 'M', 'يي'),
- (0xFC97, 'M', 'ئج'),
- (0xFC98, 'M', 'ئح'),
- (0xFC99, 'M', 'ئخ'),
- (0xFC9A, 'M', 'ئم'),
- (0xFC9B, 'M', 'ئه'),
- (0xFC9C, 'M', 'بج'),
- (0xFC9D, 'M', 'بح'),
- (0xFC9E, 'M', 'بخ'),
- (0xFC9F, 'M', 'بم'),
- (0xFCA0, 'M', 'به'),
- (0xFCA1, 'M', 'تج'),
- (0xFCA2, 'M', 'تح'),
- (0xFCA3, 'M', 'تخ'),
- (0xFCA4, 'M', 'تم'),
- (0xFCA5, 'M', 'ته'),
- (0xFCA6, 'M', 'ثم'),
- (0xFCA7, 'M', 'جح'),
- (0xFCA8, 'M', 'جم'),
- (0xFCA9, 'M', 'حج'),
- (0xFCAA, 'M', 'حم'),
- (0xFCAB, 'M', 'خج'),
- (0xFCAC, 'M', 'خم'),
- (0xFCAD, 'M', 'سج'),
- (0xFCAE, 'M', 'سح'),
- (0xFCAF, 'M', 'سخ'),
- (0xFCB0, 'M', 'سم'),
- (0xFCB1, 'M', 'صح'),
- (0xFCB2, 'M', 'صخ'),
- (0xFCB3, 'M', 'صم'),
- (0xFCB4, 'M', 'ضج'),
- (0xFCB5, 'M', 'ضح'),
- (0xFCB6, 'M', 'ضخ'),
- (0xFCB7, 'M', 'ضم'),
- (0xFCB8, 'M', 'طح'),
- (0xFCB9, 'M', 'ظم'),
- (0xFCBA, 'M', 'عج'),
- (0xFCBB, 'M', 'عم'),
- (0xFCBC, 'M', 'غج'),
- (0xFCBD, 'M', 'غم'),
- (0xFCBE, 'M', 'فج'),
- ]
-
-def _seg_47() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFCBF, 'M', 'فح'),
- (0xFCC0, 'M', 'فخ'),
- (0xFCC1, 'M', 'فم'),
- (0xFCC2, 'M', 'قح'),
- (0xFCC3, 'M', 'قم'),
- (0xFCC4, 'M', 'كج'),
- (0xFCC5, 'M', 'كح'),
- (0xFCC6, 'M', 'كخ'),
- (0xFCC7, 'M', 'كل'),
- (0xFCC8, 'M', 'كم'),
- (0xFCC9, 'M', 'لج'),
- (0xFCCA, 'M', 'لح'),
- (0xFCCB, 'M', 'لخ'),
- (0xFCCC, 'M', 'لم'),
- (0xFCCD, 'M', 'له'),
- (0xFCCE, 'M', 'مج'),
- (0xFCCF, 'M', 'مح'),
- (0xFCD0, 'M', 'مخ'),
- (0xFCD1, 'M', 'مم'),
- (0xFCD2, 'M', 'نج'),
- (0xFCD3, 'M', 'نح'),
- (0xFCD4, 'M', 'نخ'),
- (0xFCD5, 'M', 'نم'),
- (0xFCD6, 'M', 'نه'),
- (0xFCD7, 'M', 'هج'),
- (0xFCD8, 'M', 'هم'),
- (0xFCD9, 'M', 'هٰ'),
- (0xFCDA, 'M', 'يج'),
- (0xFCDB, 'M', 'يح'),
- (0xFCDC, 'M', 'يخ'),
- (0xFCDD, 'M', 'يم'),
- (0xFCDE, 'M', 'يه'),
- (0xFCDF, 'M', 'ئم'),
- (0xFCE0, 'M', 'ئه'),
- (0xFCE1, 'M', 'بم'),
- (0xFCE2, 'M', 'به'),
- (0xFCE3, 'M', 'تم'),
- (0xFCE4, 'M', 'ته'),
- (0xFCE5, 'M', 'ثم'),
- (0xFCE6, 'M', 'ثه'),
- (0xFCE7, 'M', 'سم'),
- (0xFCE8, 'M', 'سه'),
- (0xFCE9, 'M', 'شم'),
- (0xFCEA, 'M', 'شه'),
- (0xFCEB, 'M', 'كل'),
- (0xFCEC, 'M', 'كم'),
- (0xFCED, 'M', 'لم'),
- (0xFCEE, 'M', 'نم'),
- (0xFCEF, 'M', 'نه'),
- (0xFCF0, 'M', 'يم'),
- (0xFCF1, 'M', 'يه'),
- (0xFCF2, 'M', 'ـَّ'),
- (0xFCF3, 'M', 'ـُّ'),
- (0xFCF4, 'M', 'ـِّ'),
- (0xFCF5, 'M', 'طى'),
- (0xFCF6, 'M', 'طي'),
- (0xFCF7, 'M', 'عى'),
- (0xFCF8, 'M', 'عي'),
- (0xFCF9, 'M', 'غى'),
- (0xFCFA, 'M', 'غي'),
- (0xFCFB, 'M', 'سى'),
- (0xFCFC, 'M', 'سي'),
- (0xFCFD, 'M', 'شى'),
- (0xFCFE, 'M', 'شي'),
- (0xFCFF, 'M', 'حى'),
- (0xFD00, 'M', 'حي'),
- (0xFD01, 'M', 'جى'),
- (0xFD02, 'M', 'جي'),
- (0xFD03, 'M', 'خى'),
- (0xFD04, 'M', 'خي'),
- (0xFD05, 'M', 'صى'),
- (0xFD06, 'M', 'صي'),
- (0xFD07, 'M', 'ضى'),
- (0xFD08, 'M', 'ضي'),
- (0xFD09, 'M', 'شج'),
- (0xFD0A, 'M', 'شح'),
- (0xFD0B, 'M', 'شخ'),
- (0xFD0C, 'M', 'شم'),
- (0xFD0D, 'M', 'شر'),
- (0xFD0E, 'M', 'سر'),
- (0xFD0F, 'M', 'صر'),
- (0xFD10, 'M', 'ضر'),
- (0xFD11, 'M', 'طى'),
- (0xFD12, 'M', 'طي'),
- (0xFD13, 'M', 'عى'),
- (0xFD14, 'M', 'عي'),
- (0xFD15, 'M', 'غى'),
- (0xFD16, 'M', 'غي'),
- (0xFD17, 'M', 'سى'),
- (0xFD18, 'M', 'سي'),
- (0xFD19, 'M', 'شى'),
- (0xFD1A, 'M', 'شي'),
- (0xFD1B, 'M', 'حى'),
- (0xFD1C, 'M', 'حي'),
- (0xFD1D, 'M', 'جى'),
- (0xFD1E, 'M', 'جي'),
- (0xFD1F, 'M', 'خى'),
- (0xFD20, 'M', 'خي'),
- (0xFD21, 'M', 'صى'),
- (0xFD22, 'M', 'صي'),
- ]
-
-def _seg_48() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFD23, 'M', 'ضى'),
- (0xFD24, 'M', 'ضي'),
- (0xFD25, 'M', 'شج'),
- (0xFD26, 'M', 'شح'),
- (0xFD27, 'M', 'شخ'),
- (0xFD28, 'M', 'شم'),
- (0xFD29, 'M', 'شر'),
- (0xFD2A, 'M', 'سر'),
- (0xFD2B, 'M', 'صر'),
- (0xFD2C, 'M', 'ضر'),
- (0xFD2D, 'M', 'شج'),
- (0xFD2E, 'M', 'شح'),
- (0xFD2F, 'M', 'شخ'),
- (0xFD30, 'M', 'شم'),
- (0xFD31, 'M', 'سه'),
- (0xFD32, 'M', 'شه'),
- (0xFD33, 'M', 'طم'),
- (0xFD34, 'M', 'سج'),
- (0xFD35, 'M', 'سح'),
- (0xFD36, 'M', 'سخ'),
- (0xFD37, 'M', 'شج'),
- (0xFD38, 'M', 'شح'),
- (0xFD39, 'M', 'شخ'),
- (0xFD3A, 'M', 'طم'),
- (0xFD3B, 'M', 'ظم'),
- (0xFD3C, 'M', 'اً'),
- (0xFD3E, 'V'),
- (0xFD50, 'M', 'تجم'),
- (0xFD51, 'M', 'تحج'),
- (0xFD53, 'M', 'تحم'),
- (0xFD54, 'M', 'تخم'),
- (0xFD55, 'M', 'تمج'),
- (0xFD56, 'M', 'تمح'),
- (0xFD57, 'M', 'تمخ'),
- (0xFD58, 'M', 'جمح'),
- (0xFD5A, 'M', 'حمي'),
- (0xFD5B, 'M', 'حمى'),
- (0xFD5C, 'M', 'سحج'),
- (0xFD5D, 'M', 'سجح'),
- (0xFD5E, 'M', 'سجى'),
- (0xFD5F, 'M', 'سمح'),
- (0xFD61, 'M', 'سمج'),
- (0xFD62, 'M', 'سمم'),
- (0xFD64, 'M', 'صحح'),
- (0xFD66, 'M', 'صمم'),
- (0xFD67, 'M', 'شحم'),
- (0xFD69, 'M', 'شجي'),
- (0xFD6A, 'M', 'شمخ'),
- (0xFD6C, 'M', 'شمم'),
- (0xFD6E, 'M', 'ضحى'),
- (0xFD6F, 'M', 'ضخم'),
- (0xFD71, 'M', 'طمح'),
- (0xFD73, 'M', 'طمم'),
- (0xFD74, 'M', 'طمي'),
- (0xFD75, 'M', 'عجم'),
- (0xFD76, 'M', 'عمم'),
- (0xFD78, 'M', 'عمى'),
- (0xFD79, 'M', 'غمم'),
- (0xFD7A, 'M', 'غمي'),
- (0xFD7B, 'M', 'غمى'),
- (0xFD7C, 'M', 'فخم'),
- (0xFD7E, 'M', 'قمح'),
- (0xFD7F, 'M', 'قمم'),
- (0xFD80, 'M', 'لحم'),
- (0xFD81, 'M', 'لحي'),
- (0xFD82, 'M', 'لحى'),
- (0xFD83, 'M', 'لجج'),
- (0xFD85, 'M', 'لخم'),
- (0xFD87, 'M', 'لمح'),
- (0xFD89, 'M', 'محج'),
- (0xFD8A, 'M', 'محم'),
- (0xFD8B, 'M', 'محي'),
- (0xFD8C, 'M', 'مجح'),
- (0xFD8D, 'M', 'مجم'),
- (0xFD8E, 'M', 'مخج'),
- (0xFD8F, 'M', 'مخم'),
- (0xFD90, 'X'),
- (0xFD92, 'M', 'مجخ'),
- (0xFD93, 'M', 'همج'),
- (0xFD94, 'M', 'همم'),
- (0xFD95, 'M', 'نحم'),
- (0xFD96, 'M', 'نحى'),
- (0xFD97, 'M', 'نجم'),
- (0xFD99, 'M', 'نجى'),
- (0xFD9A, 'M', 'نمي'),
- (0xFD9B, 'M', 'نمى'),
- (0xFD9C, 'M', 'يمم'),
- (0xFD9E, 'M', 'بخي'),
- (0xFD9F, 'M', 'تجي'),
- (0xFDA0, 'M', 'تجى'),
- (0xFDA1, 'M', 'تخي'),
- (0xFDA2, 'M', 'تخى'),
- (0xFDA3, 'M', 'تمي'),
- (0xFDA4, 'M', 'تمى'),
- (0xFDA5, 'M', 'جمي'),
- (0xFDA6, 'M', 'جحى'),
- (0xFDA7, 'M', 'جمى'),
- (0xFDA8, 'M', 'سخى'),
- (0xFDA9, 'M', 'صحي'),
- (0xFDAA, 'M', 'شحي'),
- ]
-
-def _seg_49() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFDAB, 'M', 'ضحي'),
- (0xFDAC, 'M', 'لجي'),
- (0xFDAD, 'M', 'لمي'),
- (0xFDAE, 'M', 'يحي'),
- (0xFDAF, 'M', 'يجي'),
- (0xFDB0, 'M', 'يمي'),
- (0xFDB1, 'M', 'ممي'),
- (0xFDB2, 'M', 'قمي'),
- (0xFDB3, 'M', 'نحي'),
- (0xFDB4, 'M', 'قمح'),
- (0xFDB5, 'M', 'لحم'),
- (0xFDB6, 'M', 'عمي'),
- (0xFDB7, 'M', 'كمي'),
- (0xFDB8, 'M', 'نجح'),
- (0xFDB9, 'M', 'مخي'),
- (0xFDBA, 'M', 'لجم'),
- (0xFDBB, 'M', 'كمم'),
- (0xFDBC, 'M', 'لجم'),
- (0xFDBD, 'M', 'نجح'),
- (0xFDBE, 'M', 'جحي'),
- (0xFDBF, 'M', 'حجي'),
- (0xFDC0, 'M', 'مجي'),
- (0xFDC1, 'M', 'فمي'),
- (0xFDC2, 'M', 'بحي'),
- (0xFDC3, 'M', 'كمم'),
- (0xFDC4, 'M', 'عجم'),
- (0xFDC5, 'M', 'صمم'),
- (0xFDC6, 'M', 'سخي'),
- (0xFDC7, 'M', 'نجي'),
- (0xFDC8, 'X'),
- (0xFDCF, 'V'),
- (0xFDD0, 'X'),
- (0xFDF0, 'M', 'صلے'),
- (0xFDF1, 'M', 'قلے'),
- (0xFDF2, 'M', 'الله'),
- (0xFDF3, 'M', 'اكبر'),
- (0xFDF4, 'M', 'محمد'),
- (0xFDF5, 'M', 'صلعم'),
- (0xFDF6, 'M', 'رسول'),
- (0xFDF7, 'M', 'عليه'),
- (0xFDF8, 'M', 'وسلم'),
- (0xFDF9, 'M', 'صلى'),
- (0xFDFA, '3', 'صلى الله عليه وسلم'),
- (0xFDFB, '3', 'جل جلاله'),
- (0xFDFC, 'M', 'ریال'),
- (0xFDFD, 'V'),
- (0xFE00, 'I'),
- (0xFE10, '3', ','),
- (0xFE11, 'M', '、'),
- (0xFE12, 'X'),
- (0xFE13, '3', ':'),
- (0xFE14, '3', ';'),
- (0xFE15, '3', '!'),
- (0xFE16, '3', '?'),
- (0xFE17, 'M', '〖'),
- (0xFE18, 'M', '〗'),
- (0xFE19, 'X'),
- (0xFE20, 'V'),
- (0xFE30, 'X'),
- (0xFE31, 'M', '—'),
- (0xFE32, 'M', '–'),
- (0xFE33, '3', '_'),
- (0xFE35, '3', '('),
- (0xFE36, '3', ')'),
- (0xFE37, '3', '{'),
- (0xFE38, '3', '}'),
- (0xFE39, 'M', '〔'),
- (0xFE3A, 'M', '〕'),
- (0xFE3B, 'M', '【'),
- (0xFE3C, 'M', '】'),
- (0xFE3D, 'M', '《'),
- (0xFE3E, 'M', '》'),
- (0xFE3F, 'M', '〈'),
- (0xFE40, 'M', '〉'),
- (0xFE41, 'M', '「'),
- (0xFE42, 'M', '」'),
- (0xFE43, 'M', '『'),
- (0xFE44, 'M', '』'),
- (0xFE45, 'V'),
- (0xFE47, '3', '['),
- (0xFE48, '3', ']'),
- (0xFE49, '3', ' ̅'),
- (0xFE4D, '3', '_'),
- (0xFE50, '3', ','),
- (0xFE51, 'M', '、'),
- (0xFE52, 'X'),
- (0xFE54, '3', ';'),
- (0xFE55, '3', ':'),
- (0xFE56, '3', '?'),
- (0xFE57, '3', '!'),
- (0xFE58, 'M', '—'),
- (0xFE59, '3', '('),
- (0xFE5A, '3', ')'),
- (0xFE5B, '3', '{'),
- (0xFE5C, '3', '}'),
- (0xFE5D, 'M', '〔'),
- (0xFE5E, 'M', '〕'),
- (0xFE5F, '3', '#'),
- (0xFE60, '3', '&'),
- (0xFE61, '3', '*'),
- ]
-
-def _seg_50() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFE62, '3', '+'),
- (0xFE63, 'M', '-'),
- (0xFE64, '3', '<'),
- (0xFE65, '3', '>'),
- (0xFE66, '3', '='),
- (0xFE67, 'X'),
- (0xFE68, '3', '\\'),
- (0xFE69, '3', '$'),
- (0xFE6A, '3', '%'),
- (0xFE6B, '3', '@'),
- (0xFE6C, 'X'),
- (0xFE70, '3', ' ً'),
- (0xFE71, 'M', 'ـً'),
- (0xFE72, '3', ' ٌ'),
- (0xFE73, 'V'),
- (0xFE74, '3', ' ٍ'),
- (0xFE75, 'X'),
- (0xFE76, '3', ' َ'),
- (0xFE77, 'M', 'ـَ'),
- (0xFE78, '3', ' ُ'),
- (0xFE79, 'M', 'ـُ'),
- (0xFE7A, '3', ' ِ'),
- (0xFE7B, 'M', 'ـِ'),
- (0xFE7C, '3', ' ّ'),
- (0xFE7D, 'M', 'ـّ'),
- (0xFE7E, '3', ' ْ'),
- (0xFE7F, 'M', 'ـْ'),
- (0xFE80, 'M', 'ء'),
- (0xFE81, 'M', 'آ'),
- (0xFE83, 'M', 'أ'),
- (0xFE85, 'M', 'ؤ'),
- (0xFE87, 'M', 'إ'),
- (0xFE89, 'M', 'ئ'),
- (0xFE8D, 'M', 'ا'),
- (0xFE8F, 'M', 'ب'),
- (0xFE93, 'M', 'ة'),
- (0xFE95, 'M', 'ت'),
- (0xFE99, 'M', 'ث'),
- (0xFE9D, 'M', 'ج'),
- (0xFEA1, 'M', 'ح'),
- (0xFEA5, 'M', 'خ'),
- (0xFEA9, 'M', 'د'),
- (0xFEAB, 'M', 'ذ'),
- (0xFEAD, 'M', 'ر'),
- (0xFEAF, 'M', 'ز'),
- (0xFEB1, 'M', 'س'),
- (0xFEB5, 'M', 'ش'),
- (0xFEB9, 'M', 'ص'),
- (0xFEBD, 'M', 'ض'),
- (0xFEC1, 'M', 'ط'),
- (0xFEC5, 'M', 'ظ'),
- (0xFEC9, 'M', 'ع'),
- (0xFECD, 'M', 'غ'),
- (0xFED1, 'M', 'ف'),
- (0xFED5, 'M', 'ق'),
- (0xFED9, 'M', 'ك'),
- (0xFEDD, 'M', 'ل'),
- (0xFEE1, 'M', 'م'),
- (0xFEE5, 'M', 'ن'),
- (0xFEE9, 'M', 'ه'),
- (0xFEED, 'M', 'و'),
- (0xFEEF, 'M', 'ى'),
- (0xFEF1, 'M', 'ي'),
- (0xFEF5, 'M', 'لآ'),
- (0xFEF7, 'M', 'لأ'),
- (0xFEF9, 'M', 'لإ'),
- (0xFEFB, 'M', 'لا'),
- (0xFEFD, 'X'),
- (0xFEFF, 'I'),
- (0xFF00, 'X'),
- (0xFF01, '3', '!'),
- (0xFF02, '3', '"'),
- (0xFF03, '3', '#'),
- (0xFF04, '3', '$'),
- (0xFF05, '3', '%'),
- (0xFF06, '3', '&'),
- (0xFF07, '3', '\''),
- (0xFF08, '3', '('),
- (0xFF09, '3', ')'),
- (0xFF0A, '3', '*'),
- (0xFF0B, '3', '+'),
- (0xFF0C, '3', ','),
- (0xFF0D, 'M', '-'),
- (0xFF0E, 'M', '.'),
- (0xFF0F, '3', '/'),
- (0xFF10, 'M', '0'),
- (0xFF11, 'M', '1'),
- (0xFF12, 'M', '2'),
- (0xFF13, 'M', '3'),
- (0xFF14, 'M', '4'),
- (0xFF15, 'M', '5'),
- (0xFF16, 'M', '6'),
- (0xFF17, 'M', '7'),
- (0xFF18, 'M', '8'),
- (0xFF19, 'M', '9'),
- (0xFF1A, '3', ':'),
- (0xFF1B, '3', ';'),
- (0xFF1C, '3', '<'),
- (0xFF1D, '3', '='),
- (0xFF1E, '3', '>'),
- ]
-
-def _seg_51() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFF1F, '3', '?'),
- (0xFF20, '3', '@'),
- (0xFF21, 'M', 'a'),
- (0xFF22, 'M', 'b'),
- (0xFF23, 'M', 'c'),
- (0xFF24, 'M', 'd'),
- (0xFF25, 'M', 'e'),
- (0xFF26, 'M', 'f'),
- (0xFF27, 'M', 'g'),
- (0xFF28, 'M', 'h'),
- (0xFF29, 'M', 'i'),
- (0xFF2A, 'M', 'j'),
- (0xFF2B, 'M', 'k'),
- (0xFF2C, 'M', 'l'),
- (0xFF2D, 'M', 'm'),
- (0xFF2E, 'M', 'n'),
- (0xFF2F, 'M', 'o'),
- (0xFF30, 'M', 'p'),
- (0xFF31, 'M', 'q'),
- (0xFF32, 'M', 'r'),
- (0xFF33, 'M', 's'),
- (0xFF34, 'M', 't'),
- (0xFF35, 'M', 'u'),
- (0xFF36, 'M', 'v'),
- (0xFF37, 'M', 'w'),
- (0xFF38, 'M', 'x'),
- (0xFF39, 'M', 'y'),
- (0xFF3A, 'M', 'z'),
- (0xFF3B, '3', '['),
- (0xFF3C, '3', '\\'),
- (0xFF3D, '3', ']'),
- (0xFF3E, '3', '^'),
- (0xFF3F, '3', '_'),
- (0xFF40, '3', '`'),
- (0xFF41, 'M', 'a'),
- (0xFF42, 'M', 'b'),
- (0xFF43, 'M', 'c'),
- (0xFF44, 'M', 'd'),
- (0xFF45, 'M', 'e'),
- (0xFF46, 'M', 'f'),
- (0xFF47, 'M', 'g'),
- (0xFF48, 'M', 'h'),
- (0xFF49, 'M', 'i'),
- (0xFF4A, 'M', 'j'),
- (0xFF4B, 'M', 'k'),
- (0xFF4C, 'M', 'l'),
- (0xFF4D, 'M', 'm'),
- (0xFF4E, 'M', 'n'),
- (0xFF4F, 'M', 'o'),
- (0xFF50, 'M', 'p'),
- (0xFF51, 'M', 'q'),
- (0xFF52, 'M', 'r'),
- (0xFF53, 'M', 's'),
- (0xFF54, 'M', 't'),
- (0xFF55, 'M', 'u'),
- (0xFF56, 'M', 'v'),
- (0xFF57, 'M', 'w'),
- (0xFF58, 'M', 'x'),
- (0xFF59, 'M', 'y'),
- (0xFF5A, 'M', 'z'),
- (0xFF5B, '3', '{'),
- (0xFF5C, '3', '|'),
- (0xFF5D, '3', '}'),
- (0xFF5E, '3', '~'),
- (0xFF5F, 'M', '⦅'),
- (0xFF60, 'M', '⦆'),
- (0xFF61, 'M', '.'),
- (0xFF62, 'M', '「'),
- (0xFF63, 'M', '」'),
- (0xFF64, 'M', '、'),
- (0xFF65, 'M', '・'),
- (0xFF66, 'M', 'ヲ'),
- (0xFF67, 'M', 'ァ'),
- (0xFF68, 'M', 'ィ'),
- (0xFF69, 'M', 'ゥ'),
- (0xFF6A, 'M', 'ェ'),
- (0xFF6B, 'M', 'ォ'),
- (0xFF6C, 'M', 'ャ'),
- (0xFF6D, 'M', 'ュ'),
- (0xFF6E, 'M', 'ョ'),
- (0xFF6F, 'M', 'ッ'),
- (0xFF70, 'M', 'ー'),
- (0xFF71, 'M', 'ア'),
- (0xFF72, 'M', 'イ'),
- (0xFF73, 'M', 'ウ'),
- (0xFF74, 'M', 'エ'),
- (0xFF75, 'M', 'オ'),
- (0xFF76, 'M', 'カ'),
- (0xFF77, 'M', 'キ'),
- (0xFF78, 'M', 'ク'),
- (0xFF79, 'M', 'ケ'),
- (0xFF7A, 'M', 'コ'),
- (0xFF7B, 'M', 'サ'),
- (0xFF7C, 'M', 'シ'),
- (0xFF7D, 'M', 'ス'),
- (0xFF7E, 'M', 'セ'),
- (0xFF7F, 'M', 'ソ'),
- (0xFF80, 'M', 'タ'),
- (0xFF81, 'M', 'チ'),
- (0xFF82, 'M', 'ツ'),
- ]
-
-def _seg_52() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFF83, 'M', 'テ'),
- (0xFF84, 'M', 'ト'),
- (0xFF85, 'M', 'ナ'),
- (0xFF86, 'M', 'ニ'),
- (0xFF87, 'M', 'ヌ'),
- (0xFF88, 'M', 'ネ'),
- (0xFF89, 'M', 'ノ'),
- (0xFF8A, 'M', 'ハ'),
- (0xFF8B, 'M', 'ヒ'),
- (0xFF8C, 'M', 'フ'),
- (0xFF8D, 'M', 'ヘ'),
- (0xFF8E, 'M', 'ホ'),
- (0xFF8F, 'M', 'マ'),
- (0xFF90, 'M', 'ミ'),
- (0xFF91, 'M', 'ム'),
- (0xFF92, 'M', 'メ'),
- (0xFF93, 'M', 'モ'),
- (0xFF94, 'M', 'ヤ'),
- (0xFF95, 'M', 'ユ'),
- (0xFF96, 'M', 'ヨ'),
- (0xFF97, 'M', 'ラ'),
- (0xFF98, 'M', 'リ'),
- (0xFF99, 'M', 'ル'),
- (0xFF9A, 'M', 'レ'),
- (0xFF9B, 'M', 'ロ'),
- (0xFF9C, 'M', 'ワ'),
- (0xFF9D, 'M', 'ン'),
- (0xFF9E, 'M', '゙'),
- (0xFF9F, 'M', '゚'),
- (0xFFA0, 'X'),
- (0xFFA1, 'M', 'ᄀ'),
- (0xFFA2, 'M', 'ᄁ'),
- (0xFFA3, 'M', 'ᆪ'),
- (0xFFA4, 'M', 'ᄂ'),
- (0xFFA5, 'M', 'ᆬ'),
- (0xFFA6, 'M', 'ᆭ'),
- (0xFFA7, 'M', 'ᄃ'),
- (0xFFA8, 'M', 'ᄄ'),
- (0xFFA9, 'M', 'ᄅ'),
- (0xFFAA, 'M', 'ᆰ'),
- (0xFFAB, 'M', 'ᆱ'),
- (0xFFAC, 'M', 'ᆲ'),
- (0xFFAD, 'M', 'ᆳ'),
- (0xFFAE, 'M', 'ᆴ'),
- (0xFFAF, 'M', 'ᆵ'),
- (0xFFB0, 'M', 'ᄚ'),
- (0xFFB1, 'M', 'ᄆ'),
- (0xFFB2, 'M', 'ᄇ'),
- (0xFFB3, 'M', 'ᄈ'),
- (0xFFB4, 'M', 'ᄡ'),
- (0xFFB5, 'M', 'ᄉ'),
- (0xFFB6, 'M', 'ᄊ'),
- (0xFFB7, 'M', 'ᄋ'),
- (0xFFB8, 'M', 'ᄌ'),
- (0xFFB9, 'M', 'ᄍ'),
- (0xFFBA, 'M', 'ᄎ'),
- (0xFFBB, 'M', 'ᄏ'),
- (0xFFBC, 'M', 'ᄐ'),
- (0xFFBD, 'M', 'ᄑ'),
- (0xFFBE, 'M', 'ᄒ'),
- (0xFFBF, 'X'),
- (0xFFC2, 'M', 'ᅡ'),
- (0xFFC3, 'M', 'ᅢ'),
- (0xFFC4, 'M', 'ᅣ'),
- (0xFFC5, 'M', 'ᅤ'),
- (0xFFC6, 'M', 'ᅥ'),
- (0xFFC7, 'M', 'ᅦ'),
- (0xFFC8, 'X'),
- (0xFFCA, 'M', 'ᅧ'),
- (0xFFCB, 'M', 'ᅨ'),
- (0xFFCC, 'M', 'ᅩ'),
- (0xFFCD, 'M', 'ᅪ'),
- (0xFFCE, 'M', 'ᅫ'),
- (0xFFCF, 'M', 'ᅬ'),
- (0xFFD0, 'X'),
- (0xFFD2, 'M', 'ᅭ'),
- (0xFFD3, 'M', 'ᅮ'),
- (0xFFD4, 'M', 'ᅯ'),
- (0xFFD5, 'M', 'ᅰ'),
- (0xFFD6, 'M', 'ᅱ'),
- (0xFFD7, 'M', 'ᅲ'),
- (0xFFD8, 'X'),
- (0xFFDA, 'M', 'ᅳ'),
- (0xFFDB, 'M', 'ᅴ'),
- (0xFFDC, 'M', 'ᅵ'),
- (0xFFDD, 'X'),
- (0xFFE0, 'M', '¢'),
- (0xFFE1, 'M', '£'),
- (0xFFE2, 'M', '¬'),
- (0xFFE3, '3', ' ̄'),
- (0xFFE4, 'M', '¦'),
- (0xFFE5, 'M', '¥'),
- (0xFFE6, 'M', '₩'),
- (0xFFE7, 'X'),
- (0xFFE8, 'M', '│'),
- (0xFFE9, 'M', '←'),
- (0xFFEA, 'M', '↑'),
- (0xFFEB, 'M', '→'),
- (0xFFEC, 'M', '↓'),
- (0xFFED, 'M', '■'),
- ]
-
-def _seg_53() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0xFFEE, 'M', '○'),
- (0xFFEF, 'X'),
- (0x10000, 'V'),
- (0x1000C, 'X'),
- (0x1000D, 'V'),
- (0x10027, 'X'),
- (0x10028, 'V'),
- (0x1003B, 'X'),
- (0x1003C, 'V'),
- (0x1003E, 'X'),
- (0x1003F, 'V'),
- (0x1004E, 'X'),
- (0x10050, 'V'),
- (0x1005E, 'X'),
- (0x10080, 'V'),
- (0x100FB, 'X'),
- (0x10100, 'V'),
- (0x10103, 'X'),
- (0x10107, 'V'),
- (0x10134, 'X'),
- (0x10137, 'V'),
- (0x1018F, 'X'),
- (0x10190, 'V'),
- (0x1019D, 'X'),
- (0x101A0, 'V'),
- (0x101A1, 'X'),
- (0x101D0, 'V'),
- (0x101FE, 'X'),
- (0x10280, 'V'),
- (0x1029D, 'X'),
- (0x102A0, 'V'),
- (0x102D1, 'X'),
- (0x102E0, 'V'),
- (0x102FC, 'X'),
- (0x10300, 'V'),
- (0x10324, 'X'),
- (0x1032D, 'V'),
- (0x1034B, 'X'),
- (0x10350, 'V'),
- (0x1037B, 'X'),
- (0x10380, 'V'),
- (0x1039E, 'X'),
- (0x1039F, 'V'),
- (0x103C4, 'X'),
- (0x103C8, 'V'),
- (0x103D6, 'X'),
- (0x10400, 'M', '𐐨'),
- (0x10401, 'M', '𐐩'),
- (0x10402, 'M', '𐐪'),
- (0x10403, 'M', '𐐫'),
- (0x10404, 'M', '𐐬'),
- (0x10405, 'M', '𐐭'),
- (0x10406, 'M', '𐐮'),
- (0x10407, 'M', '𐐯'),
- (0x10408, 'M', '𐐰'),
- (0x10409, 'M', '𐐱'),
- (0x1040A, 'M', '𐐲'),
- (0x1040B, 'M', '𐐳'),
- (0x1040C, 'M', '𐐴'),
- (0x1040D, 'M', '𐐵'),
- (0x1040E, 'M', '𐐶'),
- (0x1040F, 'M', '𐐷'),
- (0x10410, 'M', '𐐸'),
- (0x10411, 'M', '𐐹'),
- (0x10412, 'M', '𐐺'),
- (0x10413, 'M', '𐐻'),
- (0x10414, 'M', '𐐼'),
- (0x10415, 'M', '𐐽'),
- (0x10416, 'M', '𐐾'),
- (0x10417, 'M', '𐐿'),
- (0x10418, 'M', '𐑀'),
- (0x10419, 'M', '𐑁'),
- (0x1041A, 'M', '𐑂'),
- (0x1041B, 'M', '𐑃'),
- (0x1041C, 'M', '𐑄'),
- (0x1041D, 'M', '𐑅'),
- (0x1041E, 'M', '𐑆'),
- (0x1041F, 'M', '𐑇'),
- (0x10420, 'M', '𐑈'),
- (0x10421, 'M', '𐑉'),
- (0x10422, 'M', '𐑊'),
- (0x10423, 'M', '𐑋'),
- (0x10424, 'M', '𐑌'),
- (0x10425, 'M', '𐑍'),
- (0x10426, 'M', '𐑎'),
- (0x10427, 'M', '𐑏'),
- (0x10428, 'V'),
- (0x1049E, 'X'),
- (0x104A0, 'V'),
- (0x104AA, 'X'),
- (0x104B0, 'M', '𐓘'),
- (0x104B1, 'M', '𐓙'),
- (0x104B2, 'M', '𐓚'),
- (0x104B3, 'M', '𐓛'),
- (0x104B4, 'M', '𐓜'),
- (0x104B5, 'M', '𐓝'),
- (0x104B6, 'M', '𐓞'),
- (0x104B7, 'M', '𐓟'),
- (0x104B8, 'M', '𐓠'),
- (0x104B9, 'M', '𐓡'),
- ]
-
-def _seg_54() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x104BA, 'M', '𐓢'),
- (0x104BB, 'M', '𐓣'),
- (0x104BC, 'M', '𐓤'),
- (0x104BD, 'M', '𐓥'),
- (0x104BE, 'M', '𐓦'),
- (0x104BF, 'M', '𐓧'),
- (0x104C0, 'M', '𐓨'),
- (0x104C1, 'M', '𐓩'),
- (0x104C2, 'M', '𐓪'),
- (0x104C3, 'M', '𐓫'),
- (0x104C4, 'M', '𐓬'),
- (0x104C5, 'M', '𐓭'),
- (0x104C6, 'M', '𐓮'),
- (0x104C7, 'M', '𐓯'),
- (0x104C8, 'M', '𐓰'),
- (0x104C9, 'M', '𐓱'),
- (0x104CA, 'M', '𐓲'),
- (0x104CB, 'M', '𐓳'),
- (0x104CC, 'M', '𐓴'),
- (0x104CD, 'M', '𐓵'),
- (0x104CE, 'M', '𐓶'),
- (0x104CF, 'M', '𐓷'),
- (0x104D0, 'M', '𐓸'),
- (0x104D1, 'M', '𐓹'),
- (0x104D2, 'M', '𐓺'),
- (0x104D3, 'M', '𐓻'),
- (0x104D4, 'X'),
- (0x104D8, 'V'),
- (0x104FC, 'X'),
- (0x10500, 'V'),
- (0x10528, 'X'),
- (0x10530, 'V'),
- (0x10564, 'X'),
- (0x1056F, 'V'),
- (0x10570, 'M', '𐖗'),
- (0x10571, 'M', '𐖘'),
- (0x10572, 'M', '𐖙'),
- (0x10573, 'M', '𐖚'),
- (0x10574, 'M', '𐖛'),
- (0x10575, 'M', '𐖜'),
- (0x10576, 'M', '𐖝'),
- (0x10577, 'M', '𐖞'),
- (0x10578, 'M', '𐖟'),
- (0x10579, 'M', '𐖠'),
- (0x1057A, 'M', '𐖡'),
- (0x1057B, 'X'),
- (0x1057C, 'M', '𐖣'),
- (0x1057D, 'M', '𐖤'),
- (0x1057E, 'M', '𐖥'),
- (0x1057F, 'M', '𐖦'),
- (0x10580, 'M', '𐖧'),
- (0x10581, 'M', '𐖨'),
- (0x10582, 'M', '𐖩'),
- (0x10583, 'M', '𐖪'),
- (0x10584, 'M', '𐖫'),
- (0x10585, 'M', '𐖬'),
- (0x10586, 'M', '𐖭'),
- (0x10587, 'M', '𐖮'),
- (0x10588, 'M', '𐖯'),
- (0x10589, 'M', '𐖰'),
- (0x1058A, 'M', '𐖱'),
- (0x1058B, 'X'),
- (0x1058C, 'M', '𐖳'),
- (0x1058D, 'M', '𐖴'),
- (0x1058E, 'M', '𐖵'),
- (0x1058F, 'M', '𐖶'),
- (0x10590, 'M', '𐖷'),
- (0x10591, 'M', '𐖸'),
- (0x10592, 'M', '𐖹'),
- (0x10593, 'X'),
- (0x10594, 'M', '𐖻'),
- (0x10595, 'M', '𐖼'),
- (0x10596, 'X'),
- (0x10597, 'V'),
- (0x105A2, 'X'),
- (0x105A3, 'V'),
- (0x105B2, 'X'),
- (0x105B3, 'V'),
- (0x105BA, 'X'),
- (0x105BB, 'V'),
- (0x105BD, 'X'),
- (0x10600, 'V'),
- (0x10737, 'X'),
- (0x10740, 'V'),
- (0x10756, 'X'),
- (0x10760, 'V'),
- (0x10768, 'X'),
- (0x10780, 'V'),
- (0x10781, 'M', 'ː'),
- (0x10782, 'M', 'ˑ'),
- (0x10783, 'M', 'æ'),
- (0x10784, 'M', 'ʙ'),
- (0x10785, 'M', 'ɓ'),
- (0x10786, 'X'),
- (0x10787, 'M', 'ʣ'),
- (0x10788, 'M', 'ꭦ'),
- (0x10789, 'M', 'ʥ'),
- (0x1078A, 'M', 'ʤ'),
- (0x1078B, 'M', 'ɖ'),
- (0x1078C, 'M', 'ɗ'),
- ]
-
-def _seg_55() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1078D, 'M', 'ᶑ'),
- (0x1078E, 'M', 'ɘ'),
- (0x1078F, 'M', 'ɞ'),
- (0x10790, 'M', 'ʩ'),
- (0x10791, 'M', 'ɤ'),
- (0x10792, 'M', 'ɢ'),
- (0x10793, 'M', 'ɠ'),
- (0x10794, 'M', 'ʛ'),
- (0x10795, 'M', 'ħ'),
- (0x10796, 'M', 'ʜ'),
- (0x10797, 'M', 'ɧ'),
- (0x10798, 'M', 'ʄ'),
- (0x10799, 'M', 'ʪ'),
- (0x1079A, 'M', 'ʫ'),
- (0x1079B, 'M', 'ɬ'),
- (0x1079C, 'M', '𝼄'),
- (0x1079D, 'M', 'ꞎ'),
- (0x1079E, 'M', 'ɮ'),
- (0x1079F, 'M', '𝼅'),
- (0x107A0, 'M', 'ʎ'),
- (0x107A1, 'M', '𝼆'),
- (0x107A2, 'M', 'ø'),
- (0x107A3, 'M', 'ɶ'),
- (0x107A4, 'M', 'ɷ'),
- (0x107A5, 'M', 'q'),
- (0x107A6, 'M', 'ɺ'),
- (0x107A7, 'M', '𝼈'),
- (0x107A8, 'M', 'ɽ'),
- (0x107A9, 'M', 'ɾ'),
- (0x107AA, 'M', 'ʀ'),
- (0x107AB, 'M', 'ʨ'),
- (0x107AC, 'M', 'ʦ'),
- (0x107AD, 'M', 'ꭧ'),
- (0x107AE, 'M', 'ʧ'),
- (0x107AF, 'M', 'ʈ'),
- (0x107B0, 'M', 'ⱱ'),
- (0x107B1, 'X'),
- (0x107B2, 'M', 'ʏ'),
- (0x107B3, 'M', 'ʡ'),
- (0x107B4, 'M', 'ʢ'),
- (0x107B5, 'M', 'ʘ'),
- (0x107B6, 'M', 'ǀ'),
- (0x107B7, 'M', 'ǁ'),
- (0x107B8, 'M', 'ǂ'),
- (0x107B9, 'M', '𝼊'),
- (0x107BA, 'M', '𝼞'),
- (0x107BB, 'X'),
- (0x10800, 'V'),
- (0x10806, 'X'),
- (0x10808, 'V'),
- (0x10809, 'X'),
- (0x1080A, 'V'),
- (0x10836, 'X'),
- (0x10837, 'V'),
- (0x10839, 'X'),
- (0x1083C, 'V'),
- (0x1083D, 'X'),
- (0x1083F, 'V'),
- (0x10856, 'X'),
- (0x10857, 'V'),
- (0x1089F, 'X'),
- (0x108A7, 'V'),
- (0x108B0, 'X'),
- (0x108E0, 'V'),
- (0x108F3, 'X'),
- (0x108F4, 'V'),
- (0x108F6, 'X'),
- (0x108FB, 'V'),
- (0x1091C, 'X'),
- (0x1091F, 'V'),
- (0x1093A, 'X'),
- (0x1093F, 'V'),
- (0x10940, 'X'),
- (0x10980, 'V'),
- (0x109B8, 'X'),
- (0x109BC, 'V'),
- (0x109D0, 'X'),
- (0x109D2, 'V'),
- (0x10A04, 'X'),
- (0x10A05, 'V'),
- (0x10A07, 'X'),
- (0x10A0C, 'V'),
- (0x10A14, 'X'),
- (0x10A15, 'V'),
- (0x10A18, 'X'),
- (0x10A19, 'V'),
- (0x10A36, 'X'),
- (0x10A38, 'V'),
- (0x10A3B, 'X'),
- (0x10A3F, 'V'),
- (0x10A49, 'X'),
- (0x10A50, 'V'),
- (0x10A59, 'X'),
- (0x10A60, 'V'),
- (0x10AA0, 'X'),
- (0x10AC0, 'V'),
- (0x10AE7, 'X'),
- (0x10AEB, 'V'),
- (0x10AF7, 'X'),
- (0x10B00, 'V'),
- ]
-
-def _seg_56() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x10B36, 'X'),
- (0x10B39, 'V'),
- (0x10B56, 'X'),
- (0x10B58, 'V'),
- (0x10B73, 'X'),
- (0x10B78, 'V'),
- (0x10B92, 'X'),
- (0x10B99, 'V'),
- (0x10B9D, 'X'),
- (0x10BA9, 'V'),
- (0x10BB0, 'X'),
- (0x10C00, 'V'),
- (0x10C49, 'X'),
- (0x10C80, 'M', '𐳀'),
- (0x10C81, 'M', '𐳁'),
- (0x10C82, 'M', '𐳂'),
- (0x10C83, 'M', '𐳃'),
- (0x10C84, 'M', '𐳄'),
- (0x10C85, 'M', '𐳅'),
- (0x10C86, 'M', '𐳆'),
- (0x10C87, 'M', '𐳇'),
- (0x10C88, 'M', '𐳈'),
- (0x10C89, 'M', '𐳉'),
- (0x10C8A, 'M', '𐳊'),
- (0x10C8B, 'M', '𐳋'),
- (0x10C8C, 'M', '𐳌'),
- (0x10C8D, 'M', '𐳍'),
- (0x10C8E, 'M', '𐳎'),
- (0x10C8F, 'M', '𐳏'),
- (0x10C90, 'M', '𐳐'),
- (0x10C91, 'M', '𐳑'),
- (0x10C92, 'M', '𐳒'),
- (0x10C93, 'M', '𐳓'),
- (0x10C94, 'M', '𐳔'),
- (0x10C95, 'M', '𐳕'),
- (0x10C96, 'M', '𐳖'),
- (0x10C97, 'M', '𐳗'),
- (0x10C98, 'M', '𐳘'),
- (0x10C99, 'M', '𐳙'),
- (0x10C9A, 'M', '𐳚'),
- (0x10C9B, 'M', '𐳛'),
- (0x10C9C, 'M', '𐳜'),
- (0x10C9D, 'M', '𐳝'),
- (0x10C9E, 'M', '𐳞'),
- (0x10C9F, 'M', '𐳟'),
- (0x10CA0, 'M', '𐳠'),
- (0x10CA1, 'M', '𐳡'),
- (0x10CA2, 'M', '𐳢'),
- (0x10CA3, 'M', '𐳣'),
- (0x10CA4, 'M', '𐳤'),
- (0x10CA5, 'M', '𐳥'),
- (0x10CA6, 'M', '𐳦'),
- (0x10CA7, 'M', '𐳧'),
- (0x10CA8, 'M', '𐳨'),
- (0x10CA9, 'M', '𐳩'),
- (0x10CAA, 'M', '𐳪'),
- (0x10CAB, 'M', '𐳫'),
- (0x10CAC, 'M', '𐳬'),
- (0x10CAD, 'M', '𐳭'),
- (0x10CAE, 'M', '𐳮'),
- (0x10CAF, 'M', '𐳯'),
- (0x10CB0, 'M', '𐳰'),
- (0x10CB1, 'M', '𐳱'),
- (0x10CB2, 'M', '𐳲'),
- (0x10CB3, 'X'),
- (0x10CC0, 'V'),
- (0x10CF3, 'X'),
- (0x10CFA, 'V'),
- (0x10D28, 'X'),
- (0x10D30, 'V'),
- (0x10D3A, 'X'),
- (0x10E60, 'V'),
- (0x10E7F, 'X'),
- (0x10E80, 'V'),
- (0x10EAA, 'X'),
- (0x10EAB, 'V'),
- (0x10EAE, 'X'),
- (0x10EB0, 'V'),
- (0x10EB2, 'X'),
- (0x10EFD, 'V'),
- (0x10F28, 'X'),
- (0x10F30, 'V'),
- (0x10F5A, 'X'),
- (0x10F70, 'V'),
- (0x10F8A, 'X'),
- (0x10FB0, 'V'),
- (0x10FCC, 'X'),
- (0x10FE0, 'V'),
- (0x10FF7, 'X'),
- (0x11000, 'V'),
- (0x1104E, 'X'),
- (0x11052, 'V'),
- (0x11076, 'X'),
- (0x1107F, 'V'),
- (0x110BD, 'X'),
- (0x110BE, 'V'),
- (0x110C3, 'X'),
- (0x110D0, 'V'),
- (0x110E9, 'X'),
- (0x110F0, 'V'),
- ]
-
-def _seg_57() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x110FA, 'X'),
- (0x11100, 'V'),
- (0x11135, 'X'),
- (0x11136, 'V'),
- (0x11148, 'X'),
- (0x11150, 'V'),
- (0x11177, 'X'),
- (0x11180, 'V'),
- (0x111E0, 'X'),
- (0x111E1, 'V'),
- (0x111F5, 'X'),
- (0x11200, 'V'),
- (0x11212, 'X'),
- (0x11213, 'V'),
- (0x11242, 'X'),
- (0x11280, 'V'),
- (0x11287, 'X'),
- (0x11288, 'V'),
- (0x11289, 'X'),
- (0x1128A, 'V'),
- (0x1128E, 'X'),
- (0x1128F, 'V'),
- (0x1129E, 'X'),
- (0x1129F, 'V'),
- (0x112AA, 'X'),
- (0x112B0, 'V'),
- (0x112EB, 'X'),
- (0x112F0, 'V'),
- (0x112FA, 'X'),
- (0x11300, 'V'),
- (0x11304, 'X'),
- (0x11305, 'V'),
- (0x1130D, 'X'),
- (0x1130F, 'V'),
- (0x11311, 'X'),
- (0x11313, 'V'),
- (0x11329, 'X'),
- (0x1132A, 'V'),
- (0x11331, 'X'),
- (0x11332, 'V'),
- (0x11334, 'X'),
- (0x11335, 'V'),
- (0x1133A, 'X'),
- (0x1133B, 'V'),
- (0x11345, 'X'),
- (0x11347, 'V'),
- (0x11349, 'X'),
- (0x1134B, 'V'),
- (0x1134E, 'X'),
- (0x11350, 'V'),
- (0x11351, 'X'),
- (0x11357, 'V'),
- (0x11358, 'X'),
- (0x1135D, 'V'),
- (0x11364, 'X'),
- (0x11366, 'V'),
- (0x1136D, 'X'),
- (0x11370, 'V'),
- (0x11375, 'X'),
- (0x11400, 'V'),
- (0x1145C, 'X'),
- (0x1145D, 'V'),
- (0x11462, 'X'),
- (0x11480, 'V'),
- (0x114C8, 'X'),
- (0x114D0, 'V'),
- (0x114DA, 'X'),
- (0x11580, 'V'),
- (0x115B6, 'X'),
- (0x115B8, 'V'),
- (0x115DE, 'X'),
- (0x11600, 'V'),
- (0x11645, 'X'),
- (0x11650, 'V'),
- (0x1165A, 'X'),
- (0x11660, 'V'),
- (0x1166D, 'X'),
- (0x11680, 'V'),
- (0x116BA, 'X'),
- (0x116C0, 'V'),
- (0x116CA, 'X'),
- (0x11700, 'V'),
- (0x1171B, 'X'),
- (0x1171D, 'V'),
- (0x1172C, 'X'),
- (0x11730, 'V'),
- (0x11747, 'X'),
- (0x11800, 'V'),
- (0x1183C, 'X'),
- (0x118A0, 'M', '𑣀'),
- (0x118A1, 'M', '𑣁'),
- (0x118A2, 'M', '𑣂'),
- (0x118A3, 'M', '𑣃'),
- (0x118A4, 'M', '𑣄'),
- (0x118A5, 'M', '𑣅'),
- (0x118A6, 'M', '𑣆'),
- (0x118A7, 'M', '𑣇'),
- (0x118A8, 'M', '𑣈'),
- (0x118A9, 'M', '𑣉'),
- (0x118AA, 'M', '𑣊'),
- ]
-
-def _seg_58() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x118AB, 'M', '𑣋'),
- (0x118AC, 'M', '𑣌'),
- (0x118AD, 'M', '𑣍'),
- (0x118AE, 'M', '𑣎'),
- (0x118AF, 'M', '𑣏'),
- (0x118B0, 'M', '𑣐'),
- (0x118B1, 'M', '𑣑'),
- (0x118B2, 'M', '𑣒'),
- (0x118B3, 'M', '𑣓'),
- (0x118B4, 'M', '𑣔'),
- (0x118B5, 'M', '𑣕'),
- (0x118B6, 'M', '𑣖'),
- (0x118B7, 'M', '𑣗'),
- (0x118B8, 'M', '𑣘'),
- (0x118B9, 'M', '𑣙'),
- (0x118BA, 'M', '𑣚'),
- (0x118BB, 'M', '𑣛'),
- (0x118BC, 'M', '𑣜'),
- (0x118BD, 'M', '𑣝'),
- (0x118BE, 'M', '𑣞'),
- (0x118BF, 'M', '𑣟'),
- (0x118C0, 'V'),
- (0x118F3, 'X'),
- (0x118FF, 'V'),
- (0x11907, 'X'),
- (0x11909, 'V'),
- (0x1190A, 'X'),
- (0x1190C, 'V'),
- (0x11914, 'X'),
- (0x11915, 'V'),
- (0x11917, 'X'),
- (0x11918, 'V'),
- (0x11936, 'X'),
- (0x11937, 'V'),
- (0x11939, 'X'),
- (0x1193B, 'V'),
- (0x11947, 'X'),
- (0x11950, 'V'),
- (0x1195A, 'X'),
- (0x119A0, 'V'),
- (0x119A8, 'X'),
- (0x119AA, 'V'),
- (0x119D8, 'X'),
- (0x119DA, 'V'),
- (0x119E5, 'X'),
- (0x11A00, 'V'),
- (0x11A48, 'X'),
- (0x11A50, 'V'),
- (0x11AA3, 'X'),
- (0x11AB0, 'V'),
- (0x11AF9, 'X'),
- (0x11B00, 'V'),
- (0x11B0A, 'X'),
- (0x11C00, 'V'),
- (0x11C09, 'X'),
- (0x11C0A, 'V'),
- (0x11C37, 'X'),
- (0x11C38, 'V'),
- (0x11C46, 'X'),
- (0x11C50, 'V'),
- (0x11C6D, 'X'),
- (0x11C70, 'V'),
- (0x11C90, 'X'),
- (0x11C92, 'V'),
- (0x11CA8, 'X'),
- (0x11CA9, 'V'),
- (0x11CB7, 'X'),
- (0x11D00, 'V'),
- (0x11D07, 'X'),
- (0x11D08, 'V'),
- (0x11D0A, 'X'),
- (0x11D0B, 'V'),
- (0x11D37, 'X'),
- (0x11D3A, 'V'),
- (0x11D3B, 'X'),
- (0x11D3C, 'V'),
- (0x11D3E, 'X'),
- (0x11D3F, 'V'),
- (0x11D48, 'X'),
- (0x11D50, 'V'),
- (0x11D5A, 'X'),
- (0x11D60, 'V'),
- (0x11D66, 'X'),
- (0x11D67, 'V'),
- (0x11D69, 'X'),
- (0x11D6A, 'V'),
- (0x11D8F, 'X'),
- (0x11D90, 'V'),
- (0x11D92, 'X'),
- (0x11D93, 'V'),
- (0x11D99, 'X'),
- (0x11DA0, 'V'),
- (0x11DAA, 'X'),
- (0x11EE0, 'V'),
- (0x11EF9, 'X'),
- (0x11F00, 'V'),
- (0x11F11, 'X'),
- (0x11F12, 'V'),
- (0x11F3B, 'X'),
- (0x11F3E, 'V'),
- ]
-
-def _seg_59() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x11F5A, 'X'),
- (0x11FB0, 'V'),
- (0x11FB1, 'X'),
- (0x11FC0, 'V'),
- (0x11FF2, 'X'),
- (0x11FFF, 'V'),
- (0x1239A, 'X'),
- (0x12400, 'V'),
- (0x1246F, 'X'),
- (0x12470, 'V'),
- (0x12475, 'X'),
- (0x12480, 'V'),
- (0x12544, 'X'),
- (0x12F90, 'V'),
- (0x12FF3, 'X'),
- (0x13000, 'V'),
- (0x13430, 'X'),
- (0x13440, 'V'),
- (0x13456, 'X'),
- (0x14400, 'V'),
- (0x14647, 'X'),
- (0x16800, 'V'),
- (0x16A39, 'X'),
- (0x16A40, 'V'),
- (0x16A5F, 'X'),
- (0x16A60, 'V'),
- (0x16A6A, 'X'),
- (0x16A6E, 'V'),
- (0x16ABF, 'X'),
- (0x16AC0, 'V'),
- (0x16ACA, 'X'),
- (0x16AD0, 'V'),
- (0x16AEE, 'X'),
- (0x16AF0, 'V'),
- (0x16AF6, 'X'),
- (0x16B00, 'V'),
- (0x16B46, 'X'),
- (0x16B50, 'V'),
- (0x16B5A, 'X'),
- (0x16B5B, 'V'),
- (0x16B62, 'X'),
- (0x16B63, 'V'),
- (0x16B78, 'X'),
- (0x16B7D, 'V'),
- (0x16B90, 'X'),
- (0x16E40, 'M', '𖹠'),
- (0x16E41, 'M', '𖹡'),
- (0x16E42, 'M', '𖹢'),
- (0x16E43, 'M', '𖹣'),
- (0x16E44, 'M', '𖹤'),
- (0x16E45, 'M', '𖹥'),
- (0x16E46, 'M', '𖹦'),
- (0x16E47, 'M', '𖹧'),
- (0x16E48, 'M', '𖹨'),
- (0x16E49, 'M', '𖹩'),
- (0x16E4A, 'M', '𖹪'),
- (0x16E4B, 'M', '𖹫'),
- (0x16E4C, 'M', '𖹬'),
- (0x16E4D, 'M', '𖹭'),
- (0x16E4E, 'M', '𖹮'),
- (0x16E4F, 'M', '𖹯'),
- (0x16E50, 'M', '𖹰'),
- (0x16E51, 'M', '𖹱'),
- (0x16E52, 'M', '𖹲'),
- (0x16E53, 'M', '𖹳'),
- (0x16E54, 'M', '𖹴'),
- (0x16E55, 'M', '𖹵'),
- (0x16E56, 'M', '𖹶'),
- (0x16E57, 'M', '𖹷'),
- (0x16E58, 'M', '𖹸'),
- (0x16E59, 'M', '𖹹'),
- (0x16E5A, 'M', '𖹺'),
- (0x16E5B, 'M', '𖹻'),
- (0x16E5C, 'M', '𖹼'),
- (0x16E5D, 'M', '𖹽'),
- (0x16E5E, 'M', '𖹾'),
- (0x16E5F, 'M', '𖹿'),
- (0x16E60, 'V'),
- (0x16E9B, 'X'),
- (0x16F00, 'V'),
- (0x16F4B, 'X'),
- (0x16F4F, 'V'),
- (0x16F88, 'X'),
- (0x16F8F, 'V'),
- (0x16FA0, 'X'),
- (0x16FE0, 'V'),
- (0x16FE5, 'X'),
- (0x16FF0, 'V'),
- (0x16FF2, 'X'),
- (0x17000, 'V'),
- (0x187F8, 'X'),
- (0x18800, 'V'),
- (0x18CD6, 'X'),
- (0x18D00, 'V'),
- (0x18D09, 'X'),
- (0x1AFF0, 'V'),
- (0x1AFF4, 'X'),
- (0x1AFF5, 'V'),
- (0x1AFFC, 'X'),
- (0x1AFFD, 'V'),
- ]
-
-def _seg_60() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1AFFF, 'X'),
- (0x1B000, 'V'),
- (0x1B123, 'X'),
- (0x1B132, 'V'),
- (0x1B133, 'X'),
- (0x1B150, 'V'),
- (0x1B153, 'X'),
- (0x1B155, 'V'),
- (0x1B156, 'X'),
- (0x1B164, 'V'),
- (0x1B168, 'X'),
- (0x1B170, 'V'),
- (0x1B2FC, 'X'),
- (0x1BC00, 'V'),
- (0x1BC6B, 'X'),
- (0x1BC70, 'V'),
- (0x1BC7D, 'X'),
- (0x1BC80, 'V'),
- (0x1BC89, 'X'),
- (0x1BC90, 'V'),
- (0x1BC9A, 'X'),
- (0x1BC9C, 'V'),
- (0x1BCA0, 'I'),
- (0x1BCA4, 'X'),
- (0x1CF00, 'V'),
- (0x1CF2E, 'X'),
- (0x1CF30, 'V'),
- (0x1CF47, 'X'),
- (0x1CF50, 'V'),
- (0x1CFC4, 'X'),
- (0x1D000, 'V'),
- (0x1D0F6, 'X'),
- (0x1D100, 'V'),
- (0x1D127, 'X'),
- (0x1D129, 'V'),
- (0x1D15E, 'M', '𝅗𝅥'),
- (0x1D15F, 'M', '𝅘𝅥'),
- (0x1D160, 'M', '𝅘𝅥𝅮'),
- (0x1D161, 'M', '𝅘𝅥𝅯'),
- (0x1D162, 'M', '𝅘𝅥𝅰'),
- (0x1D163, 'M', '𝅘𝅥𝅱'),
- (0x1D164, 'M', '𝅘𝅥𝅲'),
- (0x1D165, 'V'),
- (0x1D173, 'X'),
- (0x1D17B, 'V'),
- (0x1D1BB, 'M', '𝆹𝅥'),
- (0x1D1BC, 'M', '𝆺𝅥'),
- (0x1D1BD, 'M', '𝆹𝅥𝅮'),
- (0x1D1BE, 'M', '𝆺𝅥𝅮'),
- (0x1D1BF, 'M', '𝆹𝅥𝅯'),
- (0x1D1C0, 'M', '𝆺𝅥𝅯'),
- (0x1D1C1, 'V'),
- (0x1D1EB, 'X'),
- (0x1D200, 'V'),
- (0x1D246, 'X'),
- (0x1D2C0, 'V'),
- (0x1D2D4, 'X'),
- (0x1D2E0, 'V'),
- (0x1D2F4, 'X'),
- (0x1D300, 'V'),
- (0x1D357, 'X'),
- (0x1D360, 'V'),
- (0x1D379, 'X'),
- (0x1D400, 'M', 'a'),
- (0x1D401, 'M', 'b'),
- (0x1D402, 'M', 'c'),
- (0x1D403, 'M', 'd'),
- (0x1D404, 'M', 'e'),
- (0x1D405, 'M', 'f'),
- (0x1D406, 'M', 'g'),
- (0x1D407, 'M', 'h'),
- (0x1D408, 'M', 'i'),
- (0x1D409, 'M', 'j'),
- (0x1D40A, 'M', 'k'),
- (0x1D40B, 'M', 'l'),
- (0x1D40C, 'M', 'm'),
- (0x1D40D, 'M', 'n'),
- (0x1D40E, 'M', 'o'),
- (0x1D40F, 'M', 'p'),
- (0x1D410, 'M', 'q'),
- (0x1D411, 'M', 'r'),
- (0x1D412, 'M', 's'),
- (0x1D413, 'M', 't'),
- (0x1D414, 'M', 'u'),
- (0x1D415, 'M', 'v'),
- (0x1D416, 'M', 'w'),
- (0x1D417, 'M', 'x'),
- (0x1D418, 'M', 'y'),
- (0x1D419, 'M', 'z'),
- (0x1D41A, 'M', 'a'),
- (0x1D41B, 'M', 'b'),
- (0x1D41C, 'M', 'c'),
- (0x1D41D, 'M', 'd'),
- (0x1D41E, 'M', 'e'),
- (0x1D41F, 'M', 'f'),
- (0x1D420, 'M', 'g'),
- (0x1D421, 'M', 'h'),
- (0x1D422, 'M', 'i'),
- (0x1D423, 'M', 'j'),
- (0x1D424, 'M', 'k'),
- ]
-
-def _seg_61() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D425, 'M', 'l'),
- (0x1D426, 'M', 'm'),
- (0x1D427, 'M', 'n'),
- (0x1D428, 'M', 'o'),
- (0x1D429, 'M', 'p'),
- (0x1D42A, 'M', 'q'),
- (0x1D42B, 'M', 'r'),
- (0x1D42C, 'M', 's'),
- (0x1D42D, 'M', 't'),
- (0x1D42E, 'M', 'u'),
- (0x1D42F, 'M', 'v'),
- (0x1D430, 'M', 'w'),
- (0x1D431, 'M', 'x'),
- (0x1D432, 'M', 'y'),
- (0x1D433, 'M', 'z'),
- (0x1D434, 'M', 'a'),
- (0x1D435, 'M', 'b'),
- (0x1D436, 'M', 'c'),
- (0x1D437, 'M', 'd'),
- (0x1D438, 'M', 'e'),
- (0x1D439, 'M', 'f'),
- (0x1D43A, 'M', 'g'),
- (0x1D43B, 'M', 'h'),
- (0x1D43C, 'M', 'i'),
- (0x1D43D, 'M', 'j'),
- (0x1D43E, 'M', 'k'),
- (0x1D43F, 'M', 'l'),
- (0x1D440, 'M', 'm'),
- (0x1D441, 'M', 'n'),
- (0x1D442, 'M', 'o'),
- (0x1D443, 'M', 'p'),
- (0x1D444, 'M', 'q'),
- (0x1D445, 'M', 'r'),
- (0x1D446, 'M', 's'),
- (0x1D447, 'M', 't'),
- (0x1D448, 'M', 'u'),
- (0x1D449, 'M', 'v'),
- (0x1D44A, 'M', 'w'),
- (0x1D44B, 'M', 'x'),
- (0x1D44C, 'M', 'y'),
- (0x1D44D, 'M', 'z'),
- (0x1D44E, 'M', 'a'),
- (0x1D44F, 'M', 'b'),
- (0x1D450, 'M', 'c'),
- (0x1D451, 'M', 'd'),
- (0x1D452, 'M', 'e'),
- (0x1D453, 'M', 'f'),
- (0x1D454, 'M', 'g'),
- (0x1D455, 'X'),
- (0x1D456, 'M', 'i'),
- (0x1D457, 'M', 'j'),
- (0x1D458, 'M', 'k'),
- (0x1D459, 'M', 'l'),
- (0x1D45A, 'M', 'm'),
- (0x1D45B, 'M', 'n'),
- (0x1D45C, 'M', 'o'),
- (0x1D45D, 'M', 'p'),
- (0x1D45E, 'M', 'q'),
- (0x1D45F, 'M', 'r'),
- (0x1D460, 'M', 's'),
- (0x1D461, 'M', 't'),
- (0x1D462, 'M', 'u'),
- (0x1D463, 'M', 'v'),
- (0x1D464, 'M', 'w'),
- (0x1D465, 'M', 'x'),
- (0x1D466, 'M', 'y'),
- (0x1D467, 'M', 'z'),
- (0x1D468, 'M', 'a'),
- (0x1D469, 'M', 'b'),
- (0x1D46A, 'M', 'c'),
- (0x1D46B, 'M', 'd'),
- (0x1D46C, 'M', 'e'),
- (0x1D46D, 'M', 'f'),
- (0x1D46E, 'M', 'g'),
- (0x1D46F, 'M', 'h'),
- (0x1D470, 'M', 'i'),
- (0x1D471, 'M', 'j'),
- (0x1D472, 'M', 'k'),
- (0x1D473, 'M', 'l'),
- (0x1D474, 'M', 'm'),
- (0x1D475, 'M', 'n'),
- (0x1D476, 'M', 'o'),
- (0x1D477, 'M', 'p'),
- (0x1D478, 'M', 'q'),
- (0x1D479, 'M', 'r'),
- (0x1D47A, 'M', 's'),
- (0x1D47B, 'M', 't'),
- (0x1D47C, 'M', 'u'),
- (0x1D47D, 'M', 'v'),
- (0x1D47E, 'M', 'w'),
- (0x1D47F, 'M', 'x'),
- (0x1D480, 'M', 'y'),
- (0x1D481, 'M', 'z'),
- (0x1D482, 'M', 'a'),
- (0x1D483, 'M', 'b'),
- (0x1D484, 'M', 'c'),
- (0x1D485, 'M', 'd'),
- (0x1D486, 'M', 'e'),
- (0x1D487, 'M', 'f'),
- (0x1D488, 'M', 'g'),
- ]
-
-def _seg_62() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D489, 'M', 'h'),
- (0x1D48A, 'M', 'i'),
- (0x1D48B, 'M', 'j'),
- (0x1D48C, 'M', 'k'),
- (0x1D48D, 'M', 'l'),
- (0x1D48E, 'M', 'm'),
- (0x1D48F, 'M', 'n'),
- (0x1D490, 'M', 'o'),
- (0x1D491, 'M', 'p'),
- (0x1D492, 'M', 'q'),
- (0x1D493, 'M', 'r'),
- (0x1D494, 'M', 's'),
- (0x1D495, 'M', 't'),
- (0x1D496, 'M', 'u'),
- (0x1D497, 'M', 'v'),
- (0x1D498, 'M', 'w'),
- (0x1D499, 'M', 'x'),
- (0x1D49A, 'M', 'y'),
- (0x1D49B, 'M', 'z'),
- (0x1D49C, 'M', 'a'),
- (0x1D49D, 'X'),
- (0x1D49E, 'M', 'c'),
- (0x1D49F, 'M', 'd'),
- (0x1D4A0, 'X'),
- (0x1D4A2, 'M', 'g'),
- (0x1D4A3, 'X'),
- (0x1D4A5, 'M', 'j'),
- (0x1D4A6, 'M', 'k'),
- (0x1D4A7, 'X'),
- (0x1D4A9, 'M', 'n'),
- (0x1D4AA, 'M', 'o'),
- (0x1D4AB, 'M', 'p'),
- (0x1D4AC, 'M', 'q'),
- (0x1D4AD, 'X'),
- (0x1D4AE, 'M', 's'),
- (0x1D4AF, 'M', 't'),
- (0x1D4B0, 'M', 'u'),
- (0x1D4B1, 'M', 'v'),
- (0x1D4B2, 'M', 'w'),
- (0x1D4B3, 'M', 'x'),
- (0x1D4B4, 'M', 'y'),
- (0x1D4B5, 'M', 'z'),
- (0x1D4B6, 'M', 'a'),
- (0x1D4B7, 'M', 'b'),
- (0x1D4B8, 'M', 'c'),
- (0x1D4B9, 'M', 'd'),
- (0x1D4BA, 'X'),
- (0x1D4BB, 'M', 'f'),
- (0x1D4BC, 'X'),
- (0x1D4BD, 'M', 'h'),
- (0x1D4BE, 'M', 'i'),
- (0x1D4BF, 'M', 'j'),
- (0x1D4C0, 'M', 'k'),
- (0x1D4C1, 'M', 'l'),
- (0x1D4C2, 'M', 'm'),
- (0x1D4C3, 'M', 'n'),
- (0x1D4C4, 'X'),
- (0x1D4C5, 'M', 'p'),
- (0x1D4C6, 'M', 'q'),
- (0x1D4C7, 'M', 'r'),
- (0x1D4C8, 'M', 's'),
- (0x1D4C9, 'M', 't'),
- (0x1D4CA, 'M', 'u'),
- (0x1D4CB, 'M', 'v'),
- (0x1D4CC, 'M', 'w'),
- (0x1D4CD, 'M', 'x'),
- (0x1D4CE, 'M', 'y'),
- (0x1D4CF, 'M', 'z'),
- (0x1D4D0, 'M', 'a'),
- (0x1D4D1, 'M', 'b'),
- (0x1D4D2, 'M', 'c'),
- (0x1D4D3, 'M', 'd'),
- (0x1D4D4, 'M', 'e'),
- (0x1D4D5, 'M', 'f'),
- (0x1D4D6, 'M', 'g'),
- (0x1D4D7, 'M', 'h'),
- (0x1D4D8, 'M', 'i'),
- (0x1D4D9, 'M', 'j'),
- (0x1D4DA, 'M', 'k'),
- (0x1D4DB, 'M', 'l'),
- (0x1D4DC, 'M', 'm'),
- (0x1D4DD, 'M', 'n'),
- (0x1D4DE, 'M', 'o'),
- (0x1D4DF, 'M', 'p'),
- (0x1D4E0, 'M', 'q'),
- (0x1D4E1, 'M', 'r'),
- (0x1D4E2, 'M', 's'),
- (0x1D4E3, 'M', 't'),
- (0x1D4E4, 'M', 'u'),
- (0x1D4E5, 'M', 'v'),
- (0x1D4E6, 'M', 'w'),
- (0x1D4E7, 'M', 'x'),
- (0x1D4E8, 'M', 'y'),
- (0x1D4E9, 'M', 'z'),
- (0x1D4EA, 'M', 'a'),
- (0x1D4EB, 'M', 'b'),
- (0x1D4EC, 'M', 'c'),
- (0x1D4ED, 'M', 'd'),
- (0x1D4EE, 'M', 'e'),
- (0x1D4EF, 'M', 'f'),
- ]
-
-def _seg_63() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D4F0, 'M', 'g'),
- (0x1D4F1, 'M', 'h'),
- (0x1D4F2, 'M', 'i'),
- (0x1D4F3, 'M', 'j'),
- (0x1D4F4, 'M', 'k'),
- (0x1D4F5, 'M', 'l'),
- (0x1D4F6, 'M', 'm'),
- (0x1D4F7, 'M', 'n'),
- (0x1D4F8, 'M', 'o'),
- (0x1D4F9, 'M', 'p'),
- (0x1D4FA, 'M', 'q'),
- (0x1D4FB, 'M', 'r'),
- (0x1D4FC, 'M', 's'),
- (0x1D4FD, 'M', 't'),
- (0x1D4FE, 'M', 'u'),
- (0x1D4FF, 'M', 'v'),
- (0x1D500, 'M', 'w'),
- (0x1D501, 'M', 'x'),
- (0x1D502, 'M', 'y'),
- (0x1D503, 'M', 'z'),
- (0x1D504, 'M', 'a'),
- (0x1D505, 'M', 'b'),
- (0x1D506, 'X'),
- (0x1D507, 'M', 'd'),
- (0x1D508, 'M', 'e'),
- (0x1D509, 'M', 'f'),
- (0x1D50A, 'M', 'g'),
- (0x1D50B, 'X'),
- (0x1D50D, 'M', 'j'),
- (0x1D50E, 'M', 'k'),
- (0x1D50F, 'M', 'l'),
- (0x1D510, 'M', 'm'),
- (0x1D511, 'M', 'n'),
- (0x1D512, 'M', 'o'),
- (0x1D513, 'M', 'p'),
- (0x1D514, 'M', 'q'),
- (0x1D515, 'X'),
- (0x1D516, 'M', 's'),
- (0x1D517, 'M', 't'),
- (0x1D518, 'M', 'u'),
- (0x1D519, 'M', 'v'),
- (0x1D51A, 'M', 'w'),
- (0x1D51B, 'M', 'x'),
- (0x1D51C, 'M', 'y'),
- (0x1D51D, 'X'),
- (0x1D51E, 'M', 'a'),
- (0x1D51F, 'M', 'b'),
- (0x1D520, 'M', 'c'),
- (0x1D521, 'M', 'd'),
- (0x1D522, 'M', 'e'),
- (0x1D523, 'M', 'f'),
- (0x1D524, 'M', 'g'),
- (0x1D525, 'M', 'h'),
- (0x1D526, 'M', 'i'),
- (0x1D527, 'M', 'j'),
- (0x1D528, 'M', 'k'),
- (0x1D529, 'M', 'l'),
- (0x1D52A, 'M', 'm'),
- (0x1D52B, 'M', 'n'),
- (0x1D52C, 'M', 'o'),
- (0x1D52D, 'M', 'p'),
- (0x1D52E, 'M', 'q'),
- (0x1D52F, 'M', 'r'),
- (0x1D530, 'M', 's'),
- (0x1D531, 'M', 't'),
- (0x1D532, 'M', 'u'),
- (0x1D533, 'M', 'v'),
- (0x1D534, 'M', 'w'),
- (0x1D535, 'M', 'x'),
- (0x1D536, 'M', 'y'),
- (0x1D537, 'M', 'z'),
- (0x1D538, 'M', 'a'),
- (0x1D539, 'M', 'b'),
- (0x1D53A, 'X'),
- (0x1D53B, 'M', 'd'),
- (0x1D53C, 'M', 'e'),
- (0x1D53D, 'M', 'f'),
- (0x1D53E, 'M', 'g'),
- (0x1D53F, 'X'),
- (0x1D540, 'M', 'i'),
- (0x1D541, 'M', 'j'),
- (0x1D542, 'M', 'k'),
- (0x1D543, 'M', 'l'),
- (0x1D544, 'M', 'm'),
- (0x1D545, 'X'),
- (0x1D546, 'M', 'o'),
- (0x1D547, 'X'),
- (0x1D54A, 'M', 's'),
- (0x1D54B, 'M', 't'),
- (0x1D54C, 'M', 'u'),
- (0x1D54D, 'M', 'v'),
- (0x1D54E, 'M', 'w'),
- (0x1D54F, 'M', 'x'),
- (0x1D550, 'M', 'y'),
- (0x1D551, 'X'),
- (0x1D552, 'M', 'a'),
- (0x1D553, 'M', 'b'),
- (0x1D554, 'M', 'c'),
- (0x1D555, 'M', 'd'),
- (0x1D556, 'M', 'e'),
- ]
-
-def _seg_64() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D557, 'M', 'f'),
- (0x1D558, 'M', 'g'),
- (0x1D559, 'M', 'h'),
- (0x1D55A, 'M', 'i'),
- (0x1D55B, 'M', 'j'),
- (0x1D55C, 'M', 'k'),
- (0x1D55D, 'M', 'l'),
- (0x1D55E, 'M', 'm'),
- (0x1D55F, 'M', 'n'),
- (0x1D560, 'M', 'o'),
- (0x1D561, 'M', 'p'),
- (0x1D562, 'M', 'q'),
- (0x1D563, 'M', 'r'),
- (0x1D564, 'M', 's'),
- (0x1D565, 'M', 't'),
- (0x1D566, 'M', 'u'),
- (0x1D567, 'M', 'v'),
- (0x1D568, 'M', 'w'),
- (0x1D569, 'M', 'x'),
- (0x1D56A, 'M', 'y'),
- (0x1D56B, 'M', 'z'),
- (0x1D56C, 'M', 'a'),
- (0x1D56D, 'M', 'b'),
- (0x1D56E, 'M', 'c'),
- (0x1D56F, 'M', 'd'),
- (0x1D570, 'M', 'e'),
- (0x1D571, 'M', 'f'),
- (0x1D572, 'M', 'g'),
- (0x1D573, 'M', 'h'),
- (0x1D574, 'M', 'i'),
- (0x1D575, 'M', 'j'),
- (0x1D576, 'M', 'k'),
- (0x1D577, 'M', 'l'),
- (0x1D578, 'M', 'm'),
- (0x1D579, 'M', 'n'),
- (0x1D57A, 'M', 'o'),
- (0x1D57B, 'M', 'p'),
- (0x1D57C, 'M', 'q'),
- (0x1D57D, 'M', 'r'),
- (0x1D57E, 'M', 's'),
- (0x1D57F, 'M', 't'),
- (0x1D580, 'M', 'u'),
- (0x1D581, 'M', 'v'),
- (0x1D582, 'M', 'w'),
- (0x1D583, 'M', 'x'),
- (0x1D584, 'M', 'y'),
- (0x1D585, 'M', 'z'),
- (0x1D586, 'M', 'a'),
- (0x1D587, 'M', 'b'),
- (0x1D588, 'M', 'c'),
- (0x1D589, 'M', 'd'),
- (0x1D58A, 'M', 'e'),
- (0x1D58B, 'M', 'f'),
- (0x1D58C, 'M', 'g'),
- (0x1D58D, 'M', 'h'),
- (0x1D58E, 'M', 'i'),
- (0x1D58F, 'M', 'j'),
- (0x1D590, 'M', 'k'),
- (0x1D591, 'M', 'l'),
- (0x1D592, 'M', 'm'),
- (0x1D593, 'M', 'n'),
- (0x1D594, 'M', 'o'),
- (0x1D595, 'M', 'p'),
- (0x1D596, 'M', 'q'),
- (0x1D597, 'M', 'r'),
- (0x1D598, 'M', 's'),
- (0x1D599, 'M', 't'),
- (0x1D59A, 'M', 'u'),
- (0x1D59B, 'M', 'v'),
- (0x1D59C, 'M', 'w'),
- (0x1D59D, 'M', 'x'),
- (0x1D59E, 'M', 'y'),
- (0x1D59F, 'M', 'z'),
- (0x1D5A0, 'M', 'a'),
- (0x1D5A1, 'M', 'b'),
- (0x1D5A2, 'M', 'c'),
- (0x1D5A3, 'M', 'd'),
- (0x1D5A4, 'M', 'e'),
- (0x1D5A5, 'M', 'f'),
- (0x1D5A6, 'M', 'g'),
- (0x1D5A7, 'M', 'h'),
- (0x1D5A8, 'M', 'i'),
- (0x1D5A9, 'M', 'j'),
- (0x1D5AA, 'M', 'k'),
- (0x1D5AB, 'M', 'l'),
- (0x1D5AC, 'M', 'm'),
- (0x1D5AD, 'M', 'n'),
- (0x1D5AE, 'M', 'o'),
- (0x1D5AF, 'M', 'p'),
- (0x1D5B0, 'M', 'q'),
- (0x1D5B1, 'M', 'r'),
- (0x1D5B2, 'M', 's'),
- (0x1D5B3, 'M', 't'),
- (0x1D5B4, 'M', 'u'),
- (0x1D5B5, 'M', 'v'),
- (0x1D5B6, 'M', 'w'),
- (0x1D5B7, 'M', 'x'),
- (0x1D5B8, 'M', 'y'),
- (0x1D5B9, 'M', 'z'),
- (0x1D5BA, 'M', 'a'),
- ]
-
-def _seg_65() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D5BB, 'M', 'b'),
- (0x1D5BC, 'M', 'c'),
- (0x1D5BD, 'M', 'd'),
- (0x1D5BE, 'M', 'e'),
- (0x1D5BF, 'M', 'f'),
- (0x1D5C0, 'M', 'g'),
- (0x1D5C1, 'M', 'h'),
- (0x1D5C2, 'M', 'i'),
- (0x1D5C3, 'M', 'j'),
- (0x1D5C4, 'M', 'k'),
- (0x1D5C5, 'M', 'l'),
- (0x1D5C6, 'M', 'm'),
- (0x1D5C7, 'M', 'n'),
- (0x1D5C8, 'M', 'o'),
- (0x1D5C9, 'M', 'p'),
- (0x1D5CA, 'M', 'q'),
- (0x1D5CB, 'M', 'r'),
- (0x1D5CC, 'M', 's'),
- (0x1D5CD, 'M', 't'),
- (0x1D5CE, 'M', 'u'),
- (0x1D5CF, 'M', 'v'),
- (0x1D5D0, 'M', 'w'),
- (0x1D5D1, 'M', 'x'),
- (0x1D5D2, 'M', 'y'),
- (0x1D5D3, 'M', 'z'),
- (0x1D5D4, 'M', 'a'),
- (0x1D5D5, 'M', 'b'),
- (0x1D5D6, 'M', 'c'),
- (0x1D5D7, 'M', 'd'),
- (0x1D5D8, 'M', 'e'),
- (0x1D5D9, 'M', 'f'),
- (0x1D5DA, 'M', 'g'),
- (0x1D5DB, 'M', 'h'),
- (0x1D5DC, 'M', 'i'),
- (0x1D5DD, 'M', 'j'),
- (0x1D5DE, 'M', 'k'),
- (0x1D5DF, 'M', 'l'),
- (0x1D5E0, 'M', 'm'),
- (0x1D5E1, 'M', 'n'),
- (0x1D5E2, 'M', 'o'),
- (0x1D5E3, 'M', 'p'),
- (0x1D5E4, 'M', 'q'),
- (0x1D5E5, 'M', 'r'),
- (0x1D5E6, 'M', 's'),
- (0x1D5E7, 'M', 't'),
- (0x1D5E8, 'M', 'u'),
- (0x1D5E9, 'M', 'v'),
- (0x1D5EA, 'M', 'w'),
- (0x1D5EB, 'M', 'x'),
- (0x1D5EC, 'M', 'y'),
- (0x1D5ED, 'M', 'z'),
- (0x1D5EE, 'M', 'a'),
- (0x1D5EF, 'M', 'b'),
- (0x1D5F0, 'M', 'c'),
- (0x1D5F1, 'M', 'd'),
- (0x1D5F2, 'M', 'e'),
- (0x1D5F3, 'M', 'f'),
- (0x1D5F4, 'M', 'g'),
- (0x1D5F5, 'M', 'h'),
- (0x1D5F6, 'M', 'i'),
- (0x1D5F7, 'M', 'j'),
- (0x1D5F8, 'M', 'k'),
- (0x1D5F9, 'M', 'l'),
- (0x1D5FA, 'M', 'm'),
- (0x1D5FB, 'M', 'n'),
- (0x1D5FC, 'M', 'o'),
- (0x1D5FD, 'M', 'p'),
- (0x1D5FE, 'M', 'q'),
- (0x1D5FF, 'M', 'r'),
- (0x1D600, 'M', 's'),
- (0x1D601, 'M', 't'),
- (0x1D602, 'M', 'u'),
- (0x1D603, 'M', 'v'),
- (0x1D604, 'M', 'w'),
- (0x1D605, 'M', 'x'),
- (0x1D606, 'M', 'y'),
- (0x1D607, 'M', 'z'),
- (0x1D608, 'M', 'a'),
- (0x1D609, 'M', 'b'),
- (0x1D60A, 'M', 'c'),
- (0x1D60B, 'M', 'd'),
- (0x1D60C, 'M', 'e'),
- (0x1D60D, 'M', 'f'),
- (0x1D60E, 'M', 'g'),
- (0x1D60F, 'M', 'h'),
- (0x1D610, 'M', 'i'),
- (0x1D611, 'M', 'j'),
- (0x1D612, 'M', 'k'),
- (0x1D613, 'M', 'l'),
- (0x1D614, 'M', 'm'),
- (0x1D615, 'M', 'n'),
- (0x1D616, 'M', 'o'),
- (0x1D617, 'M', 'p'),
- (0x1D618, 'M', 'q'),
- (0x1D619, 'M', 'r'),
- (0x1D61A, 'M', 's'),
- (0x1D61B, 'M', 't'),
- (0x1D61C, 'M', 'u'),
- (0x1D61D, 'M', 'v'),
- (0x1D61E, 'M', 'w'),
- ]
-
-def _seg_66() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D61F, 'M', 'x'),
- (0x1D620, 'M', 'y'),
- (0x1D621, 'M', 'z'),
- (0x1D622, 'M', 'a'),
- (0x1D623, 'M', 'b'),
- (0x1D624, 'M', 'c'),
- (0x1D625, 'M', 'd'),
- (0x1D626, 'M', 'e'),
- (0x1D627, 'M', 'f'),
- (0x1D628, 'M', 'g'),
- (0x1D629, 'M', 'h'),
- (0x1D62A, 'M', 'i'),
- (0x1D62B, 'M', 'j'),
- (0x1D62C, 'M', 'k'),
- (0x1D62D, 'M', 'l'),
- (0x1D62E, 'M', 'm'),
- (0x1D62F, 'M', 'n'),
- (0x1D630, 'M', 'o'),
- (0x1D631, 'M', 'p'),
- (0x1D632, 'M', 'q'),
- (0x1D633, 'M', 'r'),
- (0x1D634, 'M', 's'),
- (0x1D635, 'M', 't'),
- (0x1D636, 'M', 'u'),
- (0x1D637, 'M', 'v'),
- (0x1D638, 'M', 'w'),
- (0x1D639, 'M', 'x'),
- (0x1D63A, 'M', 'y'),
- (0x1D63B, 'M', 'z'),
- (0x1D63C, 'M', 'a'),
- (0x1D63D, 'M', 'b'),
- (0x1D63E, 'M', 'c'),
- (0x1D63F, 'M', 'd'),
- (0x1D640, 'M', 'e'),
- (0x1D641, 'M', 'f'),
- (0x1D642, 'M', 'g'),
- (0x1D643, 'M', 'h'),
- (0x1D644, 'M', 'i'),
- (0x1D645, 'M', 'j'),
- (0x1D646, 'M', 'k'),
- (0x1D647, 'M', 'l'),
- (0x1D648, 'M', 'm'),
- (0x1D649, 'M', 'n'),
- (0x1D64A, 'M', 'o'),
- (0x1D64B, 'M', 'p'),
- (0x1D64C, 'M', 'q'),
- (0x1D64D, 'M', 'r'),
- (0x1D64E, 'M', 's'),
- (0x1D64F, 'M', 't'),
- (0x1D650, 'M', 'u'),
- (0x1D651, 'M', 'v'),
- (0x1D652, 'M', 'w'),
- (0x1D653, 'M', 'x'),
- (0x1D654, 'M', 'y'),
- (0x1D655, 'M', 'z'),
- (0x1D656, 'M', 'a'),
- (0x1D657, 'M', 'b'),
- (0x1D658, 'M', 'c'),
- (0x1D659, 'M', 'd'),
- (0x1D65A, 'M', 'e'),
- (0x1D65B, 'M', 'f'),
- (0x1D65C, 'M', 'g'),
- (0x1D65D, 'M', 'h'),
- (0x1D65E, 'M', 'i'),
- (0x1D65F, 'M', 'j'),
- (0x1D660, 'M', 'k'),
- (0x1D661, 'M', 'l'),
- (0x1D662, 'M', 'm'),
- (0x1D663, 'M', 'n'),
- (0x1D664, 'M', 'o'),
- (0x1D665, 'M', 'p'),
- (0x1D666, 'M', 'q'),
- (0x1D667, 'M', 'r'),
- (0x1D668, 'M', 's'),
- (0x1D669, 'M', 't'),
- (0x1D66A, 'M', 'u'),
- (0x1D66B, 'M', 'v'),
- (0x1D66C, 'M', 'w'),
- (0x1D66D, 'M', 'x'),
- (0x1D66E, 'M', 'y'),
- (0x1D66F, 'M', 'z'),
- (0x1D670, 'M', 'a'),
- (0x1D671, 'M', 'b'),
- (0x1D672, 'M', 'c'),
- (0x1D673, 'M', 'd'),
- (0x1D674, 'M', 'e'),
- (0x1D675, 'M', 'f'),
- (0x1D676, 'M', 'g'),
- (0x1D677, 'M', 'h'),
- (0x1D678, 'M', 'i'),
- (0x1D679, 'M', 'j'),
- (0x1D67A, 'M', 'k'),
- (0x1D67B, 'M', 'l'),
- (0x1D67C, 'M', 'm'),
- (0x1D67D, 'M', 'n'),
- (0x1D67E, 'M', 'o'),
- (0x1D67F, 'M', 'p'),
- (0x1D680, 'M', 'q'),
- (0x1D681, 'M', 'r'),
- (0x1D682, 'M', 's'),
- ]
-
-def _seg_67() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D683, 'M', 't'),
- (0x1D684, 'M', 'u'),
- (0x1D685, 'M', 'v'),
- (0x1D686, 'M', 'w'),
- (0x1D687, 'M', 'x'),
- (0x1D688, 'M', 'y'),
- (0x1D689, 'M', 'z'),
- (0x1D68A, 'M', 'a'),
- (0x1D68B, 'M', 'b'),
- (0x1D68C, 'M', 'c'),
- (0x1D68D, 'M', 'd'),
- (0x1D68E, 'M', 'e'),
- (0x1D68F, 'M', 'f'),
- (0x1D690, 'M', 'g'),
- (0x1D691, 'M', 'h'),
- (0x1D692, 'M', 'i'),
- (0x1D693, 'M', 'j'),
- (0x1D694, 'M', 'k'),
- (0x1D695, 'M', 'l'),
- (0x1D696, 'M', 'm'),
- (0x1D697, 'M', 'n'),
- (0x1D698, 'M', 'o'),
- (0x1D699, 'M', 'p'),
- (0x1D69A, 'M', 'q'),
- (0x1D69B, 'M', 'r'),
- (0x1D69C, 'M', 's'),
- (0x1D69D, 'M', 't'),
- (0x1D69E, 'M', 'u'),
- (0x1D69F, 'M', 'v'),
- (0x1D6A0, 'M', 'w'),
- (0x1D6A1, 'M', 'x'),
- (0x1D6A2, 'M', 'y'),
- (0x1D6A3, 'M', 'z'),
- (0x1D6A4, 'M', 'ı'),
- (0x1D6A5, 'M', 'ȷ'),
- (0x1D6A6, 'X'),
- (0x1D6A8, 'M', 'α'),
- (0x1D6A9, 'M', 'β'),
- (0x1D6AA, 'M', 'γ'),
- (0x1D6AB, 'M', 'δ'),
- (0x1D6AC, 'M', 'ε'),
- (0x1D6AD, 'M', 'ζ'),
- (0x1D6AE, 'M', 'η'),
- (0x1D6AF, 'M', 'θ'),
- (0x1D6B0, 'M', 'ι'),
- (0x1D6B1, 'M', 'κ'),
- (0x1D6B2, 'M', 'λ'),
- (0x1D6B3, 'M', 'μ'),
- (0x1D6B4, 'M', 'ν'),
- (0x1D6B5, 'M', 'ξ'),
- (0x1D6B6, 'M', 'ο'),
- (0x1D6B7, 'M', 'π'),
- (0x1D6B8, 'M', 'ρ'),
- (0x1D6B9, 'M', 'θ'),
- (0x1D6BA, 'M', 'σ'),
- (0x1D6BB, 'M', 'τ'),
- (0x1D6BC, 'M', 'υ'),
- (0x1D6BD, 'M', 'φ'),
- (0x1D6BE, 'M', 'χ'),
- (0x1D6BF, 'M', 'ψ'),
- (0x1D6C0, 'M', 'ω'),
- (0x1D6C1, 'M', '∇'),
- (0x1D6C2, 'M', 'α'),
- (0x1D6C3, 'M', 'β'),
- (0x1D6C4, 'M', 'γ'),
- (0x1D6C5, 'M', 'δ'),
- (0x1D6C6, 'M', 'ε'),
- (0x1D6C7, 'M', 'ζ'),
- (0x1D6C8, 'M', 'η'),
- (0x1D6C9, 'M', 'θ'),
- (0x1D6CA, 'M', 'ι'),
- (0x1D6CB, 'M', 'κ'),
- (0x1D6CC, 'M', 'λ'),
- (0x1D6CD, 'M', 'μ'),
- (0x1D6CE, 'M', 'ν'),
- (0x1D6CF, 'M', 'ξ'),
- (0x1D6D0, 'M', 'ο'),
- (0x1D6D1, 'M', 'π'),
- (0x1D6D2, 'M', 'ρ'),
- (0x1D6D3, 'M', 'σ'),
- (0x1D6D5, 'M', 'τ'),
- (0x1D6D6, 'M', 'υ'),
- (0x1D6D7, 'M', 'φ'),
- (0x1D6D8, 'M', 'χ'),
- (0x1D6D9, 'M', 'ψ'),
- (0x1D6DA, 'M', 'ω'),
- (0x1D6DB, 'M', '∂'),
- (0x1D6DC, 'M', 'ε'),
- (0x1D6DD, 'M', 'θ'),
- (0x1D6DE, 'M', 'κ'),
- (0x1D6DF, 'M', 'φ'),
- (0x1D6E0, 'M', 'ρ'),
- (0x1D6E1, 'M', 'π'),
- (0x1D6E2, 'M', 'α'),
- (0x1D6E3, 'M', 'β'),
- (0x1D6E4, 'M', 'γ'),
- (0x1D6E5, 'M', 'δ'),
- (0x1D6E6, 'M', 'ε'),
- (0x1D6E7, 'M', 'ζ'),
- (0x1D6E8, 'M', 'η'),
- ]
-
-def _seg_68() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D6E9, 'M', 'θ'),
- (0x1D6EA, 'M', 'ι'),
- (0x1D6EB, 'M', 'κ'),
- (0x1D6EC, 'M', 'λ'),
- (0x1D6ED, 'M', 'μ'),
- (0x1D6EE, 'M', 'ν'),
- (0x1D6EF, 'M', 'ξ'),
- (0x1D6F0, 'M', 'ο'),
- (0x1D6F1, 'M', 'π'),
- (0x1D6F2, 'M', 'ρ'),
- (0x1D6F3, 'M', 'θ'),
- (0x1D6F4, 'M', 'σ'),
- (0x1D6F5, 'M', 'τ'),
- (0x1D6F6, 'M', 'υ'),
- (0x1D6F7, 'M', 'φ'),
- (0x1D6F8, 'M', 'χ'),
- (0x1D6F9, 'M', 'ψ'),
- (0x1D6FA, 'M', 'ω'),
- (0x1D6FB, 'M', '∇'),
- (0x1D6FC, 'M', 'α'),
- (0x1D6FD, 'M', 'β'),
- (0x1D6FE, 'M', 'γ'),
- (0x1D6FF, 'M', 'δ'),
- (0x1D700, 'M', 'ε'),
- (0x1D701, 'M', 'ζ'),
- (0x1D702, 'M', 'η'),
- (0x1D703, 'M', 'θ'),
- (0x1D704, 'M', 'ι'),
- (0x1D705, 'M', 'κ'),
- (0x1D706, 'M', 'λ'),
- (0x1D707, 'M', 'μ'),
- (0x1D708, 'M', 'ν'),
- (0x1D709, 'M', 'ξ'),
- (0x1D70A, 'M', 'ο'),
- (0x1D70B, 'M', 'π'),
- (0x1D70C, 'M', 'ρ'),
- (0x1D70D, 'M', 'σ'),
- (0x1D70F, 'M', 'τ'),
- (0x1D710, 'M', 'υ'),
- (0x1D711, 'M', 'φ'),
- (0x1D712, 'M', 'χ'),
- (0x1D713, 'M', 'ψ'),
- (0x1D714, 'M', 'ω'),
- (0x1D715, 'M', '∂'),
- (0x1D716, 'M', 'ε'),
- (0x1D717, 'M', 'θ'),
- (0x1D718, 'M', 'κ'),
- (0x1D719, 'M', 'φ'),
- (0x1D71A, 'M', 'ρ'),
- (0x1D71B, 'M', 'π'),
- (0x1D71C, 'M', 'α'),
- (0x1D71D, 'M', 'β'),
- (0x1D71E, 'M', 'γ'),
- (0x1D71F, 'M', 'δ'),
- (0x1D720, 'M', 'ε'),
- (0x1D721, 'M', 'ζ'),
- (0x1D722, 'M', 'η'),
- (0x1D723, 'M', 'θ'),
- (0x1D724, 'M', 'ι'),
- (0x1D725, 'M', 'κ'),
- (0x1D726, 'M', 'λ'),
- (0x1D727, 'M', 'μ'),
- (0x1D728, 'M', 'ν'),
- (0x1D729, 'M', 'ξ'),
- (0x1D72A, 'M', 'ο'),
- (0x1D72B, 'M', 'π'),
- (0x1D72C, 'M', 'ρ'),
- (0x1D72D, 'M', 'θ'),
- (0x1D72E, 'M', 'σ'),
- (0x1D72F, 'M', 'τ'),
- (0x1D730, 'M', 'υ'),
- (0x1D731, 'M', 'φ'),
- (0x1D732, 'M', 'χ'),
- (0x1D733, 'M', 'ψ'),
- (0x1D734, 'M', 'ω'),
- (0x1D735, 'M', '∇'),
- (0x1D736, 'M', 'α'),
- (0x1D737, 'M', 'β'),
- (0x1D738, 'M', 'γ'),
- (0x1D739, 'M', 'δ'),
- (0x1D73A, 'M', 'ε'),
- (0x1D73B, 'M', 'ζ'),
- (0x1D73C, 'M', 'η'),
- (0x1D73D, 'M', 'θ'),
- (0x1D73E, 'M', 'ι'),
- (0x1D73F, 'M', 'κ'),
- (0x1D740, 'M', 'λ'),
- (0x1D741, 'M', 'μ'),
- (0x1D742, 'M', 'ν'),
- (0x1D743, 'M', 'ξ'),
- (0x1D744, 'M', 'ο'),
- (0x1D745, 'M', 'π'),
- (0x1D746, 'M', 'ρ'),
- (0x1D747, 'M', 'σ'),
- (0x1D749, 'M', 'τ'),
- (0x1D74A, 'M', 'υ'),
- (0x1D74B, 'M', 'φ'),
- (0x1D74C, 'M', 'χ'),
- (0x1D74D, 'M', 'ψ'),
- (0x1D74E, 'M', 'ω'),
- ]
-
-def _seg_69() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D74F, 'M', '∂'),
- (0x1D750, 'M', 'ε'),
- (0x1D751, 'M', 'θ'),
- (0x1D752, 'M', 'κ'),
- (0x1D753, 'M', 'φ'),
- (0x1D754, 'M', 'ρ'),
- (0x1D755, 'M', 'π'),
- (0x1D756, 'M', 'α'),
- (0x1D757, 'M', 'β'),
- (0x1D758, 'M', 'γ'),
- (0x1D759, 'M', 'δ'),
- (0x1D75A, 'M', 'ε'),
- (0x1D75B, 'M', 'ζ'),
- (0x1D75C, 'M', 'η'),
- (0x1D75D, 'M', 'θ'),
- (0x1D75E, 'M', 'ι'),
- (0x1D75F, 'M', 'κ'),
- (0x1D760, 'M', 'λ'),
- (0x1D761, 'M', 'μ'),
- (0x1D762, 'M', 'ν'),
- (0x1D763, 'M', 'ξ'),
- (0x1D764, 'M', 'ο'),
- (0x1D765, 'M', 'π'),
- (0x1D766, 'M', 'ρ'),
- (0x1D767, 'M', 'θ'),
- (0x1D768, 'M', 'σ'),
- (0x1D769, 'M', 'τ'),
- (0x1D76A, 'M', 'υ'),
- (0x1D76B, 'M', 'φ'),
- (0x1D76C, 'M', 'χ'),
- (0x1D76D, 'M', 'ψ'),
- (0x1D76E, 'M', 'ω'),
- (0x1D76F, 'M', '∇'),
- (0x1D770, 'M', 'α'),
- (0x1D771, 'M', 'β'),
- (0x1D772, 'M', 'γ'),
- (0x1D773, 'M', 'δ'),
- (0x1D774, 'M', 'ε'),
- (0x1D775, 'M', 'ζ'),
- (0x1D776, 'M', 'η'),
- (0x1D777, 'M', 'θ'),
- (0x1D778, 'M', 'ι'),
- (0x1D779, 'M', 'κ'),
- (0x1D77A, 'M', 'λ'),
- (0x1D77B, 'M', 'μ'),
- (0x1D77C, 'M', 'ν'),
- (0x1D77D, 'M', 'ξ'),
- (0x1D77E, 'M', 'ο'),
- (0x1D77F, 'M', 'π'),
- (0x1D780, 'M', 'ρ'),
- (0x1D781, 'M', 'σ'),
- (0x1D783, 'M', 'τ'),
- (0x1D784, 'M', 'υ'),
- (0x1D785, 'M', 'φ'),
- (0x1D786, 'M', 'χ'),
- (0x1D787, 'M', 'ψ'),
- (0x1D788, 'M', 'ω'),
- (0x1D789, 'M', '∂'),
- (0x1D78A, 'M', 'ε'),
- (0x1D78B, 'M', 'θ'),
- (0x1D78C, 'M', 'κ'),
- (0x1D78D, 'M', 'φ'),
- (0x1D78E, 'M', 'ρ'),
- (0x1D78F, 'M', 'π'),
- (0x1D790, 'M', 'α'),
- (0x1D791, 'M', 'β'),
- (0x1D792, 'M', 'γ'),
- (0x1D793, 'M', 'δ'),
- (0x1D794, 'M', 'ε'),
- (0x1D795, 'M', 'ζ'),
- (0x1D796, 'M', 'η'),
- (0x1D797, 'M', 'θ'),
- (0x1D798, 'M', 'ι'),
- (0x1D799, 'M', 'κ'),
- (0x1D79A, 'M', 'λ'),
- (0x1D79B, 'M', 'μ'),
- (0x1D79C, 'M', 'ν'),
- (0x1D79D, 'M', 'ξ'),
- (0x1D79E, 'M', 'ο'),
- (0x1D79F, 'M', 'π'),
- (0x1D7A0, 'M', 'ρ'),
- (0x1D7A1, 'M', 'θ'),
- (0x1D7A2, 'M', 'σ'),
- (0x1D7A3, 'M', 'τ'),
- (0x1D7A4, 'M', 'υ'),
- (0x1D7A5, 'M', 'φ'),
- (0x1D7A6, 'M', 'χ'),
- (0x1D7A7, 'M', 'ψ'),
- (0x1D7A8, 'M', 'ω'),
- (0x1D7A9, 'M', '∇'),
- (0x1D7AA, 'M', 'α'),
- (0x1D7AB, 'M', 'β'),
- (0x1D7AC, 'M', 'γ'),
- (0x1D7AD, 'M', 'δ'),
- (0x1D7AE, 'M', 'ε'),
- (0x1D7AF, 'M', 'ζ'),
- (0x1D7B0, 'M', 'η'),
- (0x1D7B1, 'M', 'θ'),
- (0x1D7B2, 'M', 'ι'),
- (0x1D7B3, 'M', 'κ'),
- ]
-
-def _seg_70() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1D7B4, 'M', 'λ'),
- (0x1D7B5, 'M', 'μ'),
- (0x1D7B6, 'M', 'ν'),
- (0x1D7B7, 'M', 'ξ'),
- (0x1D7B8, 'M', 'ο'),
- (0x1D7B9, 'M', 'π'),
- (0x1D7BA, 'M', 'ρ'),
- (0x1D7BB, 'M', 'σ'),
- (0x1D7BD, 'M', 'τ'),
- (0x1D7BE, 'M', 'υ'),
- (0x1D7BF, 'M', 'φ'),
- (0x1D7C0, 'M', 'χ'),
- (0x1D7C1, 'M', 'ψ'),
- (0x1D7C2, 'M', 'ω'),
- (0x1D7C3, 'M', '∂'),
- (0x1D7C4, 'M', 'ε'),
- (0x1D7C5, 'M', 'θ'),
- (0x1D7C6, 'M', 'κ'),
- (0x1D7C7, 'M', 'φ'),
- (0x1D7C8, 'M', 'ρ'),
- (0x1D7C9, 'M', 'π'),
- (0x1D7CA, 'M', 'ϝ'),
- (0x1D7CC, 'X'),
- (0x1D7CE, 'M', '0'),
- (0x1D7CF, 'M', '1'),
- (0x1D7D0, 'M', '2'),
- (0x1D7D1, 'M', '3'),
- (0x1D7D2, 'M', '4'),
- (0x1D7D3, 'M', '5'),
- (0x1D7D4, 'M', '6'),
- (0x1D7D5, 'M', '7'),
- (0x1D7D6, 'M', '8'),
- (0x1D7D7, 'M', '9'),
- (0x1D7D8, 'M', '0'),
- (0x1D7D9, 'M', '1'),
- (0x1D7DA, 'M', '2'),
- (0x1D7DB, 'M', '3'),
- (0x1D7DC, 'M', '4'),
- (0x1D7DD, 'M', '5'),
- (0x1D7DE, 'M', '6'),
- (0x1D7DF, 'M', '7'),
- (0x1D7E0, 'M', '8'),
- (0x1D7E1, 'M', '9'),
- (0x1D7E2, 'M', '0'),
- (0x1D7E3, 'M', '1'),
- (0x1D7E4, 'M', '2'),
- (0x1D7E5, 'M', '3'),
- (0x1D7E6, 'M', '4'),
- (0x1D7E7, 'M', '5'),
- (0x1D7E8, 'M', '6'),
- (0x1D7E9, 'M', '7'),
- (0x1D7EA, 'M', '8'),
- (0x1D7EB, 'M', '9'),
- (0x1D7EC, 'M', '0'),
- (0x1D7ED, 'M', '1'),
- (0x1D7EE, 'M', '2'),
- (0x1D7EF, 'M', '3'),
- (0x1D7F0, 'M', '4'),
- (0x1D7F1, 'M', '5'),
- (0x1D7F2, 'M', '6'),
- (0x1D7F3, 'M', '7'),
- (0x1D7F4, 'M', '8'),
- (0x1D7F5, 'M', '9'),
- (0x1D7F6, 'M', '0'),
- (0x1D7F7, 'M', '1'),
- (0x1D7F8, 'M', '2'),
- (0x1D7F9, 'M', '3'),
- (0x1D7FA, 'M', '4'),
- (0x1D7FB, 'M', '5'),
- (0x1D7FC, 'M', '6'),
- (0x1D7FD, 'M', '7'),
- (0x1D7FE, 'M', '8'),
- (0x1D7FF, 'M', '9'),
- (0x1D800, 'V'),
- (0x1DA8C, 'X'),
- (0x1DA9B, 'V'),
- (0x1DAA0, 'X'),
- (0x1DAA1, 'V'),
- (0x1DAB0, 'X'),
- (0x1DF00, 'V'),
- (0x1DF1F, 'X'),
- (0x1DF25, 'V'),
- (0x1DF2B, 'X'),
- (0x1E000, 'V'),
- (0x1E007, 'X'),
- (0x1E008, 'V'),
- (0x1E019, 'X'),
- (0x1E01B, 'V'),
- (0x1E022, 'X'),
- (0x1E023, 'V'),
- (0x1E025, 'X'),
- (0x1E026, 'V'),
- (0x1E02B, 'X'),
- (0x1E030, 'M', 'а'),
- (0x1E031, 'M', 'б'),
- (0x1E032, 'M', 'в'),
- (0x1E033, 'M', 'г'),
- (0x1E034, 'M', 'д'),
- (0x1E035, 'M', 'е'),
- (0x1E036, 'M', 'ж'),
- ]
-
-def _seg_71() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1E037, 'M', 'з'),
- (0x1E038, 'M', 'и'),
- (0x1E039, 'M', 'к'),
- (0x1E03A, 'M', 'л'),
- (0x1E03B, 'M', 'м'),
- (0x1E03C, 'M', 'о'),
- (0x1E03D, 'M', 'п'),
- (0x1E03E, 'M', 'р'),
- (0x1E03F, 'M', 'с'),
- (0x1E040, 'M', 'т'),
- (0x1E041, 'M', 'у'),
- (0x1E042, 'M', 'ф'),
- (0x1E043, 'M', 'х'),
- (0x1E044, 'M', 'ц'),
- (0x1E045, 'M', 'ч'),
- (0x1E046, 'M', 'ш'),
- (0x1E047, 'M', 'ы'),
- (0x1E048, 'M', 'э'),
- (0x1E049, 'M', 'ю'),
- (0x1E04A, 'M', 'ꚉ'),
- (0x1E04B, 'M', 'ә'),
- (0x1E04C, 'M', 'і'),
- (0x1E04D, 'M', 'ј'),
- (0x1E04E, 'M', 'ө'),
- (0x1E04F, 'M', 'ү'),
- (0x1E050, 'M', 'ӏ'),
- (0x1E051, 'M', 'а'),
- (0x1E052, 'M', 'б'),
- (0x1E053, 'M', 'в'),
- (0x1E054, 'M', 'г'),
- (0x1E055, 'M', 'д'),
- (0x1E056, 'M', 'е'),
- (0x1E057, 'M', 'ж'),
- (0x1E058, 'M', 'з'),
- (0x1E059, 'M', 'и'),
- (0x1E05A, 'M', 'к'),
- (0x1E05B, 'M', 'л'),
- (0x1E05C, 'M', 'о'),
- (0x1E05D, 'M', 'п'),
- (0x1E05E, 'M', 'с'),
- (0x1E05F, 'M', 'у'),
- (0x1E060, 'M', 'ф'),
- (0x1E061, 'M', 'х'),
- (0x1E062, 'M', 'ц'),
- (0x1E063, 'M', 'ч'),
- (0x1E064, 'M', 'ш'),
- (0x1E065, 'M', 'ъ'),
- (0x1E066, 'M', 'ы'),
- (0x1E067, 'M', 'ґ'),
- (0x1E068, 'M', 'і'),
- (0x1E069, 'M', 'ѕ'),
- (0x1E06A, 'M', 'џ'),
- (0x1E06B, 'M', 'ҫ'),
- (0x1E06C, 'M', 'ꙑ'),
- (0x1E06D, 'M', 'ұ'),
- (0x1E06E, 'X'),
- (0x1E08F, 'V'),
- (0x1E090, 'X'),
- (0x1E100, 'V'),
- (0x1E12D, 'X'),
- (0x1E130, 'V'),
- (0x1E13E, 'X'),
- (0x1E140, 'V'),
- (0x1E14A, 'X'),
- (0x1E14E, 'V'),
- (0x1E150, 'X'),
- (0x1E290, 'V'),
- (0x1E2AF, 'X'),
- (0x1E2C0, 'V'),
- (0x1E2FA, 'X'),
- (0x1E2FF, 'V'),
- (0x1E300, 'X'),
- (0x1E4D0, 'V'),
- (0x1E4FA, 'X'),
- (0x1E7E0, 'V'),
- (0x1E7E7, 'X'),
- (0x1E7E8, 'V'),
- (0x1E7EC, 'X'),
- (0x1E7ED, 'V'),
- (0x1E7EF, 'X'),
- (0x1E7F0, 'V'),
- (0x1E7FF, 'X'),
- (0x1E800, 'V'),
- (0x1E8C5, 'X'),
- (0x1E8C7, 'V'),
- (0x1E8D7, 'X'),
- (0x1E900, 'M', '𞤢'),
- (0x1E901, 'M', '𞤣'),
- (0x1E902, 'M', '𞤤'),
- (0x1E903, 'M', '𞤥'),
- (0x1E904, 'M', '𞤦'),
- (0x1E905, 'M', '𞤧'),
- (0x1E906, 'M', '𞤨'),
- (0x1E907, 'M', '𞤩'),
- (0x1E908, 'M', '𞤪'),
- (0x1E909, 'M', '𞤫'),
- (0x1E90A, 'M', '𞤬'),
- (0x1E90B, 'M', '𞤭'),
- (0x1E90C, 'M', '𞤮'),
- (0x1E90D, 'M', '𞤯'),
- ]
-
-def _seg_72() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1E90E, 'M', '𞤰'),
- (0x1E90F, 'M', '𞤱'),
- (0x1E910, 'M', '𞤲'),
- (0x1E911, 'M', '𞤳'),
- (0x1E912, 'M', '𞤴'),
- (0x1E913, 'M', '𞤵'),
- (0x1E914, 'M', '𞤶'),
- (0x1E915, 'M', '𞤷'),
- (0x1E916, 'M', '𞤸'),
- (0x1E917, 'M', '𞤹'),
- (0x1E918, 'M', '𞤺'),
- (0x1E919, 'M', '𞤻'),
- (0x1E91A, 'M', '𞤼'),
- (0x1E91B, 'M', '𞤽'),
- (0x1E91C, 'M', '𞤾'),
- (0x1E91D, 'M', '𞤿'),
- (0x1E91E, 'M', '𞥀'),
- (0x1E91F, 'M', '𞥁'),
- (0x1E920, 'M', '𞥂'),
- (0x1E921, 'M', '𞥃'),
- (0x1E922, 'V'),
- (0x1E94C, 'X'),
- (0x1E950, 'V'),
- (0x1E95A, 'X'),
- (0x1E95E, 'V'),
- (0x1E960, 'X'),
- (0x1EC71, 'V'),
- (0x1ECB5, 'X'),
- (0x1ED01, 'V'),
- (0x1ED3E, 'X'),
- (0x1EE00, 'M', 'ا'),
- (0x1EE01, 'M', 'ب'),
- (0x1EE02, 'M', 'ج'),
- (0x1EE03, 'M', 'د'),
- (0x1EE04, 'X'),
- (0x1EE05, 'M', 'و'),
- (0x1EE06, 'M', 'ز'),
- (0x1EE07, 'M', 'ح'),
- (0x1EE08, 'M', 'ط'),
- (0x1EE09, 'M', 'ي'),
- (0x1EE0A, 'M', 'ك'),
- (0x1EE0B, 'M', 'ل'),
- (0x1EE0C, 'M', 'م'),
- (0x1EE0D, 'M', 'ن'),
- (0x1EE0E, 'M', 'س'),
- (0x1EE0F, 'M', 'ع'),
- (0x1EE10, 'M', 'ف'),
- (0x1EE11, 'M', 'ص'),
- (0x1EE12, 'M', 'ق'),
- (0x1EE13, 'M', 'ر'),
- (0x1EE14, 'M', 'ش'),
- (0x1EE15, 'M', 'ت'),
- (0x1EE16, 'M', 'ث'),
- (0x1EE17, 'M', 'خ'),
- (0x1EE18, 'M', 'ذ'),
- (0x1EE19, 'M', 'ض'),
- (0x1EE1A, 'M', 'ظ'),
- (0x1EE1B, 'M', 'غ'),
- (0x1EE1C, 'M', 'ٮ'),
- (0x1EE1D, 'M', 'ں'),
- (0x1EE1E, 'M', 'ڡ'),
- (0x1EE1F, 'M', 'ٯ'),
- (0x1EE20, 'X'),
- (0x1EE21, 'M', 'ب'),
- (0x1EE22, 'M', 'ج'),
- (0x1EE23, 'X'),
- (0x1EE24, 'M', 'ه'),
- (0x1EE25, 'X'),
- (0x1EE27, 'M', 'ح'),
- (0x1EE28, 'X'),
- (0x1EE29, 'M', 'ي'),
- (0x1EE2A, 'M', 'ك'),
- (0x1EE2B, 'M', 'ل'),
- (0x1EE2C, 'M', 'م'),
- (0x1EE2D, 'M', 'ن'),
- (0x1EE2E, 'M', 'س'),
- (0x1EE2F, 'M', 'ع'),
- (0x1EE30, 'M', 'ف'),
- (0x1EE31, 'M', 'ص'),
- (0x1EE32, 'M', 'ق'),
- (0x1EE33, 'X'),
- (0x1EE34, 'M', 'ش'),
- (0x1EE35, 'M', 'ت'),
- (0x1EE36, 'M', 'ث'),
- (0x1EE37, 'M', 'خ'),
- (0x1EE38, 'X'),
- (0x1EE39, 'M', 'ض'),
- (0x1EE3A, 'X'),
- (0x1EE3B, 'M', 'غ'),
- (0x1EE3C, 'X'),
- (0x1EE42, 'M', 'ج'),
- (0x1EE43, 'X'),
- (0x1EE47, 'M', 'ح'),
- (0x1EE48, 'X'),
- (0x1EE49, 'M', 'ي'),
- (0x1EE4A, 'X'),
- (0x1EE4B, 'M', 'ل'),
- (0x1EE4C, 'X'),
- (0x1EE4D, 'M', 'ن'),
- (0x1EE4E, 'M', 'س'),
- ]
-
-def _seg_73() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1EE4F, 'M', 'ع'),
- (0x1EE50, 'X'),
- (0x1EE51, 'M', 'ص'),
- (0x1EE52, 'M', 'ق'),
- (0x1EE53, 'X'),
- (0x1EE54, 'M', 'ش'),
- (0x1EE55, 'X'),
- (0x1EE57, 'M', 'خ'),
- (0x1EE58, 'X'),
- (0x1EE59, 'M', 'ض'),
- (0x1EE5A, 'X'),
- (0x1EE5B, 'M', 'غ'),
- (0x1EE5C, 'X'),
- (0x1EE5D, 'M', 'ں'),
- (0x1EE5E, 'X'),
- (0x1EE5F, 'M', 'ٯ'),
- (0x1EE60, 'X'),
- (0x1EE61, 'M', 'ب'),
- (0x1EE62, 'M', 'ج'),
- (0x1EE63, 'X'),
- (0x1EE64, 'M', 'ه'),
- (0x1EE65, 'X'),
- (0x1EE67, 'M', 'ح'),
- (0x1EE68, 'M', 'ط'),
- (0x1EE69, 'M', 'ي'),
- (0x1EE6A, 'M', 'ك'),
- (0x1EE6B, 'X'),
- (0x1EE6C, 'M', 'م'),
- (0x1EE6D, 'M', 'ن'),
- (0x1EE6E, 'M', 'س'),
- (0x1EE6F, 'M', 'ع'),
- (0x1EE70, 'M', 'ف'),
- (0x1EE71, 'M', 'ص'),
- (0x1EE72, 'M', 'ق'),
- (0x1EE73, 'X'),
- (0x1EE74, 'M', 'ش'),
- (0x1EE75, 'M', 'ت'),
- (0x1EE76, 'M', 'ث'),
- (0x1EE77, 'M', 'خ'),
- (0x1EE78, 'X'),
- (0x1EE79, 'M', 'ض'),
- (0x1EE7A, 'M', 'ظ'),
- (0x1EE7B, 'M', 'غ'),
- (0x1EE7C, 'M', 'ٮ'),
- (0x1EE7D, 'X'),
- (0x1EE7E, 'M', 'ڡ'),
- (0x1EE7F, 'X'),
- (0x1EE80, 'M', 'ا'),
- (0x1EE81, 'M', 'ب'),
- (0x1EE82, 'M', 'ج'),
- (0x1EE83, 'M', 'د'),
- (0x1EE84, 'M', 'ه'),
- (0x1EE85, 'M', 'و'),
- (0x1EE86, 'M', 'ز'),
- (0x1EE87, 'M', 'ح'),
- (0x1EE88, 'M', 'ط'),
- (0x1EE89, 'M', 'ي'),
- (0x1EE8A, 'X'),
- (0x1EE8B, 'M', 'ل'),
- (0x1EE8C, 'M', 'م'),
- (0x1EE8D, 'M', 'ن'),
- (0x1EE8E, 'M', 'س'),
- (0x1EE8F, 'M', 'ع'),
- (0x1EE90, 'M', 'ف'),
- (0x1EE91, 'M', 'ص'),
- (0x1EE92, 'M', 'ق'),
- (0x1EE93, 'M', 'ر'),
- (0x1EE94, 'M', 'ش'),
- (0x1EE95, 'M', 'ت'),
- (0x1EE96, 'M', 'ث'),
- (0x1EE97, 'M', 'خ'),
- (0x1EE98, 'M', 'ذ'),
- (0x1EE99, 'M', 'ض'),
- (0x1EE9A, 'M', 'ظ'),
- (0x1EE9B, 'M', 'غ'),
- (0x1EE9C, 'X'),
- (0x1EEA1, 'M', 'ب'),
- (0x1EEA2, 'M', 'ج'),
- (0x1EEA3, 'M', 'د'),
- (0x1EEA4, 'X'),
- (0x1EEA5, 'M', 'و'),
- (0x1EEA6, 'M', 'ز'),
- (0x1EEA7, 'M', 'ح'),
- (0x1EEA8, 'M', 'ط'),
- (0x1EEA9, 'M', 'ي'),
- (0x1EEAA, 'X'),
- (0x1EEAB, 'M', 'ل'),
- (0x1EEAC, 'M', 'م'),
- (0x1EEAD, 'M', 'ن'),
- (0x1EEAE, 'M', 'س'),
- (0x1EEAF, 'M', 'ع'),
- (0x1EEB0, 'M', 'ف'),
- (0x1EEB1, 'M', 'ص'),
- (0x1EEB2, 'M', 'ق'),
- (0x1EEB3, 'M', 'ر'),
- (0x1EEB4, 'M', 'ش'),
- (0x1EEB5, 'M', 'ت'),
- (0x1EEB6, 'M', 'ث'),
- (0x1EEB7, 'M', 'خ'),
- (0x1EEB8, 'M', 'ذ'),
- ]
-
-def _seg_74() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1EEB9, 'M', 'ض'),
- (0x1EEBA, 'M', 'ظ'),
- (0x1EEBB, 'M', 'غ'),
- (0x1EEBC, 'X'),
- (0x1EEF0, 'V'),
- (0x1EEF2, 'X'),
- (0x1F000, 'V'),
- (0x1F02C, 'X'),
- (0x1F030, 'V'),
- (0x1F094, 'X'),
- (0x1F0A0, 'V'),
- (0x1F0AF, 'X'),
- (0x1F0B1, 'V'),
- (0x1F0C0, 'X'),
- (0x1F0C1, 'V'),
- (0x1F0D0, 'X'),
- (0x1F0D1, 'V'),
- (0x1F0F6, 'X'),
- (0x1F101, '3', '0,'),
- (0x1F102, '3', '1,'),
- (0x1F103, '3', '2,'),
- (0x1F104, '3', '3,'),
- (0x1F105, '3', '4,'),
- (0x1F106, '3', '5,'),
- (0x1F107, '3', '6,'),
- (0x1F108, '3', '7,'),
- (0x1F109, '3', '8,'),
- (0x1F10A, '3', '9,'),
- (0x1F10B, 'V'),
- (0x1F110, '3', '(a)'),
- (0x1F111, '3', '(b)'),
- (0x1F112, '3', '(c)'),
- (0x1F113, '3', '(d)'),
- (0x1F114, '3', '(e)'),
- (0x1F115, '3', '(f)'),
- (0x1F116, '3', '(g)'),
- (0x1F117, '3', '(h)'),
- (0x1F118, '3', '(i)'),
- (0x1F119, '3', '(j)'),
- (0x1F11A, '3', '(k)'),
- (0x1F11B, '3', '(l)'),
- (0x1F11C, '3', '(m)'),
- (0x1F11D, '3', '(n)'),
- (0x1F11E, '3', '(o)'),
- (0x1F11F, '3', '(p)'),
- (0x1F120, '3', '(q)'),
- (0x1F121, '3', '(r)'),
- (0x1F122, '3', '(s)'),
- (0x1F123, '3', '(t)'),
- (0x1F124, '3', '(u)'),
- (0x1F125, '3', '(v)'),
- (0x1F126, '3', '(w)'),
- (0x1F127, '3', '(x)'),
- (0x1F128, '3', '(y)'),
- (0x1F129, '3', '(z)'),
- (0x1F12A, 'M', '〔s〕'),
- (0x1F12B, 'M', 'c'),
- (0x1F12C, 'M', 'r'),
- (0x1F12D, 'M', 'cd'),
- (0x1F12E, 'M', 'wz'),
- (0x1F12F, 'V'),
- (0x1F130, 'M', 'a'),
- (0x1F131, 'M', 'b'),
- (0x1F132, 'M', 'c'),
- (0x1F133, 'M', 'd'),
- (0x1F134, 'M', 'e'),
- (0x1F135, 'M', 'f'),
- (0x1F136, 'M', 'g'),
- (0x1F137, 'M', 'h'),
- (0x1F138, 'M', 'i'),
- (0x1F139, 'M', 'j'),
- (0x1F13A, 'M', 'k'),
- (0x1F13B, 'M', 'l'),
- (0x1F13C, 'M', 'm'),
- (0x1F13D, 'M', 'n'),
- (0x1F13E, 'M', 'o'),
- (0x1F13F, 'M', 'p'),
- (0x1F140, 'M', 'q'),
- (0x1F141, 'M', 'r'),
- (0x1F142, 'M', 's'),
- (0x1F143, 'M', 't'),
- (0x1F144, 'M', 'u'),
- (0x1F145, 'M', 'v'),
- (0x1F146, 'M', 'w'),
- (0x1F147, 'M', 'x'),
- (0x1F148, 'M', 'y'),
- (0x1F149, 'M', 'z'),
- (0x1F14A, 'M', 'hv'),
- (0x1F14B, 'M', 'mv'),
- (0x1F14C, 'M', 'sd'),
- (0x1F14D, 'M', 'ss'),
- (0x1F14E, 'M', 'ppv'),
- (0x1F14F, 'M', 'wc'),
- (0x1F150, 'V'),
- (0x1F16A, 'M', 'mc'),
- (0x1F16B, 'M', 'md'),
- (0x1F16C, 'M', 'mr'),
- (0x1F16D, 'V'),
- (0x1F190, 'M', 'dj'),
- (0x1F191, 'V'),
- ]
-
-def _seg_75() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1F1AE, 'X'),
- (0x1F1E6, 'V'),
- (0x1F200, 'M', 'ほか'),
- (0x1F201, 'M', 'ココ'),
- (0x1F202, 'M', 'サ'),
- (0x1F203, 'X'),
- (0x1F210, 'M', '手'),
- (0x1F211, 'M', '字'),
- (0x1F212, 'M', '双'),
- (0x1F213, 'M', 'デ'),
- (0x1F214, 'M', '二'),
- (0x1F215, 'M', '多'),
- (0x1F216, 'M', '解'),
- (0x1F217, 'M', '天'),
- (0x1F218, 'M', '交'),
- (0x1F219, 'M', '映'),
- (0x1F21A, 'M', '無'),
- (0x1F21B, 'M', '料'),
- (0x1F21C, 'M', '前'),
- (0x1F21D, 'M', '後'),
- (0x1F21E, 'M', '再'),
- (0x1F21F, 'M', '新'),
- (0x1F220, 'M', '初'),
- (0x1F221, 'M', '終'),
- (0x1F222, 'M', '生'),
- (0x1F223, 'M', '販'),
- (0x1F224, 'M', '声'),
- (0x1F225, 'M', '吹'),
- (0x1F226, 'M', '演'),
- (0x1F227, 'M', '投'),
- (0x1F228, 'M', '捕'),
- (0x1F229, 'M', '一'),
- (0x1F22A, 'M', '三'),
- (0x1F22B, 'M', '遊'),
- (0x1F22C, 'M', '左'),
- (0x1F22D, 'M', '中'),
- (0x1F22E, 'M', '右'),
- (0x1F22F, 'M', '指'),
- (0x1F230, 'M', '走'),
- (0x1F231, 'M', '打'),
- (0x1F232, 'M', '禁'),
- (0x1F233, 'M', '空'),
- (0x1F234, 'M', '合'),
- (0x1F235, 'M', '満'),
- (0x1F236, 'M', '有'),
- (0x1F237, 'M', '月'),
- (0x1F238, 'M', '申'),
- (0x1F239, 'M', '割'),
- (0x1F23A, 'M', '営'),
- (0x1F23B, 'M', '配'),
- (0x1F23C, 'X'),
- (0x1F240, 'M', '〔本〕'),
- (0x1F241, 'M', '〔三〕'),
- (0x1F242, 'M', '〔二〕'),
- (0x1F243, 'M', '〔安〕'),
- (0x1F244, 'M', '〔点〕'),
- (0x1F245, 'M', '〔打〕'),
- (0x1F246, 'M', '〔盗〕'),
- (0x1F247, 'M', '〔勝〕'),
- (0x1F248, 'M', '〔敗〕'),
- (0x1F249, 'X'),
- (0x1F250, 'M', '得'),
- (0x1F251, 'M', '可'),
- (0x1F252, 'X'),
- (0x1F260, 'V'),
- (0x1F266, 'X'),
- (0x1F300, 'V'),
- (0x1F6D8, 'X'),
- (0x1F6DC, 'V'),
- (0x1F6ED, 'X'),
- (0x1F6F0, 'V'),
- (0x1F6FD, 'X'),
- (0x1F700, 'V'),
- (0x1F777, 'X'),
- (0x1F77B, 'V'),
- (0x1F7DA, 'X'),
- (0x1F7E0, 'V'),
- (0x1F7EC, 'X'),
- (0x1F7F0, 'V'),
- (0x1F7F1, 'X'),
- (0x1F800, 'V'),
- (0x1F80C, 'X'),
- (0x1F810, 'V'),
- (0x1F848, 'X'),
- (0x1F850, 'V'),
- (0x1F85A, 'X'),
- (0x1F860, 'V'),
- (0x1F888, 'X'),
- (0x1F890, 'V'),
- (0x1F8AE, 'X'),
- (0x1F8B0, 'V'),
- (0x1F8B2, 'X'),
- (0x1F900, 'V'),
- (0x1FA54, 'X'),
- (0x1FA60, 'V'),
- (0x1FA6E, 'X'),
- (0x1FA70, 'V'),
- (0x1FA7D, 'X'),
- (0x1FA80, 'V'),
- (0x1FA89, 'X'),
- ]
-
-def _seg_76() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x1FA90, 'V'),
- (0x1FABE, 'X'),
- (0x1FABF, 'V'),
- (0x1FAC6, 'X'),
- (0x1FACE, 'V'),
- (0x1FADC, 'X'),
- (0x1FAE0, 'V'),
- (0x1FAE9, 'X'),
- (0x1FAF0, 'V'),
- (0x1FAF9, 'X'),
- (0x1FB00, 'V'),
- (0x1FB93, 'X'),
- (0x1FB94, 'V'),
- (0x1FBCB, 'X'),
- (0x1FBF0, 'M', '0'),
- (0x1FBF1, 'M', '1'),
- (0x1FBF2, 'M', '2'),
- (0x1FBF3, 'M', '3'),
- (0x1FBF4, 'M', '4'),
- (0x1FBF5, 'M', '5'),
- (0x1FBF6, 'M', '6'),
- (0x1FBF7, 'M', '7'),
- (0x1FBF8, 'M', '8'),
- (0x1FBF9, 'M', '9'),
- (0x1FBFA, 'X'),
- (0x20000, 'V'),
- (0x2A6E0, 'X'),
- (0x2A700, 'V'),
- (0x2B73A, 'X'),
- (0x2B740, 'V'),
- (0x2B81E, 'X'),
- (0x2B820, 'V'),
- (0x2CEA2, 'X'),
- (0x2CEB0, 'V'),
- (0x2EBE1, 'X'),
- (0x2EBF0, 'V'),
- (0x2EE5E, 'X'),
- (0x2F800, 'M', '丽'),
- (0x2F801, 'M', '丸'),
- (0x2F802, 'M', '乁'),
- (0x2F803, 'M', '𠄢'),
- (0x2F804, 'M', '你'),
- (0x2F805, 'M', '侮'),
- (0x2F806, 'M', '侻'),
- (0x2F807, 'M', '倂'),
- (0x2F808, 'M', '偺'),
- (0x2F809, 'M', '備'),
- (0x2F80A, 'M', '僧'),
- (0x2F80B, 'M', '像'),
- (0x2F80C, 'M', '㒞'),
- (0x2F80D, 'M', '𠘺'),
- (0x2F80E, 'M', '免'),
- (0x2F80F, 'M', '兔'),
- (0x2F810, 'M', '兤'),
- (0x2F811, 'M', '具'),
- (0x2F812, 'M', '𠔜'),
- (0x2F813, 'M', '㒹'),
- (0x2F814, 'M', '內'),
- (0x2F815, 'M', '再'),
- (0x2F816, 'M', '𠕋'),
- (0x2F817, 'M', '冗'),
- (0x2F818, 'M', '冤'),
- (0x2F819, 'M', '仌'),
- (0x2F81A, 'M', '冬'),
- (0x2F81B, 'M', '况'),
- (0x2F81C, 'M', '𩇟'),
- (0x2F81D, 'M', '凵'),
- (0x2F81E, 'M', '刃'),
- (0x2F81F, 'M', '㓟'),
- (0x2F820, 'M', '刻'),
- (0x2F821, 'M', '剆'),
- (0x2F822, 'M', '割'),
- (0x2F823, 'M', '剷'),
- (0x2F824, 'M', '㔕'),
- (0x2F825, 'M', '勇'),
- (0x2F826, 'M', '勉'),
- (0x2F827, 'M', '勤'),
- (0x2F828, 'M', '勺'),
- (0x2F829, 'M', '包'),
- (0x2F82A, 'M', '匆'),
- (0x2F82B, 'M', '北'),
- (0x2F82C, 'M', '卉'),
- (0x2F82D, 'M', '卑'),
- (0x2F82E, 'M', '博'),
- (0x2F82F, 'M', '即'),
- (0x2F830, 'M', '卽'),
- (0x2F831, 'M', '卿'),
- (0x2F834, 'M', '𠨬'),
- (0x2F835, 'M', '灰'),
- (0x2F836, 'M', '及'),
- (0x2F837, 'M', '叟'),
- (0x2F838, 'M', '𠭣'),
- (0x2F839, 'M', '叫'),
- (0x2F83A, 'M', '叱'),
- (0x2F83B, 'M', '吆'),
- (0x2F83C, 'M', '咞'),
- (0x2F83D, 'M', '吸'),
- (0x2F83E, 'M', '呈'),
- (0x2F83F, 'M', '周'),
- (0x2F840, 'M', '咢'),
- ]
-
-def _seg_77() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F841, 'M', '哶'),
- (0x2F842, 'M', '唐'),
- (0x2F843, 'M', '啓'),
- (0x2F844, 'M', '啣'),
- (0x2F845, 'M', '善'),
- (0x2F847, 'M', '喙'),
- (0x2F848, 'M', '喫'),
- (0x2F849, 'M', '喳'),
- (0x2F84A, 'M', '嗂'),
- (0x2F84B, 'M', '圖'),
- (0x2F84C, 'M', '嘆'),
- (0x2F84D, 'M', '圗'),
- (0x2F84E, 'M', '噑'),
- (0x2F84F, 'M', '噴'),
- (0x2F850, 'M', '切'),
- (0x2F851, 'M', '壮'),
- (0x2F852, 'M', '城'),
- (0x2F853, 'M', '埴'),
- (0x2F854, 'M', '堍'),
- (0x2F855, 'M', '型'),
- (0x2F856, 'M', '堲'),
- (0x2F857, 'M', '報'),
- (0x2F858, 'M', '墬'),
- (0x2F859, 'M', '𡓤'),
- (0x2F85A, 'M', '売'),
- (0x2F85B, 'M', '壷'),
- (0x2F85C, 'M', '夆'),
- (0x2F85D, 'M', '多'),
- (0x2F85E, 'M', '夢'),
- (0x2F85F, 'M', '奢'),
- (0x2F860, 'M', '𡚨'),
- (0x2F861, 'M', '𡛪'),
- (0x2F862, 'M', '姬'),
- (0x2F863, 'M', '娛'),
- (0x2F864, 'M', '娧'),
- (0x2F865, 'M', '姘'),
- (0x2F866, 'M', '婦'),
- (0x2F867, 'M', '㛮'),
- (0x2F868, 'X'),
- (0x2F869, 'M', '嬈'),
- (0x2F86A, 'M', '嬾'),
- (0x2F86C, 'M', '𡧈'),
- (0x2F86D, 'M', '寃'),
- (0x2F86E, 'M', '寘'),
- (0x2F86F, 'M', '寧'),
- (0x2F870, 'M', '寳'),
- (0x2F871, 'M', '𡬘'),
- (0x2F872, 'M', '寿'),
- (0x2F873, 'M', '将'),
- (0x2F874, 'X'),
- (0x2F875, 'M', '尢'),
- (0x2F876, 'M', '㞁'),
- (0x2F877, 'M', '屠'),
- (0x2F878, 'M', '屮'),
- (0x2F879, 'M', '峀'),
- (0x2F87A, 'M', '岍'),
- (0x2F87B, 'M', '𡷤'),
- (0x2F87C, 'M', '嵃'),
- (0x2F87D, 'M', '𡷦'),
- (0x2F87E, 'M', '嵮'),
- (0x2F87F, 'M', '嵫'),
- (0x2F880, 'M', '嵼'),
- (0x2F881, 'M', '巡'),
- (0x2F882, 'M', '巢'),
- (0x2F883, 'M', '㠯'),
- (0x2F884, 'M', '巽'),
- (0x2F885, 'M', '帨'),
- (0x2F886, 'M', '帽'),
- (0x2F887, 'M', '幩'),
- (0x2F888, 'M', '㡢'),
- (0x2F889, 'M', '𢆃'),
- (0x2F88A, 'M', '㡼'),
- (0x2F88B, 'M', '庰'),
- (0x2F88C, 'M', '庳'),
- (0x2F88D, 'M', '庶'),
- (0x2F88E, 'M', '廊'),
- (0x2F88F, 'M', '𪎒'),
- (0x2F890, 'M', '廾'),
- (0x2F891, 'M', '𢌱'),
- (0x2F893, 'M', '舁'),
- (0x2F894, 'M', '弢'),
- (0x2F896, 'M', '㣇'),
- (0x2F897, 'M', '𣊸'),
- (0x2F898, 'M', '𦇚'),
- (0x2F899, 'M', '形'),
- (0x2F89A, 'M', '彫'),
- (0x2F89B, 'M', '㣣'),
- (0x2F89C, 'M', '徚'),
- (0x2F89D, 'M', '忍'),
- (0x2F89E, 'M', '志'),
- (0x2F89F, 'M', '忹'),
- (0x2F8A0, 'M', '悁'),
- (0x2F8A1, 'M', '㤺'),
- (0x2F8A2, 'M', '㤜'),
- (0x2F8A3, 'M', '悔'),
- (0x2F8A4, 'M', '𢛔'),
- (0x2F8A5, 'M', '惇'),
- (0x2F8A6, 'M', '慈'),
- (0x2F8A7, 'M', '慌'),
- (0x2F8A8, 'M', '慎'),
- ]
-
-def _seg_78() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F8A9, 'M', '慌'),
- (0x2F8AA, 'M', '慺'),
- (0x2F8AB, 'M', '憎'),
- (0x2F8AC, 'M', '憲'),
- (0x2F8AD, 'M', '憤'),
- (0x2F8AE, 'M', '憯'),
- (0x2F8AF, 'M', '懞'),
- (0x2F8B0, 'M', '懲'),
- (0x2F8B1, 'M', '懶'),
- (0x2F8B2, 'M', '成'),
- (0x2F8B3, 'M', '戛'),
- (0x2F8B4, 'M', '扝'),
- (0x2F8B5, 'M', '抱'),
- (0x2F8B6, 'M', '拔'),
- (0x2F8B7, 'M', '捐'),
- (0x2F8B8, 'M', '𢬌'),
- (0x2F8B9, 'M', '挽'),
- (0x2F8BA, 'M', '拼'),
- (0x2F8BB, 'M', '捨'),
- (0x2F8BC, 'M', '掃'),
- (0x2F8BD, 'M', '揤'),
- (0x2F8BE, 'M', '𢯱'),
- (0x2F8BF, 'M', '搢'),
- (0x2F8C0, 'M', '揅'),
- (0x2F8C1, 'M', '掩'),
- (0x2F8C2, 'M', '㨮'),
- (0x2F8C3, 'M', '摩'),
- (0x2F8C4, 'M', '摾'),
- (0x2F8C5, 'M', '撝'),
- (0x2F8C6, 'M', '摷'),
- (0x2F8C7, 'M', '㩬'),
- (0x2F8C8, 'M', '敏'),
- (0x2F8C9, 'M', '敬'),
- (0x2F8CA, 'M', '𣀊'),
- (0x2F8CB, 'M', '旣'),
- (0x2F8CC, 'M', '書'),
- (0x2F8CD, 'M', '晉'),
- (0x2F8CE, 'M', '㬙'),
- (0x2F8CF, 'M', '暑'),
- (0x2F8D0, 'M', '㬈'),
- (0x2F8D1, 'M', '㫤'),
- (0x2F8D2, 'M', '冒'),
- (0x2F8D3, 'M', '冕'),
- (0x2F8D4, 'M', '最'),
- (0x2F8D5, 'M', '暜'),
- (0x2F8D6, 'M', '肭'),
- (0x2F8D7, 'M', '䏙'),
- (0x2F8D8, 'M', '朗'),
- (0x2F8D9, 'M', '望'),
- (0x2F8DA, 'M', '朡'),
- (0x2F8DB, 'M', '杞'),
- (0x2F8DC, 'M', '杓'),
- (0x2F8DD, 'M', '𣏃'),
- (0x2F8DE, 'M', '㭉'),
- (0x2F8DF, 'M', '柺'),
- (0x2F8E0, 'M', '枅'),
- (0x2F8E1, 'M', '桒'),
- (0x2F8E2, 'M', '梅'),
- (0x2F8E3, 'M', '𣑭'),
- (0x2F8E4, 'M', '梎'),
- (0x2F8E5, 'M', '栟'),
- (0x2F8E6, 'M', '椔'),
- (0x2F8E7, 'M', '㮝'),
- (0x2F8E8, 'M', '楂'),
- (0x2F8E9, 'M', '榣'),
- (0x2F8EA, 'M', '槪'),
- (0x2F8EB, 'M', '檨'),
- (0x2F8EC, 'M', '𣚣'),
- (0x2F8ED, 'M', '櫛'),
- (0x2F8EE, 'M', '㰘'),
- (0x2F8EF, 'M', '次'),
- (0x2F8F0, 'M', '𣢧'),
- (0x2F8F1, 'M', '歔'),
- (0x2F8F2, 'M', '㱎'),
- (0x2F8F3, 'M', '歲'),
- (0x2F8F4, 'M', '殟'),
- (0x2F8F5, 'M', '殺'),
- (0x2F8F6, 'M', '殻'),
- (0x2F8F7, 'M', '𣪍'),
- (0x2F8F8, 'M', '𡴋'),
- (0x2F8F9, 'M', '𣫺'),
- (0x2F8FA, 'M', '汎'),
- (0x2F8FB, 'M', '𣲼'),
- (0x2F8FC, 'M', '沿'),
- (0x2F8FD, 'M', '泍'),
- (0x2F8FE, 'M', '汧'),
- (0x2F8FF, 'M', '洖'),
- (0x2F900, 'M', '派'),
- (0x2F901, 'M', '海'),
- (0x2F902, 'M', '流'),
- (0x2F903, 'M', '浩'),
- (0x2F904, 'M', '浸'),
- (0x2F905, 'M', '涅'),
- (0x2F906, 'M', '𣴞'),
- (0x2F907, 'M', '洴'),
- (0x2F908, 'M', '港'),
- (0x2F909, 'M', '湮'),
- (0x2F90A, 'M', '㴳'),
- (0x2F90B, 'M', '滋'),
- (0x2F90C, 'M', '滇'),
- ]
-
-def _seg_79() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F90D, 'M', '𣻑'),
- (0x2F90E, 'M', '淹'),
- (0x2F90F, 'M', '潮'),
- (0x2F910, 'M', '𣽞'),
- (0x2F911, 'M', '𣾎'),
- (0x2F912, 'M', '濆'),
- (0x2F913, 'M', '瀹'),
- (0x2F914, 'M', '瀞'),
- (0x2F915, 'M', '瀛'),
- (0x2F916, 'M', '㶖'),
- (0x2F917, 'M', '灊'),
- (0x2F918, 'M', '災'),
- (0x2F919, 'M', '灷'),
- (0x2F91A, 'M', '炭'),
- (0x2F91B, 'M', '𠔥'),
- (0x2F91C, 'M', '煅'),
- (0x2F91D, 'M', '𤉣'),
- (0x2F91E, 'M', '熜'),
- (0x2F91F, 'X'),
- (0x2F920, 'M', '爨'),
- (0x2F921, 'M', '爵'),
- (0x2F922, 'M', '牐'),
- (0x2F923, 'M', '𤘈'),
- (0x2F924, 'M', '犀'),
- (0x2F925, 'M', '犕'),
- (0x2F926, 'M', '𤜵'),
- (0x2F927, 'M', '𤠔'),
- (0x2F928, 'M', '獺'),
- (0x2F929, 'M', '王'),
- (0x2F92A, 'M', '㺬'),
- (0x2F92B, 'M', '玥'),
- (0x2F92C, 'M', '㺸'),
- (0x2F92E, 'M', '瑇'),
- (0x2F92F, 'M', '瑜'),
- (0x2F930, 'M', '瑱'),
- (0x2F931, 'M', '璅'),
- (0x2F932, 'M', '瓊'),
- (0x2F933, 'M', '㼛'),
- (0x2F934, 'M', '甤'),
- (0x2F935, 'M', '𤰶'),
- (0x2F936, 'M', '甾'),
- (0x2F937, 'M', '𤲒'),
- (0x2F938, 'M', '異'),
- (0x2F939, 'M', '𢆟'),
- (0x2F93A, 'M', '瘐'),
- (0x2F93B, 'M', '𤾡'),
- (0x2F93C, 'M', '𤾸'),
- (0x2F93D, 'M', '𥁄'),
- (0x2F93E, 'M', '㿼'),
- (0x2F93F, 'M', '䀈'),
- (0x2F940, 'M', '直'),
- (0x2F941, 'M', '𥃳'),
- (0x2F942, 'M', '𥃲'),
- (0x2F943, 'M', '𥄙'),
- (0x2F944, 'M', '𥄳'),
- (0x2F945, 'M', '眞'),
- (0x2F946, 'M', '真'),
- (0x2F948, 'M', '睊'),
- (0x2F949, 'M', '䀹'),
- (0x2F94A, 'M', '瞋'),
- (0x2F94B, 'M', '䁆'),
- (0x2F94C, 'M', '䂖'),
- (0x2F94D, 'M', '𥐝'),
- (0x2F94E, 'M', '硎'),
- (0x2F94F, 'M', '碌'),
- (0x2F950, 'M', '磌'),
- (0x2F951, 'M', '䃣'),
- (0x2F952, 'M', '𥘦'),
- (0x2F953, 'M', '祖'),
- (0x2F954, 'M', '𥚚'),
- (0x2F955, 'M', '𥛅'),
- (0x2F956, 'M', '福'),
- (0x2F957, 'M', '秫'),
- (0x2F958, 'M', '䄯'),
- (0x2F959, 'M', '穀'),
- (0x2F95A, 'M', '穊'),
- (0x2F95B, 'M', '穏'),
- (0x2F95C, 'M', '𥥼'),
- (0x2F95D, 'M', '𥪧'),
- (0x2F95F, 'X'),
- (0x2F960, 'M', '䈂'),
- (0x2F961, 'M', '𥮫'),
- (0x2F962, 'M', '篆'),
- (0x2F963, 'M', '築'),
- (0x2F964, 'M', '䈧'),
- (0x2F965, 'M', '𥲀'),
- (0x2F966, 'M', '糒'),
- (0x2F967, 'M', '䊠'),
- (0x2F968, 'M', '糨'),
- (0x2F969, 'M', '糣'),
- (0x2F96A, 'M', '紀'),
- (0x2F96B, 'M', '𥾆'),
- (0x2F96C, 'M', '絣'),
- (0x2F96D, 'M', '䌁'),
- (0x2F96E, 'M', '緇'),
- (0x2F96F, 'M', '縂'),
- (0x2F970, 'M', '繅'),
- (0x2F971, 'M', '䌴'),
- (0x2F972, 'M', '𦈨'),
- (0x2F973, 'M', '𦉇'),
- ]
-
-def _seg_80() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F974, 'M', '䍙'),
- (0x2F975, 'M', '𦋙'),
- (0x2F976, 'M', '罺'),
- (0x2F977, 'M', '𦌾'),
- (0x2F978, 'M', '羕'),
- (0x2F979, 'M', '翺'),
- (0x2F97A, 'M', '者'),
- (0x2F97B, 'M', '𦓚'),
- (0x2F97C, 'M', '𦔣'),
- (0x2F97D, 'M', '聠'),
- (0x2F97E, 'M', '𦖨'),
- (0x2F97F, 'M', '聰'),
- (0x2F980, 'M', '𣍟'),
- (0x2F981, 'M', '䏕'),
- (0x2F982, 'M', '育'),
- (0x2F983, 'M', '脃'),
- (0x2F984, 'M', '䐋'),
- (0x2F985, 'M', '脾'),
- (0x2F986, 'M', '媵'),
- (0x2F987, 'M', '𦞧'),
- (0x2F988, 'M', '𦞵'),
- (0x2F989, 'M', '𣎓'),
- (0x2F98A, 'M', '𣎜'),
- (0x2F98B, 'M', '舁'),
- (0x2F98C, 'M', '舄'),
- (0x2F98D, 'M', '辞'),
- (0x2F98E, 'M', '䑫'),
- (0x2F98F, 'M', '芑'),
- (0x2F990, 'M', '芋'),
- (0x2F991, 'M', '芝'),
- (0x2F992, 'M', '劳'),
- (0x2F993, 'M', '花'),
- (0x2F994, 'M', '芳'),
- (0x2F995, 'M', '芽'),
- (0x2F996, 'M', '苦'),
- (0x2F997, 'M', '𦬼'),
- (0x2F998, 'M', '若'),
- (0x2F999, 'M', '茝'),
- (0x2F99A, 'M', '荣'),
- (0x2F99B, 'M', '莭'),
- (0x2F99C, 'M', '茣'),
- (0x2F99D, 'M', '莽'),
- (0x2F99E, 'M', '菧'),
- (0x2F99F, 'M', '著'),
- (0x2F9A0, 'M', '荓'),
- (0x2F9A1, 'M', '菊'),
- (0x2F9A2, 'M', '菌'),
- (0x2F9A3, 'M', '菜'),
- (0x2F9A4, 'M', '𦰶'),
- (0x2F9A5, 'M', '𦵫'),
- (0x2F9A6, 'M', '𦳕'),
- (0x2F9A7, 'M', '䔫'),
- (0x2F9A8, 'M', '蓱'),
- (0x2F9A9, 'M', '蓳'),
- (0x2F9AA, 'M', '蔖'),
- (0x2F9AB, 'M', '𧏊'),
- (0x2F9AC, 'M', '蕤'),
- (0x2F9AD, 'M', '𦼬'),
- (0x2F9AE, 'M', '䕝'),
- (0x2F9AF, 'M', '䕡'),
- (0x2F9B0, 'M', '𦾱'),
- (0x2F9B1, 'M', '𧃒'),
- (0x2F9B2, 'M', '䕫'),
- (0x2F9B3, 'M', '虐'),
- (0x2F9B4, 'M', '虜'),
- (0x2F9B5, 'M', '虧'),
- (0x2F9B6, 'M', '虩'),
- (0x2F9B7, 'M', '蚩'),
- (0x2F9B8, 'M', '蚈'),
- (0x2F9B9, 'M', '蜎'),
- (0x2F9BA, 'M', '蛢'),
- (0x2F9BB, 'M', '蝹'),
- (0x2F9BC, 'M', '蜨'),
- (0x2F9BD, 'M', '蝫'),
- (0x2F9BE, 'M', '螆'),
- (0x2F9BF, 'X'),
- (0x2F9C0, 'M', '蟡'),
- (0x2F9C1, 'M', '蠁'),
- (0x2F9C2, 'M', '䗹'),
- (0x2F9C3, 'M', '衠'),
- (0x2F9C4, 'M', '衣'),
- (0x2F9C5, 'M', '𧙧'),
- (0x2F9C6, 'M', '裗'),
- (0x2F9C7, 'M', '裞'),
- (0x2F9C8, 'M', '䘵'),
- (0x2F9C9, 'M', '裺'),
- (0x2F9CA, 'M', '㒻'),
- (0x2F9CB, 'M', '𧢮'),
- (0x2F9CC, 'M', '𧥦'),
- (0x2F9CD, 'M', '䚾'),
- (0x2F9CE, 'M', '䛇'),
- (0x2F9CF, 'M', '誠'),
- (0x2F9D0, 'M', '諭'),
- (0x2F9D1, 'M', '變'),
- (0x2F9D2, 'M', '豕'),
- (0x2F9D3, 'M', '𧲨'),
- (0x2F9D4, 'M', '貫'),
- (0x2F9D5, 'M', '賁'),
- (0x2F9D6, 'M', '贛'),
- (0x2F9D7, 'M', '起'),
- ]
-
-def _seg_81() -> List[Union[Tuple[int, str], Tuple[int, str, str]]]:
- return [
- (0x2F9D8, 'M', '𧼯'),
- (0x2F9D9, 'M', '𠠄'),
- (0x2F9DA, 'M', '跋'),
- (0x2F9DB, 'M', '趼'),
- (0x2F9DC, 'M', '跰'),
- (0x2F9DD, 'M', '𠣞'),
- (0x2F9DE, 'M', '軔'),
- (0x2F9DF, 'M', '輸'),
- (0x2F9E0, 'M', '𨗒'),
- (0x2F9E1, 'M', '𨗭'),
- (0x2F9E2, 'M', '邔'),
- (0x2F9E3, 'M', '郱'),
- (0x2F9E4, 'M', '鄑'),
- (0x2F9E5, 'M', '𨜮'),
- (0x2F9E6, 'M', '鄛'),
- (0x2F9E7, 'M', '鈸'),
- (0x2F9E8, 'M', '鋗'),
- (0x2F9E9, 'M', '鋘'),
- (0x2F9EA, 'M', '鉼'),
- (0x2F9EB, 'M', '鏹'),
- (0x2F9EC, 'M', '鐕'),
- (0x2F9ED, 'M', '𨯺'),
- (0x2F9EE, 'M', '開'),
- (0x2F9EF, 'M', '䦕'),
- (0x2F9F0, 'M', '閷'),
- (0x2F9F1, 'M', '𨵷'),
- (0x2F9F2, 'M', '䧦'),
- (0x2F9F3, 'M', '雃'),
- (0x2F9F4, 'M', '嶲'),
- (0x2F9F5, 'M', '霣'),
- (0x2F9F6, 'M', '𩅅'),
- (0x2F9F7, 'M', '𩈚'),
- (0x2F9F8, 'M', '䩮'),
- (0x2F9F9, 'M', '䩶'),
- (0x2F9FA, 'M', '韠'),
- (0x2F9FB, 'M', '𩐊'),
- (0x2F9FC, 'M', '䪲'),
- (0x2F9FD, 'M', '𩒖'),
- (0x2F9FE, 'M', '頋'),
- (0x2FA00, 'M', '頩'),
- (0x2FA01, 'M', '𩖶'),
- (0x2FA02, 'M', '飢'),
- (0x2FA03, 'M', '䬳'),
- (0x2FA04, 'M', '餩'),
- (0x2FA05, 'M', '馧'),
- (0x2FA06, 'M', '駂'),
- (0x2FA07, 'M', '駾'),
- (0x2FA08, 'M', '䯎'),
- (0x2FA09, 'M', '𩬰'),
- (0x2FA0A, 'M', '鬒'),
- (0x2FA0B, 'M', '鱀'),
- (0x2FA0C, 'M', '鳽'),
- (0x2FA0D, 'M', '䳎'),
- (0x2FA0E, 'M', '䳭'),
- (0x2FA0F, 'M', '鵧'),
- (0x2FA10, 'M', '𪃎'),
- (0x2FA11, 'M', '䳸'),
- (0x2FA12, 'M', '𪄅'),
- (0x2FA13, 'M', '𪈎'),
- (0x2FA14, 'M', '𪊑'),
- (0x2FA15, 'M', '麻'),
- (0x2FA16, 'M', '䵖'),
- (0x2FA17, 'M', '黹'),
- (0x2FA18, 'M', '黾'),
- (0x2FA19, 'M', '鼅'),
- (0x2FA1A, 'M', '鼏'),
- (0x2FA1B, 'M', '鼖'),
- (0x2FA1C, 'M', '鼻'),
- (0x2FA1D, 'M', '𪘀'),
- (0x2FA1E, 'X'),
- (0x30000, 'V'),
- (0x3134B, 'X'),
- (0x31350, 'V'),
- (0x323B0, 'X'),
- (0xE0100, 'I'),
- (0xE01F0, 'X'),
- ]
-
-uts46data = tuple(
- _seg_0()
- + _seg_1()
- + _seg_2()
- + _seg_3()
- + _seg_4()
- + _seg_5()
- + _seg_6()
- + _seg_7()
- + _seg_8()
- + _seg_9()
- + _seg_10()
- + _seg_11()
- + _seg_12()
- + _seg_13()
- + _seg_14()
- + _seg_15()
- + _seg_16()
- + _seg_17()
- + _seg_18()
- + _seg_19()
- + _seg_20()
- + _seg_21()
- + _seg_22()
- + _seg_23()
- + _seg_24()
- + _seg_25()
- + _seg_26()
- + _seg_27()
- + _seg_28()
- + _seg_29()
- + _seg_30()
- + _seg_31()
- + _seg_32()
- + _seg_33()
- + _seg_34()
- + _seg_35()
- + _seg_36()
- + _seg_37()
- + _seg_38()
- + _seg_39()
- + _seg_40()
- + _seg_41()
- + _seg_42()
- + _seg_43()
- + _seg_44()
- + _seg_45()
- + _seg_46()
- + _seg_47()
- + _seg_48()
- + _seg_49()
- + _seg_50()
- + _seg_51()
- + _seg_52()
- + _seg_53()
- + _seg_54()
- + _seg_55()
- + _seg_56()
- + _seg_57()
- + _seg_58()
- + _seg_59()
- + _seg_60()
- + _seg_61()
- + _seg_62()
- + _seg_63()
- + _seg_64()
- + _seg_65()
- + _seg_66()
- + _seg_67()
- + _seg_68()
- + _seg_69()
- + _seg_70()
- + _seg_71()
- + _seg_72()
- + _seg_73()
- + _seg_74()
- + _seg_75()
- + _seg_76()
- + _seg_77()
- + _seg_78()
- + _seg_79()
- + _seg_80()
- + _seg_81()
-) # type: Tuple[Union[Tuple[int, str], Tuple[int, str, str]], ...]
diff --git a/.venv/lib/python3.12/site-packages/pip-24.2.dist-info/RECORD b/.venv/lib/python3.12/site-packages/pip-24.2.dist-info/RECORD
index 9c347b8..175b46d 100644
--- a/.venv/lib/python3.12/site-packages/pip-24.2.dist-info/RECORD
+++ b/.venv/lib/python3.12/site-packages/pip-24.2.dist-info/RECORD
@@ -1,6 +1,6 @@
-../../../bin/pip,sha256=DYaCRkqNIIndPxYPZQWkWCV23HZan2xAXzE3ZHvRuU4,248
-../../../bin/pip3,sha256=DYaCRkqNIIndPxYPZQWkWCV23HZan2xAXzE3ZHvRuU4,248
-../../../bin/pip3.12,sha256=DYaCRkqNIIndPxYPZQWkWCV23HZan2xAXzE3ZHvRuU4,248
+../../../bin/pip,sha256=5ixYpWWXrfyv7wMFkzp5XlQZvZgi6J31pSyXRqpmvXs,257
+../../../bin/pip3,sha256=5ixYpWWXrfyv7wMFkzp5XlQZvZgi6J31pSyXRqpmvXs,257
+../../../bin/pip3.12,sha256=5ixYpWWXrfyv7wMFkzp5XlQZvZgi6J31pSyXRqpmvXs,257
pip-24.2.dist-info/AUTHORS.txt,sha256=KDa8Pd3GDeKSogF6yFW0l9A9eMneLDOFrcIDqkL8G8s,10868
pip-24.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
pip-24.2.dist-info/LICENSE.txt,sha256=Y0MApmnUmurmWxLGxIySTFGkzfPR_whtw0VtyLyqIQQ,1093
diff --git a/.venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc
index f308b3d..0d473dc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc
index 835c1a9..159b91e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc
index f6bb331..3c80fd9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/__pycache__/__pip-runner__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc
index a913395..b5ff747 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc
index bd9e879..f1cfe07 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/build_env.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc
index 41b7134..dd4e823 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc
index c96676d..04eef4d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/configuration.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc
index f5224a8..71a66cb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/exceptions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc
index aea8abd..be29219 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/main.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc
index 947e5c9..c281e37 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/pyproject.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc
index 2ababaa..d3b83fd 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/self_outdated_check.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc
index 4372221..b5dd519 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/__pycache__/wheel_builder.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc
index 93ddd94..402f9e7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc
index 00caed3..3e21589 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/autocompletion.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc
index b4028cf..6e8b72d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/base_command.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc
index a287ce5..11ed56e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/cmdoptions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc
index a77ac2e..ca48f58 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/command_context.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc
index 5f9e595..2ee4d7a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/index_command.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc
index 2834bd1..4119920 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc
index 5b689e1..7b9d560 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/main_parser.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc
index 89e95ba..1ee91b8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/parser.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc
index 59e6463..eb211a2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/progress_bars.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc
index 4b13293..74adc1c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/req_command.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc
index 4bd69ea..ac57757 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/spinners.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc
index d7f110c..8093a40 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/cli/__pycache__/status_codes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc
index f859177..0b91a8d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc
index 13841b9..03f1b7d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc
index 7c300b3..ebceda9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/check.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc
index 1b97026..5ea58f7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/completion.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc
index 169579d..562a8b4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/configuration.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc
index c9f3bf1..e564011 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/debug.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc
index 5a66cf8..b3ec53d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/download.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc
index 6a059c5..19dc633 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/freeze.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc
index 2fcf158..640aff4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/hash.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc
index 842543f..4b3972c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/help.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc
index 4052f1a..4bfbc06 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/index.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc
index 32d62d5..1f1b220 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/inspect.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc
index e72763f..6e44d13 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/install.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc
index 919b6b6..3c7e097 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/list.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc
index 82c5c27..6fa97c7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/search.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc
index be9d929..2c0c6fc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/show.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc
index 597ecb5..2c720ba 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/uninstall.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc
index 86242e6..f4144d9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/commands/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc
index f0eeb3c..8e06aa4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc
index 5cc0dac..bc83ac2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/base.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc
index 2854595..bff3ba3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/installed.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc
index 69b0466..c3dccbc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/sdist.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc
index 3fcb71a..ef451d8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/distributions/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc
index 850a432..40582d2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc
index 5351b90..42d42cd 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/collector.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc
index a94b9cc..81f707b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/package_finder.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc
index 0588f49..543a4c6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/index/__pycache__/sources.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc
index 885790f..431aa1f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc
index 94cf948..ab6ea65 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_distutils.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc
index 1e4dcca..5f7fbdb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/_sysconfig.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc
index 5d122b7..1168c76 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/locations/__pycache__/base.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc
index e9b57c9..9e140f6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc
index d9d3270..9b065f2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/_json.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc
index 88b51f5..6b53119 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/base.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc
index e24b8d5..38c0dfc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/__pycache__/pkg_resources.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc
index 64d2856..d54f621 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc
index f762250..e83add7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc
index 1b8e0e8..f7017c3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_dists.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc
index 3579f1a..3c8ceb2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/metadata/importlib/__pycache__/_envs.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc
index 733d7a4..ce1ef15 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc
index 8ea2755..08bc8b1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/candidate.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc
index 890af91..af4664e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/direct_url.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc
index 3e747c9..4a29a5f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/format_control.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc
index d8c1365..9d73a20 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/index.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc
index 378eb92..bd4da88 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/installation_report.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc
index 35f15c5..16f654a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/link.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc
index 1b8f894..82b96bb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/scheme.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc
index 88e688b..6e74267 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/search_scope.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc
index dbd65c7..ba381c1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/selection_prefs.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc
index 4b283cc..c695c0f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/target_python.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc
index 0a3a102..6130689 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/models/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc
index 44472d6..1f8fd67 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc
index 8967e7a..b2a2c3e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/auth.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc
index 2c708cd..35c325b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc
index d95e5e0..eab5998 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/download.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc
index 625a2c6..b88a49b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/lazy_wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc
index 6ca1ce5..a3f0250 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/session.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc
index 284d402..1f93965 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/utils.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc
index b5ef0b2..0e61c67 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/network/__pycache__/xmlrpc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc
index 7f145c8..b4c1ee8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc
index ef32b4d..7ebea02 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/check.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc
index ef5dcf5..6e140c2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/freeze.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc
index b6c3b75..bf5674c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/__pycache__/prepare.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc
index f53229c..1386ef1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc
index a5c157b..ede521b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/build_tracker.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc
index d6aa877..46ce489 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc
index aa8496d..c404f94 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_editable.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc
index bb60689..5982c8e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/metadata_legacy.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc
index cffb86f..98e5d24 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc
index f3fff1d..891477d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_editable.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc
index 05a5042..51fc3a8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/build/__pycache__/wheel_legacy.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc
index 0f7024e..faeed49 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc
index 2a4e4cd..fe961be 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/editable_legacy.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc
index be392ce..14c337f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/operations/install/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc
index 09f751c..3996375 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc
index d98a45a..346b79b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/constructors.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc
index 877cb69..73924df 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_file.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc
index 03e5cff..06cd725 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_install.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc
index fedd19f..b82afe3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_set.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc
index a12461b..4233b6b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/req/__pycache__/req_uninstall.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc
index 6c740ec..a9dea2c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc
index 98571b3..02da6a3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/__pycache__/base.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc
index 7952fd3..7650c28 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc
index df561ff..e2c7196 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/legacy/__pycache__/resolver.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc
index 770aad4..d674fd5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc
index 1abd1fe..99b0436 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/base.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc
index 7982ddb..3966f80 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/candidates.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc
index c1318e6..fb8d5cf 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/factory.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc
index 12f61bc..2d495e9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/found_candidates.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc
index 0da0d63..bf62e95 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/provider.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc
index 065d802..6e6ad33 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/reporter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc
index f9bb331..cf54c3c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/requirements.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc
index 597be9b..aae02bb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/resolution/resolvelib/__pycache__/resolver.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc
index f9c1c88..943e631 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc
index dfb47c2..a057a00 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_jaraco_text.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc
index 10c405e..5ced39a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/_log.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc
index 055a189..eafacf1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/appdirs.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc
index 3917691..c1e6b0f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc
index 90a2e21..98a24bf 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/compatibility_tags.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc
index 388d518..ca54f41 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/datetime.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc
index 732757b..5ba18b9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/deprecation.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc
index 329e111..bded298 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/direct_url_helpers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc
index 142db4a..4d33e54 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/egg_link.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc
index c83aa14..53875b6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/encoding.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc
index b92e064..2db4eea 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/entrypoints.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc
index 30040ae..83242d1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filesystem.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc
index 46e77c8..478b36c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/filetypes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc
index 89142e8..9540abf 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/glibc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc
index 93469b0..702bb4c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/hashes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc
index 2abff74..5d82d31 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/logging.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc
index 2b73387..2da4f97 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/misc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc
index 9f394c9..12ca052 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/packaging.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc
index 3e046d2..4e1e7ff 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/retry.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc
index 2d250bb..33c813c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/setuptools_build.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc
index dcc5904..5f95005 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/subprocess.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc
index 7b937bb..1fb9928 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/temp_dir.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc
index d9551a0..0917e98 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/unpacking.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc
index 2f96643..ce577b7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/urls.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc
index 1400904..f8596f6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/virtualenv.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc
index c1e6594..3ec230b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/utils/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc
index d2584fe..f4c533a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc
index 5a8206c..43b5a26 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/bazaar.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc
index a067b89..bfed7c0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/git.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc
index a5fae64..de969d6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/mercurial.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc
index f58d3e4..bb8b347 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/subversion.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc
index f98a8c2..49b3232 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_internal/vcs/__pycache__/versioncontrol.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc
index b2c3a11..6ed5abb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc
index eef223b..6d11108 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/__pycache__/typing_extensions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc
index 3472993..aa0201d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc
index 1c2f68c..92d3ccd 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/_cmd.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc
index b83a5b9..e683c0a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/adapter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc
index 8a177ea..751f189 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc
index 42aeb00..efa2594 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/controller.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc
index 34d0e5b..a07c7b8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/filewrapper.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc
index 2fa59f2..0cc184c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/heuristics.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc
index 37ba744..5025ed6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/serialize.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc
index 102593b..4856f3d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/__pycache__/wrapper.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc
index b387373..13027d5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc
index 2e0dd52..76c142c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/file_cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc
index 4c2ed91..a6c2fc1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/cachecontrol/caches/__pycache__/redis_cache.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc
index 57973b4..780cb58 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc
index 2c7869e..37473d0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc
index 09bb30e..11fff71 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/certifi/__pycache__/core.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc
index 2540882..0233b9d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc
index 3e8bc02..9d712f8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc
index e4e1798..7c7601d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/database.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc
index bd4c0bb..f14ab83 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/index.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc
index 172a374..ec630e5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/locators.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc
index 5a0f4aa..bd868a6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/manifest.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc
index 0f68e47..5a614b4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/markers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc
index 6bf9348..8332342 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/metadata.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc
index ea1e380..0e226e3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/resources.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc
index 9e7e74f..2155a96 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/scripts.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc
index b09ccd2..de7dd73 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/util.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc
index 29ef5cf..55e2b1d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/version.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc
index 36ec4b0..04f18a7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distlib/__pycache__/wheel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc
index 90b3075..8c10b9d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc
index 1d42e96..d956887 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc
index addc537..ac465aa 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/distro/__pycache__/distro.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc
index 3021510..e3e31bb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc
index e9f1d2e..b413852 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/codec.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc
index 335fb37..7763d55 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc
index bce3cee..9e17782 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/core.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc
index 5c97600..3911946 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/idnadata.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc
index 525bd99..8ed3cd4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/intranges.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc
index 4b871f8..83b4730 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/package_data.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc
index d91ca94..e49d26c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/idna/__pycache__/uts46data.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc
index c29d811..93347f7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc
index a2a61f1..2b00f3a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/exceptions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc
index 4c68fc5..05b132d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/ext.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc
index a5a5445..dd59c51 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/msgpack/__pycache__/fallback.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc
index 211b38f..5a3d8b0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc
index 3dcd4f9..48dc056 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_elffile.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc
index c026561..d5dd66b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_manylinux.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc
index 6804a85..46e10bc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_musllinux.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc
index f14f94d..5daac20 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_parser.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc
index edc00ec..fdad94c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_structures.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc
index 758b9d6..2daec81 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/_tokenizer.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc
index b24cdfa..8245fb0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/markers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc
index 3e2097f..8f3b8b4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/metadata.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc
index 5c344ae..83588ff 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/requirements.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc
index f893478..04dbe93 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/specifiers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc
index 9578972..9d10644 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/tags.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc
index 7a73827..eb9cdc6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/utils.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc
index 4a91cf8..ae7b195 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/packaging/__pycache__/version.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc
index a2c0f42..2b5de8a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pkg_resources/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc
index 856b41b..c7c36d9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc
index 8e4fd50..b332769 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc
index 16a485b..c1aede0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/android.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc
index a1ab5b1..cd0039f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/api.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc
index d1805fb..4c025a8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/macos.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc
index 40c4adf..a24a192 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/unix.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc
index 98b12e5..cb58215 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/version.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc
index 6bf138d..bdd7f38 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/platformdirs/__pycache__/windows.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc
index 0314f42..252f991 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc
index d0600e5..44d7750 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc
index 934669a..a200c95 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/cmdline.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc
index 2922326..b4974d8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/console.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc
index 89c945f..0367fbe 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/filter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc
index 88b9b6b..e2b801e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/formatter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc
index 26004eb..3ff047b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/lexer.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc
index 4af2e94..fe6dad1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/modeline.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc
index 45aaabc..83cbe84 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/plugin.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc
index f1716a9..1ecbf1a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/regexopt.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc
index fd26629..dc34de2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/scanner.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc
index 680b5a4..6a9b34f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/sphinxext.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc
index 32fd416..666832a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/style.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc
index 7a4fdf2..b732947 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/token.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc
index 1b6d8ff..86c6c58 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/unistring.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc
index 4c65f8e..b319330 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/__pycache__/util.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc
index 7786f89..eb72f1c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/filters/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc
index 0e0fc14..dc49c32 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc
index 8cb1247..6eda065 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/_mapping.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc
index 45fb4f7..ad01683 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/bbcode.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc
index 786168c..272f484 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/groff.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc
index 82f3bfa..732538e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/html.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc
index de0d735..8644cda 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/img.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc
index f8b2372..ac31c66 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/irc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc
index e5ff778..beb2143 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/latex.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc
index 92c6fdc..ecdd9d5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/other.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc
index d9e94fa..b4caa26 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/pangomarkup.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc
index 497e47a..8e7e125 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/rtf.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc
index bd6151c..0c67b8f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/svg.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc
index 755c320..0bb4b3a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc
index 585ed60..d9099c8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/formatters/__pycache__/terminal256.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc
index 04f8388..a624dc0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc
index 18b567a..7b9fb2d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/_mapping.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc
index a0b460a..0329d81 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/lexers/__pycache__/python.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc
index f21d0fb..c1c1afb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc
index e393690..e148a7e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pygments/styles/__pycache__/_mapping.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc
index 2a937ec..7712c3c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc
index f00b85f..24f3ebc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc
index eda3281..752fe04 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/__pycache__/_impl.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc
index 3516ec8..f36f841 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc
index f1dd25c..9d266c0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/pyproject_hooks/_in_process/__pycache__/_in_process.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc
index dce9c8f..6642429 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc
index 1589a22..98b6a12 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/__version__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc
index 8a715e5..97d00c4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/_internal_utils.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc
index f3c9263..3797f96 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/adapters.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc
index 3d3f385..0efe557 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/api.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc
index 427c6e1..57af0c1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/auth.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc
index 5445754..3fbd979 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/certs.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc
index c878112..c05481c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/compat.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc
index 023c5e5..df8365a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/cookies.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc
index 203b81b..e9462dd 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/exceptions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc
index b2f5654..eaf3804 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/help.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc
index 03d8c1a..cac8a48 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/hooks.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc
index 9588355..3888c8e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/models.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc
index 0407c65..929d114 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/packages.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc
index ae55111..e6537c8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/sessions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc
index 323df71..db957a4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/status_codes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc
index 5c78fe9..c516fff 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/structures.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc
index f530436..5956fe5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/requests/__pycache__/utils.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc
index 2a21950..b8e17c6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc
index 3961476..6aebccc 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/providers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc
index 043510a..7fb84d4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/reporters.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc
index 42aec84..1ce7555 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/resolvers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc
index 8f44c2a..3a50900 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/__pycache__/structs.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc
index 34c13f7..82af142 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc
index cb187c8..94ff663 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/resolvelib/compat/__pycache__/collections_abc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc
index d5f864a..cfb2556 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc
index af30ba7..edb3bd9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/__main__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc
index 8cafce3..a2849f4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_cell_widths.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc
index 1cb35f4..e26dac6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_codes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc
index 3a7a0a0..4f09c4d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_emoji_replace.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc
index cf0ac6a..a4c7c8d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_export_format.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc
index 074dc92..114ea6f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_extension.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc
index e430d89..934db17 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_fileno.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc
index 922676e..90a8dfa 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_inspect.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc
index 1c931af..ad8b843 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_log_render.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc
index 1dad020..24e9707 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_loop.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc
index bec9049..500c754 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_null_file.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc
index 5e64165..18aabe2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_palettes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc
index 2247dca..248f6a6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_pick.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc
index 7961b11..fb01d20 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_ratio.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc
index 908a355..0ea6e34 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_spinners.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc
index 01bf902..b694075 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_stack.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc
index bcf54a5..a6e72f8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_timer.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc
index 3c8879b..1b099ae 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_win32_console.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc
index aa9c49b..bca0dab 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc
index d23e59c..bf23477 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_windows_renderer.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc
index d8dbeb4..4a558bf 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/_wrap.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc
index 4d2747e..e306936 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/abc.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc
index c8727f1..736bec9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/align.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc
index 0968200..ffc2be4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/ansi.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc
index cc91c13..f1e1698 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/bar.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc
index f620044..44533e3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/box.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc
index eae0f84..c4226bf 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/cells.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc
index 86e53ab..4760c70 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc
index d00605b..9e1e4b5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/color_triplet.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc
index 70174c2..96445b5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/columns.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc
index 0c47975..10f4ba7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/console.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc
index 34f7be3..650ca35 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/constrain.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc
index 7aed17b..1ef750f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/containers.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc
index 010290f..546b8d0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/control.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc
index d473bcc..38e61b1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/default_styles.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc
index b6b3750..7e3411b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/diagnose.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc
index 25fa6f9..59aab5f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/emoji.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc
index 211f647..f8aa3b9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/errors.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc
index 75e682b..2178113 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/file_proxy.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc
index 4669ce3..771df1e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/filesize.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc
index f0a327e..01e9f14 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/highlighter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc
index b07e1ba..1c5ba5b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/json.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc
index cd44a08..0cd7a6a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/jupyter.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc
index 233a6d0..f013e1d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/layout.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc
index 00cd4cf..f08d73f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc
index 0ffaac7..80c84ff 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/live_render.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc
index 35eb4d2..068d3ca 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/logging.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc
index 852c240..18ac988 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/markup.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc
index 8a8f100..0d5e3d1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/measure.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc
index f142fbe..70bb5e8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/padding.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc
index 2338b1f..34194a2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pager.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc
index 63deabc..0a56f9b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/palette.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc
index 7bdbcbf..12288a0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/panel.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc
index 74f3f60..430695a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/pretty.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc
index c545acd..f315d59 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc
index 937923e..ab85184 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/progress_bar.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc
index dab2a38..fd21652 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/prompt.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc
index 2593566..35a9fc0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/protocol.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc
index 3d1d810..91b072f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/region.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc
index cefba5e..caaf38a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/repr.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc
index 91cca17..5af0ad7 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/rule.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc
index ad1d75e..74527ac 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/scope.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc
index 7d6502d..28caed6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/screen.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc
index a9e5b6f..2da953e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/segment.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc
index e8f93d9..4a68858 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/spinner.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc
index c9a5fba..05d3d44 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/status.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc
index ee34a8d..3cba632 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/style.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc
index e50f992..70b41c4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/styled.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc
index 80673c0..6d7acaa 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/syntax.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc
index 5fe3de4..5cd787f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/table.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc
index f6f3e4e..b88b386 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/terminal_theme.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc
index 6c48dc5..3a23a49 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/text.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc
index 5d9b8c2..29a146c 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/theme.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc
index 1a2d84c..d148db4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/themes.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc
index c8cc9ab..fa03de8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/traceback.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc
index 0ab9799..7d1020d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/rich/__pycache__/tree.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc
index fe0f749..96df0db 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc
index 63b08f9..438ba27 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_parser.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc
index cebe067..d32c0d2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_re.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc
index 85fd090..de134ee 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/tomli/__pycache__/_types.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc
index 0b6415a..4429f37 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc
index 8a0a80c..551171b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_api.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc
index a3bfe50..74d1630 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_macos.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc
index 0f29fe2..b285a19 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_openssl.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc
index 3edfc28..95a0365 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_ssl_constants.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc
index 62b5220..af4b125 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/truststore/__pycache__/_windows.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc
index f60f3e1..b3dd070 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc
index dc46cf0..66139a6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_collections.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc
index 35668fa..7d58629 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/_version.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc
index 5e1dbae..0c874a5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connection.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc
index 970397c..0db4bb1 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/connectionpool.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc
index b3a50dc..0c3fb45 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/exceptions.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc
index d6a3a38..6a52366 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/fields.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc
index 25dbd13..c850663 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/filepost.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc
index 6ae719a..c2abd23 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/poolmanager.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc
index 2ae0e54..97227db 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/request.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc
index b9c840e..053253f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/__pycache__/response.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc
index bf72e2b..d69d4ba 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc
index 9b998dd..6e27cf8 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/_appengine_environ.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc
index 0f67c67..3823787 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/appengine.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc
index 4c09ad8..a522e5f 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/ntlmpool.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc
index 4e61d12..359257d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc
index 86bb556..f2e1dcb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/securetransport.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc
index 112d5ec..070890e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/__pycache__/socks.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc
index 8f15169..d17e175 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc
index 575a86e..59a052e 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/bindings.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc
index 01bd2e2..553a18a 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__pycache__/low_level.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc
index e72f5f2..4d89ef4 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc
index 4533288..b478edb 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/__pycache__/six.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc
index 6ae68b0..10d37fa 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc
index 2ada100..5c99d36 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/makefile.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc
index cfd949c..4135d64 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/packages/backports/__pycache__/weakref_finalize.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc
index 36861a4..0a16ab0 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/__init__.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc
index d851565..38dbe24 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/connection.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc
index b6189f5..bfbf0c9 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/proxy.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc
index b0cb0c9..02984d5 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/queue.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc
index 8b096a9..3fad075 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/request.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc
index 01e2fac..d144fb6 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/response.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc
index 6ad0eb9..84aaae2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/retry.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc
index ecb522e..5db5cd3 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc
index b4731f4..39dfdc2 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc
index 64ce17f..967fe6b 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/ssltransport.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc
index d7c565f..4352985 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/timeout.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc
index cf9ca79..2f0caca 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/url.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc
index 496ff0f..d00402d 100644
Binary files a/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc and b/.venv/lib/python3.12/site-packages/pip/_vendor/urllib3/util/__pycache__/wait.cpython-312.pyc differ
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/LICENSE b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/LICENSE
deleted file mode 100644
index 67db858..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/LICENSE
+++ /dev/null
@@ -1,175 +0,0 @@
-
- Apache License
- Version 2.0, January 2004
- http://www.apache.org/licenses/
-
- TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
-
- 1. Definitions.
-
- "License" shall mean the terms and conditions for use, reproduction,
- and distribution as defined by Sections 1 through 9 of this document.
-
- "Licensor" shall mean the copyright owner or entity authorized by
- the copyright owner that is granting the License.
-
- "Legal Entity" shall mean the union of the acting entity and all
- other entities that control, are controlled by, or are under common
- control with that entity. For the purposes of this definition,
- "control" means (i) the power, direct or indirect, to cause the
- direction or management of such entity, whether by contract or
- otherwise, or (ii) ownership of fifty percent (50%) or more of the
- outstanding shares, or (iii) beneficial ownership of such entity.
-
- "You" (or "Your") shall mean an individual or Legal Entity
- exercising permissions granted by this License.
-
- "Source" form shall mean the preferred form for making modifications,
- including but not limited to software source code, documentation
- source, and configuration files.
-
- "Object" form shall mean any form resulting from mechanical
- transformation or translation of a Source form, including but
- not limited to compiled object code, generated documentation,
- and conversions to other media types.
-
- "Work" shall mean the work of authorship, whether in Source or
- Object form, made available under the License, as indicated by a
- copyright notice that is included in or attached to the work
- (an example is provided in the Appendix below).
-
- "Derivative Works" shall mean any work, whether in Source or Object
- form, that is based on (or derived from) the Work and for which the
- editorial revisions, annotations, elaborations, or other modifications
- represent, as a whole, an original work of authorship. For the purposes
- of this License, Derivative Works shall not include works that remain
- separable from, or merely link (or bind by name) to the interfaces of,
- the Work and Derivative Works thereof.
-
- "Contribution" shall mean any work of authorship, including
- the original version of the Work and any modifications or additions
- to that Work or Derivative Works thereof, that is intentionally
- submitted to Licensor for inclusion in the Work by the copyright owner
- or by an individual or Legal Entity authorized to submit on behalf of
- the copyright owner. For the purposes of this definition, "submitted"
- means any form of electronic, verbal, or written communication sent
- to the Licensor or its representatives, including but not limited to
- communication on electronic mailing lists, source code control systems,
- and issue tracking systems that are managed by, or on behalf of, the
- Licensor for the purpose of discussing and improving the Work, but
- excluding communication that is conspicuously marked or otherwise
- designated in writing by the copyright owner as "Not a Contribution."
-
- "Contributor" shall mean Licensor and any individual or Legal Entity
- on behalf of whom a Contribution has been received by Licensor and
- subsequently incorporated within the Work.
-
- 2. Grant of Copyright License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- copyright license to reproduce, prepare Derivative Works of,
- publicly display, publicly perform, sublicense, and distribute the
- Work and such Derivative Works in Source or Object form.
-
- 3. Grant of Patent License. Subject to the terms and conditions of
- this License, each Contributor hereby grants to You a perpetual,
- worldwide, non-exclusive, no-charge, royalty-free, irrevocable
- (except as stated in this section) patent license to make, have made,
- use, offer to sell, sell, import, and otherwise transfer the Work,
- where such license applies only to those patent claims licensable
- by such Contributor that are necessarily infringed by their
- Contribution(s) alone or by combination of their Contribution(s)
- with the Work to which such Contribution(s) was submitted. If You
- institute patent litigation against any entity (including a
- cross-claim or counterclaim in a lawsuit) alleging that the Work
- or a Contribution incorporated within the Work constitutes direct
- or contributory patent infringement, then any patent licenses
- granted to You under this License for that Work shall terminate
- as of the date such litigation is filed.
-
- 4. Redistribution. You may reproduce and distribute copies of the
- Work or Derivative Works thereof in any medium, with or without
- modifications, and in Source or Object form, provided that You
- meet the following conditions:
-
- (a) You must give any other recipients of the Work or
- Derivative Works a copy of this License; and
-
- (b) You must cause any modified files to carry prominent notices
- stating that You changed the files; and
-
- (c) You must retain, in the Source form of any Derivative Works
- that You distribute, all copyright, patent, trademark, and
- attribution notices from the Source form of the Work,
- excluding those notices that do not pertain to any part of
- the Derivative Works; and
-
- (d) If the Work includes a "NOTICE" text file as part of its
- distribution, then any Derivative Works that You distribute must
- include a readable copy of the attribution notices contained
- within such NOTICE file, excluding those notices that do not
- pertain to any part of the Derivative Works, in at least one
- of the following places: within a NOTICE text file distributed
- as part of the Derivative Works; within the Source form or
- documentation, if provided along with the Derivative Works; or,
- within a display generated by the Derivative Works, if and
- wherever such third-party notices normally appear. The contents
- of the NOTICE file are for informational purposes only and
- do not modify the License. You may add Your own attribution
- notices within Derivative Works that You distribute, alongside
- or as an addendum to the NOTICE text from the Work, provided
- that such additional attribution notices cannot be construed
- as modifying the License.
-
- You may add Your own copyright statement to Your modifications and
- may provide additional or different license terms and conditions
- for use, reproduction, or distribution of Your modifications, or
- for any such Derivative Works as a whole, provided Your use,
- reproduction, and distribution of the Work otherwise complies with
- the conditions stated in this License.
-
- 5. Submission of Contributions. Unless You explicitly state otherwise,
- any Contribution intentionally submitted for inclusion in the Work
- by You to the Licensor shall be under the terms and conditions of
- this License, without any additional terms or conditions.
- Notwithstanding the above, nothing herein shall supersede or modify
- the terms of any separate license agreement you may have executed
- with Licensor regarding such Contributions.
-
- 6. Trademarks. This License does not grant permission to use the trade
- names, trademarks, service marks, or product names of the Licensor,
- except as required for reasonable and customary use in describing the
- origin of the Work and reproducing the content of the NOTICE file.
-
- 7. Disclaimer of Warranty. Unless required by applicable law or
- agreed to in writing, Licensor provides the Work (and each
- Contributor provides its Contributions) on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
- implied, including, without limitation, any warranties or conditions
- of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
- PARTICULAR PURPOSE. You are solely responsible for determining the
- appropriateness of using or redistributing the Work and assume any
- risks associated with Your exercise of permissions under this License.
-
- 8. Limitation of Liability. In no event and under no legal theory,
- whether in tort (including negligence), contract, or otherwise,
- unless required by applicable law (such as deliberate and grossly
- negligent acts) or agreed to in writing, shall any Contributor be
- liable to You for damages, including any direct, indirect, special,
- incidental, or consequential damages of any character arising as a
- result of this License or out of the use or inability to use the
- Work (including but not limited to damages for loss of goodwill,
- work stoppage, computer failure or malfunction, or any and all
- other commercial damages or losses), even if such Contributor
- has been advised of the possibility of such damages.
-
- 9. Accepting Warranty or Additional Liability. While redistributing
- the Work or Derivative Works thereof, You may choose to offer,
- and charge a fee for, acceptance of support, warranty, indemnity,
- or other liability obligations and/or rights consistent with this
- License. However, in accepting such obligations, You may act only
- on Your own behalf and on Your sole responsibility, not on behalf
- of any other Contributor, and only if You agree to indemnify,
- defend, and hold each Contributor harmless for any liability
- incurred by, or claims asserted against, such Contributor by reason
- of your accepting any such warranty or additional liability.
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/METADATA b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/METADATA
deleted file mode 100644
index 72d9dc5..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/METADATA
+++ /dev/null
@@ -1,119 +0,0 @@
-Metadata-Version: 2.1
-Name: requests
-Version: 2.32.3
-Summary: Python HTTP for Humans.
-Home-page: https://requests.readthedocs.io
-Author: Kenneth Reitz
-Author-email: me@kennethreitz.org
-License: Apache-2.0
-Project-URL: Documentation, https://requests.readthedocs.io
-Project-URL: Source, https://github.com/psf/requests
-Classifier: Development Status :: 5 - Production/Stable
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: Apache Software License
-Classifier: Natural Language :: English
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: WWW/HTTP
-Classifier: Topic :: Software Development :: Libraries
-Requires-Python: >=3.8
-Description-Content-Type: text/markdown
-License-File: LICENSE
-Requires-Dist: charset-normalizer <4,>=2
-Requires-Dist: idna <4,>=2.5
-Requires-Dist: urllib3 <3,>=1.21.1
-Requires-Dist: certifi >=2017.4.17
-Provides-Extra: security
-Provides-Extra: socks
-Requires-Dist: PySocks !=1.5.7,>=1.5.6 ; extra == 'socks'
-Provides-Extra: use_chardet_on_py3
-Requires-Dist: chardet <6,>=3.0.2 ; extra == 'use_chardet_on_py3'
-
-# Requests
-
-**Requests** is a simple, yet elegant, HTTP library.
-
-```python
->>> import requests
->>> r = requests.get('https://httpbin.org/basic-auth/user/pass', auth=('user', 'pass'))
->>> r.status_code
-200
->>> r.headers['content-type']
-'application/json; charset=utf8'
->>> r.encoding
-'utf-8'
->>> r.text
-'{"authenticated": true, ...'
->>> r.json()
-{'authenticated': True, ...}
-```
-
-Requests allows you to send HTTP/1.1 requests extremely easily. There’s no need to manually add query strings to your URLs, or to form-encode your `PUT` & `POST` data — but nowadays, just use the `json` method!
-
-Requests is one of the most downloaded Python packages today, pulling in around `30M downloads / week`— according to GitHub, Requests is currently [depended upon](https://github.com/psf/requests/network/dependents?package_id=UGFja2FnZS01NzA4OTExNg%3D%3D) by `1,000,000+` repositories. You may certainly put your trust in this code.
-
-[](https://pepy.tech/project/requests)
-[](https://pypi.org/project/requests)
-[](https://github.com/psf/requests/graphs/contributors)
-
-## Installing Requests and Supported Versions
-
-Requests is available on PyPI:
-
-```console
-$ python -m pip install requests
-```
-
-Requests officially supports Python 3.8+.
-
-## Supported Features & Best–Practices
-
-Requests is ready for the demands of building robust and reliable HTTP–speaking applications, for the needs of today.
-
-- Keep-Alive & Connection Pooling
-- International Domains and URLs
-- Sessions with Cookie Persistence
-- Browser-style TLS/SSL Verification
-- Basic & Digest Authentication
-- Familiar `dict`–like Cookies
-- Automatic Content Decompression and Decoding
-- Multi-part File Uploads
-- SOCKS Proxy Support
-- Connection Timeouts
-- Streaming Downloads
-- Automatic honoring of `.netrc`
-- Chunked HTTP Requests
-
-## API Reference and User Guide available on [Read the Docs](https://requests.readthedocs.io)
-
-[](https://requests.readthedocs.io)
-
-## Cloning the repository
-
-When cloning the Requests repository, you may need to add the `-c
-fetch.fsck.badTimezone=ignore` flag to avoid an error about a bad commit (see
-[this issue](https://github.com/psf/requests/issues/2690) for more background):
-
-```shell
-git clone -c fetch.fsck.badTimezone=ignore https://github.com/psf/requests.git
-```
-
-You can also apply this setting to your global Git config:
-
-```shell
-git config --global fetch.fsck.badTimezone ignore
-```
-
----
-
-[](https://kennethreitz.org) [](https://www.python.org/psf)
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/RECORD b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/RECORD
deleted file mode 100644
index f34e5a1..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/RECORD
+++ /dev/null
@@ -1,43 +0,0 @@
-requests-2.32.3.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-requests-2.32.3.dist-info/LICENSE,sha256=CeipvOyAZxBGUsFoaFqwkx54aPnIKEtm9a5u2uXxEws,10142
-requests-2.32.3.dist-info/METADATA,sha256=ZY7oRUweLnb7jCEnEW9hFWs7IpQbNVnAA4ncpwA4WBo,4610
-requests-2.32.3.dist-info/RECORD,,
-requests-2.32.3.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-requests-2.32.3.dist-info/WHEEL,sha256=GJ7t_kWBFywbagK5eo9IoUwLW6oyOeTKmQ-9iHFVNxQ,92
-requests-2.32.3.dist-info/top_level.txt,sha256=fMSVmHfb5rbGOo6xv-O_tUX6j-WyixssE-SnwcDRxNQ,9
-requests/__init__.py,sha256=4xaAERmPDIBPsa2PsjpU9r06yooK-2mZKHTZAhWRWts,5072
-requests/__pycache__/__init__.cpython-312.pyc,,
-requests/__pycache__/__version__.cpython-312.pyc,,
-requests/__pycache__/_internal_utils.cpython-312.pyc,,
-requests/__pycache__/adapters.cpython-312.pyc,,
-requests/__pycache__/api.cpython-312.pyc,,
-requests/__pycache__/auth.cpython-312.pyc,,
-requests/__pycache__/certs.cpython-312.pyc,,
-requests/__pycache__/compat.cpython-312.pyc,,
-requests/__pycache__/cookies.cpython-312.pyc,,
-requests/__pycache__/exceptions.cpython-312.pyc,,
-requests/__pycache__/help.cpython-312.pyc,,
-requests/__pycache__/hooks.cpython-312.pyc,,
-requests/__pycache__/models.cpython-312.pyc,,
-requests/__pycache__/packages.cpython-312.pyc,,
-requests/__pycache__/sessions.cpython-312.pyc,,
-requests/__pycache__/status_codes.cpython-312.pyc,,
-requests/__pycache__/structures.cpython-312.pyc,,
-requests/__pycache__/utils.cpython-312.pyc,,
-requests/__version__.py,sha256=FVfglgZmNQnmYPXpOohDU58F5EUb_-VnSTaAesS187g,435
-requests/_internal_utils.py,sha256=nMQymr4hs32TqVo5AbCrmcJEhvPUh7xXlluyqwslLiQ,1495
-requests/adapters.py,sha256=KIcecscqam6reOCXRl4DwP4jX8Jcl8sd57ft17KR2cQ,27451
-requests/api.py,sha256=_Zb9Oa7tzVIizTKwFrPjDEY9ejtm_OnSRERnADxGsQs,6449
-requests/auth.py,sha256=kF75tqnLctZ9Mf_hm9TZIj4cQWnN5uxRz8oWsx5wmR0,10186
-requests/certs.py,sha256=Z9Sb410Anv6jUFTyss0jFFhU6xst8ctELqfy8Ev23gw,429
-requests/compat.py,sha256=C5w_DPLSurXPgcdWU78fora0APmbYkX2G89QvH5xzPA,1817
-requests/cookies.py,sha256=bNi-iqEj4NPZ00-ob-rHvzkvObzN3lEpgw3g6paS3Xw,18590
-requests/exceptions.py,sha256=jJPS1UWATs86ShVUaLorTiJb1SaGuoNEWgICJep-VkY,4260
-requests/help.py,sha256=gPX5d_H7Xd88aDABejhqGgl9B1VFRTt5BmiYvL3PzIQ,3875
-requests/hooks.py,sha256=CiuysiHA39V5UfcCBXFIx83IrDpuwfN9RcTUgv28ftQ,733
-requests/models.py,sha256=k42roXzC8u_OagAPQi9U4MkfO7i4r2FdaqvMqstPehc,35418
-requests/packages.py,sha256=_g0gZ681UyAlKHRjH6kanbaoxx2eAb6qzcXiODyTIoc,904
-requests/sessions.py,sha256=ykTI8UWGSltOfH07HKollH7kTBGw4WhiBVaQGmckTw4,30495
-requests/status_codes.py,sha256=iJUAeA25baTdw-6PfD0eF4qhpINDJRJI-yaMqxs4LEI,4322
-requests/structures.py,sha256=-IbmhVz06S-5aPSZuUthZ6-6D9XOjRuTXHOabY041XM,2912
-requests/utils.py,sha256=HiQC6Nq_Da3ktaMiFzQkh-dCk3iQHHKEsYS5kDc-8Cw,33619
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/REQUESTED b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/REQUESTED
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/WHEEL
deleted file mode 100644
index bab98d6..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/WHEEL
+++ /dev/null
@@ -1,5 +0,0 @@
-Wheel-Version: 1.0
-Generator: bdist_wheel (0.43.0)
-Root-Is-Purelib: true
-Tag: py3-none-any
-
diff --git a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/top_level.txt b/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/top_level.txt
deleted file mode 100644
index f229360..0000000
--- a/.venv/lib/python3.12/site-packages/requests-2.32.3.dist-info/top_level.txt
+++ /dev/null
@@ -1 +0,0 @@
-requests
diff --git a/.venv/lib/python3.12/site-packages/requests/__init__.py b/.venv/lib/python3.12/site-packages/requests/__init__.py
deleted file mode 100644
index 051cda1..0000000
--- a/.venv/lib/python3.12/site-packages/requests/__init__.py
+++ /dev/null
@@ -1,184 +0,0 @@
-# __
-# /__) _ _ _ _ _/ _
-# / ( (- (/ (/ (- _) / _)
-# /
-
-"""
-Requests HTTP Library
-~~~~~~~~~~~~~~~~~~~~~
-
-Requests is an HTTP library, written in Python, for human beings.
-Basic GET usage:
-
- >>> import requests
- >>> r = requests.get('https://www.python.org')
- >>> r.status_code
- 200
- >>> b'Python is a programming language' in r.content
- True
-
-... or POST:
-
- >>> payload = dict(key1='value1', key2='value2')
- >>> r = requests.post('https://httpbin.org/post', data=payload)
- >>> print(r.text)
- {
- ...
- "form": {
- "key1": "value1",
- "key2": "value2"
- },
- ...
- }
-
-The other HTTP methods are supported - see `requests.api`. Full documentation
-is at .
-
-:copyright: (c) 2017 by Kenneth Reitz.
-:license: Apache 2.0, see LICENSE for more details.
-"""
-
-import warnings
-
-import urllib3
-
-from .exceptions import RequestsDependencyWarning
-
-try:
- from charset_normalizer import __version__ as charset_normalizer_version
-except ImportError:
- charset_normalizer_version = None
-
-try:
- from chardet import __version__ as chardet_version
-except ImportError:
- chardet_version = None
-
-
-def check_compatibility(urllib3_version, chardet_version, charset_normalizer_version):
- urllib3_version = urllib3_version.split(".")
- assert urllib3_version != ["dev"] # Verify urllib3 isn't installed from git.
-
- # Sometimes, urllib3 only reports its version as 16.1.
- if len(urllib3_version) == 2:
- urllib3_version.append("0")
-
- # Check urllib3 for compatibility.
- major, minor, patch = urllib3_version # noqa: F811
- major, minor, patch = int(major), int(minor), int(patch)
- # urllib3 >= 1.21.1
- assert major >= 1
- if major == 1:
- assert minor >= 21
-
- # Check charset_normalizer for compatibility.
- if chardet_version:
- major, minor, patch = chardet_version.split(".")[:3]
- major, minor, patch = int(major), int(minor), int(patch)
- # chardet_version >= 3.0.2, < 6.0.0
- assert (3, 0, 2) <= (major, minor, patch) < (6, 0, 0)
- elif charset_normalizer_version:
- major, minor, patch = charset_normalizer_version.split(".")[:3]
- major, minor, patch = int(major), int(minor), int(patch)
- # charset_normalizer >= 2.0.0 < 4.0.0
- assert (2, 0, 0) <= (major, minor, patch) < (4, 0, 0)
- else:
- warnings.warn(
- "Unable to find acceptable character detection dependency "
- "(chardet or charset_normalizer).",
- RequestsDependencyWarning,
- )
-
-
-def _check_cryptography(cryptography_version):
- # cryptography < 1.3.4
- try:
- cryptography_version = list(map(int, cryptography_version.split(".")))
- except ValueError:
- return
-
- if cryptography_version < [1, 3, 4]:
- warning = "Old version of cryptography ({}) may cause slowdown.".format(
- cryptography_version
- )
- warnings.warn(warning, RequestsDependencyWarning)
-
-
-# Check imported dependencies for compatibility.
-try:
- check_compatibility(
- urllib3.__version__, chardet_version, charset_normalizer_version
- )
-except (AssertionError, ValueError):
- warnings.warn(
- "urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
- "version!".format(
- urllib3.__version__, chardet_version, charset_normalizer_version
- ),
- RequestsDependencyWarning,
- )
-
-# Attempt to enable urllib3's fallback for SNI support
-# if the standard library doesn't support SNI or the
-# 'ssl' library isn't available.
-try:
- try:
- import ssl
- except ImportError:
- ssl = None
-
- if not getattr(ssl, "HAS_SNI", False):
- from urllib3.contrib import pyopenssl
-
- pyopenssl.inject_into_urllib3()
-
- # Check cryptography version
- from cryptography import __version__ as cryptography_version
-
- _check_cryptography(cryptography_version)
-except ImportError:
- pass
-
-# urllib3's DependencyWarnings should be silenced.
-from urllib3.exceptions import DependencyWarning
-
-warnings.simplefilter("ignore", DependencyWarning)
-
-# Set default logging handler to avoid "No handler found" warnings.
-import logging
-from logging import NullHandler
-
-from . import packages, utils
-from .__version__ import (
- __author__,
- __author_email__,
- __build__,
- __cake__,
- __copyright__,
- __description__,
- __license__,
- __title__,
- __url__,
- __version__,
-)
-from .api import delete, get, head, options, patch, post, put, request
-from .exceptions import (
- ConnectionError,
- ConnectTimeout,
- FileModeWarning,
- HTTPError,
- JSONDecodeError,
- ReadTimeout,
- RequestException,
- Timeout,
- TooManyRedirects,
- URLRequired,
-)
-from .models import PreparedRequest, Request, Response
-from .sessions import Session, session
-from .status_codes import codes
-
-logging.getLogger(__name__).addHandler(NullHandler())
-
-# FileModeWarnings go off per the default.
-warnings.simplefilter("default", FileModeWarning, append=True)
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index d5e5762..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/__version__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/__version__.cpython-312.pyc
deleted file mode 100644
index cc7f5a8..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/__version__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc
deleted file mode 100644
index 4e379f3..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/_internal_utils.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/adapters.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/adapters.cpython-312.pyc
deleted file mode 100644
index d2b727a..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/adapters.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/api.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/api.cpython-312.pyc
deleted file mode 100644
index b83f5bd..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/api.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/auth.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/auth.cpython-312.pyc
deleted file mode 100644
index 2608c72..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/auth.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/certs.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/certs.cpython-312.pyc
deleted file mode 100644
index 3542f90..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/certs.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/compat.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/compat.cpython-312.pyc
deleted file mode 100644
index c8de5f2..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/compat.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/cookies.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/cookies.cpython-312.pyc
deleted file mode 100644
index 68ecae0..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/cookies.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/exceptions.cpython-312.pyc
deleted file mode 100644
index 7a9d350..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/exceptions.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/help.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/help.cpython-312.pyc
deleted file mode 100644
index fc62580..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/help.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/hooks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/hooks.cpython-312.pyc
deleted file mode 100644
index f5ebe63..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/hooks.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/models.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/models.cpython-312.pyc
deleted file mode 100644
index 7e308b5..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/models.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/packages.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/packages.cpython-312.pyc
deleted file mode 100644
index 2b9f4d3..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/packages.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/sessions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/sessions.cpython-312.pyc
deleted file mode 100644
index 5e2cde3..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/sessions.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/status_codes.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/status_codes.cpython-312.pyc
deleted file mode 100644
index 24578c8..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/status_codes.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/structures.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/structures.cpython-312.pyc
deleted file mode 100644
index c1baf87..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/structures.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__pycache__/utils.cpython-312.pyc b/.venv/lib/python3.12/site-packages/requests/__pycache__/utils.cpython-312.pyc
deleted file mode 100644
index 31f7bed..0000000
Binary files a/.venv/lib/python3.12/site-packages/requests/__pycache__/utils.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/requests/__version__.py b/.venv/lib/python3.12/site-packages/requests/__version__.py
deleted file mode 100644
index 2c105ac..0000000
--- a/.venv/lib/python3.12/site-packages/requests/__version__.py
+++ /dev/null
@@ -1,14 +0,0 @@
-# .-. .-. .-. . . .-. .-. .-. .-.
-# |( |- |.| | | |- `-. | `-.
-# ' ' `-' `-`.`-' `-' `-' ' `-'
-
-__title__ = "requests"
-__description__ = "Python HTTP for Humans."
-__url__ = "https://requests.readthedocs.io"
-__version__ = "2.32.3"
-__build__ = 0x023203
-__author__ = "Kenneth Reitz"
-__author_email__ = "me@kennethreitz.org"
-__license__ = "Apache-2.0"
-__copyright__ = "Copyright Kenneth Reitz"
-__cake__ = "\u2728 \U0001f370 \u2728"
diff --git a/.venv/lib/python3.12/site-packages/requests/_internal_utils.py b/.venv/lib/python3.12/site-packages/requests/_internal_utils.py
deleted file mode 100644
index f2cf635..0000000
--- a/.venv/lib/python3.12/site-packages/requests/_internal_utils.py
+++ /dev/null
@@ -1,50 +0,0 @@
-"""
-requests._internal_utils
-~~~~~~~~~~~~~~
-
-Provides utility functions that are consumed internally by Requests
-which depend on extremely few external helpers (such as compat)
-"""
-import re
-
-from .compat import builtin_str
-
-_VALID_HEADER_NAME_RE_BYTE = re.compile(rb"^[^:\s][^:\r\n]*$")
-_VALID_HEADER_NAME_RE_STR = re.compile(r"^[^:\s][^:\r\n]*$")
-_VALID_HEADER_VALUE_RE_BYTE = re.compile(rb"^\S[^\r\n]*$|^$")
-_VALID_HEADER_VALUE_RE_STR = re.compile(r"^\S[^\r\n]*$|^$")
-
-_HEADER_VALIDATORS_STR = (_VALID_HEADER_NAME_RE_STR, _VALID_HEADER_VALUE_RE_STR)
-_HEADER_VALIDATORS_BYTE = (_VALID_HEADER_NAME_RE_BYTE, _VALID_HEADER_VALUE_RE_BYTE)
-HEADER_VALIDATORS = {
- bytes: _HEADER_VALIDATORS_BYTE,
- str: _HEADER_VALIDATORS_STR,
-}
-
-
-def to_native_string(string, encoding="ascii"):
- """Given a string object, regardless of type, returns a representation of
- that string in the native string type, encoding and decoding where
- necessary. This assumes ASCII unless told otherwise.
- """
- if isinstance(string, builtin_str):
- out = string
- else:
- out = string.decode(encoding)
-
- return out
-
-
-def unicode_is_ascii(u_string):
- """Determine if unicode string only contains ASCII characters.
-
- :param str u_string: unicode string to check. Must be unicode
- and not Python 2 `str`.
- :rtype: bool
- """
- assert isinstance(u_string, str)
- try:
- u_string.encode("ascii")
- return True
- except UnicodeEncodeError:
- return False
diff --git a/.venv/lib/python3.12/site-packages/requests/adapters.py b/.venv/lib/python3.12/site-packages/requests/adapters.py
deleted file mode 100644
index 9a58b16..0000000
--- a/.venv/lib/python3.12/site-packages/requests/adapters.py
+++ /dev/null
@@ -1,719 +0,0 @@
-"""
-requests.adapters
-~~~~~~~~~~~~~~~~~
-
-This module contains the transport adapters that Requests uses to define
-and maintain connections.
-"""
-
-import os.path
-import socket # noqa: F401
-import typing
-import warnings
-
-from urllib3.exceptions import ClosedPoolError, ConnectTimeoutError
-from urllib3.exceptions import HTTPError as _HTTPError
-from urllib3.exceptions import InvalidHeader as _InvalidHeader
-from urllib3.exceptions import (
- LocationValueError,
- MaxRetryError,
- NewConnectionError,
- ProtocolError,
-)
-from urllib3.exceptions import ProxyError as _ProxyError
-from urllib3.exceptions import ReadTimeoutError, ResponseError
-from urllib3.exceptions import SSLError as _SSLError
-from urllib3.poolmanager import PoolManager, proxy_from_url
-from urllib3.util import Timeout as TimeoutSauce
-from urllib3.util import parse_url
-from urllib3.util.retry import Retry
-from urllib3.util.ssl_ import create_urllib3_context
-
-from .auth import _basic_auth_str
-from .compat import basestring, urlparse
-from .cookies import extract_cookies_to_jar
-from .exceptions import (
- ConnectionError,
- ConnectTimeout,
- InvalidHeader,
- InvalidProxyURL,
- InvalidSchema,
- InvalidURL,
- ProxyError,
- ReadTimeout,
- RetryError,
- SSLError,
-)
-from .models import Response
-from .structures import CaseInsensitiveDict
-from .utils import (
- DEFAULT_CA_BUNDLE_PATH,
- extract_zipped_paths,
- get_auth_from_url,
- get_encoding_from_headers,
- prepend_scheme_if_needed,
- select_proxy,
- urldefragauth,
-)
-
-try:
- from urllib3.contrib.socks import SOCKSProxyManager
-except ImportError:
-
- def SOCKSProxyManager(*args, **kwargs):
- raise InvalidSchema("Missing dependencies for SOCKS support.")
-
-
-if typing.TYPE_CHECKING:
- from .models import PreparedRequest
-
-
-DEFAULT_POOLBLOCK = False
-DEFAULT_POOLSIZE = 10
-DEFAULT_RETRIES = 0
-DEFAULT_POOL_TIMEOUT = None
-
-
-try:
- import ssl # noqa: F401
-
- _preloaded_ssl_context = create_urllib3_context()
- _preloaded_ssl_context.load_verify_locations(
- extract_zipped_paths(DEFAULT_CA_BUNDLE_PATH)
- )
-except ImportError:
- # Bypass default SSLContext creation when Python
- # interpreter isn't built with the ssl module.
- _preloaded_ssl_context = None
-
-
-def _urllib3_request_context(
- request: "PreparedRequest",
- verify: "bool | str | None",
- client_cert: "typing.Tuple[str, str] | str | None",
- poolmanager: "PoolManager",
-) -> "(typing.Dict[str, typing.Any], typing.Dict[str, typing.Any])":
- host_params = {}
- pool_kwargs = {}
- parsed_request_url = urlparse(request.url)
- scheme = parsed_request_url.scheme.lower()
- port = parsed_request_url.port
-
- # Determine if we have and should use our default SSLContext
- # to optimize performance on standard requests.
- poolmanager_kwargs = getattr(poolmanager, "connection_pool_kw", {})
- has_poolmanager_ssl_context = poolmanager_kwargs.get("ssl_context")
- should_use_default_ssl_context = (
- _preloaded_ssl_context is not None and not has_poolmanager_ssl_context
- )
-
- cert_reqs = "CERT_REQUIRED"
- if verify is False:
- cert_reqs = "CERT_NONE"
- elif verify is True and should_use_default_ssl_context:
- pool_kwargs["ssl_context"] = _preloaded_ssl_context
- elif isinstance(verify, str):
- if not os.path.isdir(verify):
- pool_kwargs["ca_certs"] = verify
- else:
- pool_kwargs["ca_cert_dir"] = verify
- pool_kwargs["cert_reqs"] = cert_reqs
- if client_cert is not None:
- if isinstance(client_cert, tuple) and len(client_cert) == 2:
- pool_kwargs["cert_file"] = client_cert[0]
- pool_kwargs["key_file"] = client_cert[1]
- else:
- # According to our docs, we allow users to specify just the client
- # cert path
- pool_kwargs["cert_file"] = client_cert
- host_params = {
- "scheme": scheme,
- "host": parsed_request_url.hostname,
- "port": port,
- }
- return host_params, pool_kwargs
-
-
-class BaseAdapter:
- """The Base Transport Adapter"""
-
- def __init__(self):
- super().__init__()
-
- def send(
- self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
- ):
- """Sends PreparedRequest object. Returns Response object.
-
- :param request: The :class:`PreparedRequest ` being sent.
- :param stream: (optional) Whether to stream the request content.
- :param timeout: (optional) How long to wait for the server to send
- data before giving up, as a float, or a :ref:`(connect timeout,
- read timeout) ` tuple.
- :type timeout: float or tuple
- :param verify: (optional) Either a boolean, in which case it controls whether we verify
- the server's TLS certificate, or a string, in which case it must be a path
- to a CA bundle to use
- :param cert: (optional) Any user-provided SSL certificate to be trusted.
- :param proxies: (optional) The proxies dictionary to apply to the request.
- """
- raise NotImplementedError
-
- def close(self):
- """Cleans up adapter specific items."""
- raise NotImplementedError
-
-
-class HTTPAdapter(BaseAdapter):
- """The built-in HTTP Adapter for urllib3.
-
- Provides a general-case interface for Requests sessions to contact HTTP and
- HTTPS urls by implementing the Transport Adapter interface. This class will
- usually be created by the :class:`Session ` class under the
- covers.
-
- :param pool_connections: The number of urllib3 connection pools to cache.
- :param pool_maxsize: The maximum number of connections to save in the pool.
- :param max_retries: The maximum number of retries each connection
- should attempt. Note, this applies only to failed DNS lookups, socket
- connections and connection timeouts, never to requests where data has
- made it to the server. By default, Requests does not retry failed
- connections. If you need granular control over the conditions under
- which we retry a request, import urllib3's ``Retry`` class and pass
- that instead.
- :param pool_block: Whether the connection pool should block for connections.
-
- Usage::
-
- >>> import requests
- >>> s = requests.Session()
- >>> a = requests.adapters.HTTPAdapter(max_retries=3)
- >>> s.mount('http://', a)
- """
-
- __attrs__ = [
- "max_retries",
- "config",
- "_pool_connections",
- "_pool_maxsize",
- "_pool_block",
- ]
-
- def __init__(
- self,
- pool_connections=DEFAULT_POOLSIZE,
- pool_maxsize=DEFAULT_POOLSIZE,
- max_retries=DEFAULT_RETRIES,
- pool_block=DEFAULT_POOLBLOCK,
- ):
- if max_retries == DEFAULT_RETRIES:
- self.max_retries = Retry(0, read=False)
- else:
- self.max_retries = Retry.from_int(max_retries)
- self.config = {}
- self.proxy_manager = {}
-
- super().__init__()
-
- self._pool_connections = pool_connections
- self._pool_maxsize = pool_maxsize
- self._pool_block = pool_block
-
- self.init_poolmanager(pool_connections, pool_maxsize, block=pool_block)
-
- def __getstate__(self):
- return {attr: getattr(self, attr, None) for attr in self.__attrs__}
-
- def __setstate__(self, state):
- # Can't handle by adding 'proxy_manager' to self.__attrs__ because
- # self.poolmanager uses a lambda function, which isn't pickleable.
- self.proxy_manager = {}
- self.config = {}
-
- for attr, value in state.items():
- setattr(self, attr, value)
-
- self.init_poolmanager(
- self._pool_connections, self._pool_maxsize, block=self._pool_block
- )
-
- def init_poolmanager(
- self, connections, maxsize, block=DEFAULT_POOLBLOCK, **pool_kwargs
- ):
- """Initializes a urllib3 PoolManager.
-
- This method should not be called from user code, and is only
- exposed for use when subclassing the
- :class:`HTTPAdapter `.
-
- :param connections: The number of urllib3 connection pools to cache.
- :param maxsize: The maximum number of connections to save in the pool.
- :param block: Block when no free connections are available.
- :param pool_kwargs: Extra keyword arguments used to initialize the Pool Manager.
- """
- # save these values for pickling
- self._pool_connections = connections
- self._pool_maxsize = maxsize
- self._pool_block = block
-
- self.poolmanager = PoolManager(
- num_pools=connections,
- maxsize=maxsize,
- block=block,
- **pool_kwargs,
- )
-
- def proxy_manager_for(self, proxy, **proxy_kwargs):
- """Return urllib3 ProxyManager for the given proxy.
-
- This method should not be called from user code, and is only
- exposed for use when subclassing the
- :class:`HTTPAdapter `.
-
- :param proxy: The proxy to return a urllib3 ProxyManager for.
- :param proxy_kwargs: Extra keyword arguments used to configure the Proxy Manager.
- :returns: ProxyManager
- :rtype: urllib3.ProxyManager
- """
- if proxy in self.proxy_manager:
- manager = self.proxy_manager[proxy]
- elif proxy.lower().startswith("socks"):
- username, password = get_auth_from_url(proxy)
- manager = self.proxy_manager[proxy] = SOCKSProxyManager(
- proxy,
- username=username,
- password=password,
- num_pools=self._pool_connections,
- maxsize=self._pool_maxsize,
- block=self._pool_block,
- **proxy_kwargs,
- )
- else:
- proxy_headers = self.proxy_headers(proxy)
- manager = self.proxy_manager[proxy] = proxy_from_url(
- proxy,
- proxy_headers=proxy_headers,
- num_pools=self._pool_connections,
- maxsize=self._pool_maxsize,
- block=self._pool_block,
- **proxy_kwargs,
- )
-
- return manager
-
- def cert_verify(self, conn, url, verify, cert):
- """Verify a SSL certificate. This method should not be called from user
- code, and is only exposed for use when subclassing the
- :class:`HTTPAdapter `.
-
- :param conn: The urllib3 connection object associated with the cert.
- :param url: The requested URL.
- :param verify: Either a boolean, in which case it controls whether we verify
- the server's TLS certificate, or a string, in which case it must be a path
- to a CA bundle to use
- :param cert: The SSL certificate to verify.
- """
- if url.lower().startswith("https") and verify:
- conn.cert_reqs = "CERT_REQUIRED"
-
- # Only load the CA certificates if 'verify' is a string indicating the CA bundle to use.
- # Otherwise, if verify is a boolean, we don't load anything since
- # the connection will be using a context with the default certificates already loaded,
- # and this avoids a call to the slow load_verify_locations()
- if verify is not True:
- # `verify` must be a str with a path then
- cert_loc = verify
-
- if not os.path.exists(cert_loc):
- raise OSError(
- f"Could not find a suitable TLS CA certificate bundle, "
- f"invalid path: {cert_loc}"
- )
-
- if not os.path.isdir(cert_loc):
- conn.ca_certs = cert_loc
- else:
- conn.ca_cert_dir = cert_loc
- else:
- conn.cert_reqs = "CERT_NONE"
- conn.ca_certs = None
- conn.ca_cert_dir = None
-
- if cert:
- if not isinstance(cert, basestring):
- conn.cert_file = cert[0]
- conn.key_file = cert[1]
- else:
- conn.cert_file = cert
- conn.key_file = None
- if conn.cert_file and not os.path.exists(conn.cert_file):
- raise OSError(
- f"Could not find the TLS certificate file, "
- f"invalid path: {conn.cert_file}"
- )
- if conn.key_file and not os.path.exists(conn.key_file):
- raise OSError(
- f"Could not find the TLS key file, invalid path: {conn.key_file}"
- )
-
- def build_response(self, req, resp):
- """Builds a :class:`Response ` object from a urllib3
- response. This should not be called from user code, and is only exposed
- for use when subclassing the
- :class:`HTTPAdapter `
-
- :param req: The :class:`PreparedRequest ` used to generate the response.
- :param resp: The urllib3 response object.
- :rtype: requests.Response
- """
- response = Response()
-
- # Fallback to None if there's no status_code, for whatever reason.
- response.status_code = getattr(resp, "status", None)
-
- # Make headers case-insensitive.
- response.headers = CaseInsensitiveDict(getattr(resp, "headers", {}))
-
- # Set encoding.
- response.encoding = get_encoding_from_headers(response.headers)
- response.raw = resp
- response.reason = response.raw.reason
-
- if isinstance(req.url, bytes):
- response.url = req.url.decode("utf-8")
- else:
- response.url = req.url
-
- # Add new cookies from the server.
- extract_cookies_to_jar(response.cookies, req, resp)
-
- # Give the Response some context.
- response.request = req
- response.connection = self
-
- return response
-
- def build_connection_pool_key_attributes(self, request, verify, cert=None):
- """Build the PoolKey attributes used by urllib3 to return a connection.
-
- This looks at the PreparedRequest, the user-specified verify value,
- and the value of the cert parameter to determine what PoolKey values
- to use to select a connection from a given urllib3 Connection Pool.
-
- The SSL related pool key arguments are not consistently set. As of
- this writing, use the following to determine what keys may be in that
- dictionary:
-
- * If ``verify`` is ``True``, ``"ssl_context"`` will be set and will be the
- default Requests SSL Context
- * If ``verify`` is ``False``, ``"ssl_context"`` will not be set but
- ``"cert_reqs"`` will be set
- * If ``verify`` is a string, (i.e., it is a user-specified trust bundle)
- ``"ca_certs"`` will be set if the string is not a directory recognized
- by :py:func:`os.path.isdir`, otherwise ``"ca_certs_dir"`` will be
- set.
- * If ``"cert"`` is specified, ``"cert_file"`` will always be set. If
- ``"cert"`` is a tuple with a second item, ``"key_file"`` will also
- be present
-
- To override these settings, one may subclass this class, call this
- method and use the above logic to change parameters as desired. For
- example, if one wishes to use a custom :py:class:`ssl.SSLContext` one
- must both set ``"ssl_context"`` and based on what else they require,
- alter the other keys to ensure the desired behaviour.
-
- :param request:
- The PreparedReqest being sent over the connection.
- :type request:
- :class:`~requests.models.PreparedRequest`
- :param verify:
- Either a boolean, in which case it controls whether
- we verify the server's TLS certificate, or a string, in which case it
- must be a path to a CA bundle to use.
- :param cert:
- (optional) Any user-provided SSL certificate for client
- authentication (a.k.a., mTLS). This may be a string (i.e., just
- the path to a file which holds both certificate and key) or a
- tuple of length 2 with the certificate file path and key file
- path.
- :returns:
- A tuple of two dictionaries. The first is the "host parameters"
- portion of the Pool Key including scheme, hostname, and port. The
- second is a dictionary of SSLContext related parameters.
- """
- return _urllib3_request_context(request, verify, cert, self.poolmanager)
-
- def get_connection_with_tls_context(self, request, verify, proxies=None, cert=None):
- """Returns a urllib3 connection for the given request and TLS settings.
- This should not be called from user code, and is only exposed for use
- when subclassing the :class:`HTTPAdapter `.
-
- :param request:
- The :class:`PreparedRequest ` object to be sent
- over the connection.
- :param verify:
- Either a boolean, in which case it controls whether we verify the
- server's TLS certificate, or a string, in which case it must be a
- path to a CA bundle to use.
- :param proxies:
- (optional) The proxies dictionary to apply to the request.
- :param cert:
- (optional) Any user-provided SSL certificate to be used for client
- authentication (a.k.a., mTLS).
- :rtype:
- urllib3.ConnectionPool
- """
- proxy = select_proxy(request.url, proxies)
- try:
- host_params, pool_kwargs = self.build_connection_pool_key_attributes(
- request,
- verify,
- cert,
- )
- except ValueError as e:
- raise InvalidURL(e, request=request)
- if proxy:
- proxy = prepend_scheme_if_needed(proxy, "http")
- proxy_url = parse_url(proxy)
- if not proxy_url.host:
- raise InvalidProxyURL(
- "Please check proxy URL. It is malformed "
- "and could be missing the host."
- )
- proxy_manager = self.proxy_manager_for(proxy)
- conn = proxy_manager.connection_from_host(
- **host_params, pool_kwargs=pool_kwargs
- )
- else:
- # Only scheme should be lower case
- conn = self.poolmanager.connection_from_host(
- **host_params, pool_kwargs=pool_kwargs
- )
-
- return conn
-
- def get_connection(self, url, proxies=None):
- """DEPRECATED: Users should move to `get_connection_with_tls_context`
- for all subclasses of HTTPAdapter using Requests>=2.32.2.
-
- Returns a urllib3 connection for the given URL. This should not be
- called from user code, and is only exposed for use when subclassing the
- :class:`HTTPAdapter `.
-
- :param url: The URL to connect to.
- :param proxies: (optional) A Requests-style dictionary of proxies used on this request.
- :rtype: urllib3.ConnectionPool
- """
- warnings.warn(
- (
- "`get_connection` has been deprecated in favor of "
- "`get_connection_with_tls_context`. Custom HTTPAdapter subclasses "
- "will need to migrate for Requests>=2.32.2. Please see "
- "https://github.com/psf/requests/pull/6710 for more details."
- ),
- DeprecationWarning,
- )
- proxy = select_proxy(url, proxies)
-
- if proxy:
- proxy = prepend_scheme_if_needed(proxy, "http")
- proxy_url = parse_url(proxy)
- if not proxy_url.host:
- raise InvalidProxyURL(
- "Please check proxy URL. It is malformed "
- "and could be missing the host."
- )
- proxy_manager = self.proxy_manager_for(proxy)
- conn = proxy_manager.connection_from_url(url)
- else:
- # Only scheme should be lower case
- parsed = urlparse(url)
- url = parsed.geturl()
- conn = self.poolmanager.connection_from_url(url)
-
- return conn
-
- def close(self):
- """Disposes of any internal state.
-
- Currently, this closes the PoolManager and any active ProxyManager,
- which closes any pooled connections.
- """
- self.poolmanager.clear()
- for proxy in self.proxy_manager.values():
- proxy.clear()
-
- def request_url(self, request, proxies):
- """Obtain the url to use when making the final request.
-
- If the message is being sent through a HTTP proxy, the full URL has to
- be used. Otherwise, we should only use the path portion of the URL.
-
- This should not be called from user code, and is only exposed for use
- when subclassing the
- :class:`HTTPAdapter `.
-
- :param request: The :class:`PreparedRequest ` being sent.
- :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs.
- :rtype: str
- """
- proxy = select_proxy(request.url, proxies)
- scheme = urlparse(request.url).scheme
-
- is_proxied_http_request = proxy and scheme != "https"
- using_socks_proxy = False
- if proxy:
- proxy_scheme = urlparse(proxy).scheme.lower()
- using_socks_proxy = proxy_scheme.startswith("socks")
-
- url = request.path_url
- if url.startswith("//"): # Don't confuse urllib3
- url = f"/{url.lstrip('/')}"
-
- if is_proxied_http_request and not using_socks_proxy:
- url = urldefragauth(request.url)
-
- return url
-
- def add_headers(self, request, **kwargs):
- """Add any headers needed by the connection. As of v2.0 this does
- nothing by default, but is left for overriding by users that subclass
- the :class:`HTTPAdapter `.
-
- This should not be called from user code, and is only exposed for use
- when subclassing the
- :class:`HTTPAdapter `.
-
- :param request: The :class:`PreparedRequest ` to add headers to.
- :param kwargs: The keyword arguments from the call to send().
- """
- pass
-
- def proxy_headers(self, proxy):
- """Returns a dictionary of the headers to add to any request sent
- through a proxy. This works with urllib3 magic to ensure that they are
- correctly sent to the proxy, rather than in a tunnelled request if
- CONNECT is being used.
-
- This should not be called from user code, and is only exposed for use
- when subclassing the
- :class:`HTTPAdapter `.
-
- :param proxy: The url of the proxy being used for this request.
- :rtype: dict
- """
- headers = {}
- username, password = get_auth_from_url(proxy)
-
- if username:
- headers["Proxy-Authorization"] = _basic_auth_str(username, password)
-
- return headers
-
- def send(
- self, request, stream=False, timeout=None, verify=True, cert=None, proxies=None
- ):
- """Sends PreparedRequest object. Returns Response object.
-
- :param request: The :class:`PreparedRequest ` being sent.
- :param stream: (optional) Whether to stream the request content.
- :param timeout: (optional) How long to wait for the server to send
- data before giving up, as a float, or a :ref:`(connect timeout,
- read timeout) ` tuple.
- :type timeout: float or tuple or urllib3 Timeout object
- :param verify: (optional) Either a boolean, in which case it controls whether
- we verify the server's TLS certificate, or a string, in which case it
- must be a path to a CA bundle to use
- :param cert: (optional) Any user-provided SSL certificate to be trusted.
- :param proxies: (optional) The proxies dictionary to apply to the request.
- :rtype: requests.Response
- """
-
- try:
- conn = self.get_connection_with_tls_context(
- request, verify, proxies=proxies, cert=cert
- )
- except LocationValueError as e:
- raise InvalidURL(e, request=request)
-
- self.cert_verify(conn, request.url, verify, cert)
- url = self.request_url(request, proxies)
- self.add_headers(
- request,
- stream=stream,
- timeout=timeout,
- verify=verify,
- cert=cert,
- proxies=proxies,
- )
-
- chunked = not (request.body is None or "Content-Length" in request.headers)
-
- if isinstance(timeout, tuple):
- try:
- connect, read = timeout
- timeout = TimeoutSauce(connect=connect, read=read)
- except ValueError:
- raise ValueError(
- f"Invalid timeout {timeout}. Pass a (connect, read) timeout tuple, "
- f"or a single float to set both timeouts to the same value."
- )
- elif isinstance(timeout, TimeoutSauce):
- pass
- else:
- timeout = TimeoutSauce(connect=timeout, read=timeout)
-
- try:
- resp = conn.urlopen(
- method=request.method,
- url=url,
- body=request.body,
- headers=request.headers,
- redirect=False,
- assert_same_host=False,
- preload_content=False,
- decode_content=False,
- retries=self.max_retries,
- timeout=timeout,
- chunked=chunked,
- )
-
- except (ProtocolError, OSError) as err:
- raise ConnectionError(err, request=request)
-
- except MaxRetryError as e:
- if isinstance(e.reason, ConnectTimeoutError):
- # TODO: Remove this in 3.0.0: see #2811
- if not isinstance(e.reason, NewConnectionError):
- raise ConnectTimeout(e, request=request)
-
- if isinstance(e.reason, ResponseError):
- raise RetryError(e, request=request)
-
- if isinstance(e.reason, _ProxyError):
- raise ProxyError(e, request=request)
-
- if isinstance(e.reason, _SSLError):
- # This branch is for urllib3 v1.22 and later.
- raise SSLError(e, request=request)
-
- raise ConnectionError(e, request=request)
-
- except ClosedPoolError as e:
- raise ConnectionError(e, request=request)
-
- except _ProxyError as e:
- raise ProxyError(e)
-
- except (_SSLError, _HTTPError) as e:
- if isinstance(e, _SSLError):
- # This branch is for urllib3 versions earlier than v1.22
- raise SSLError(e, request=request)
- elif isinstance(e, ReadTimeoutError):
- raise ReadTimeout(e, request=request)
- elif isinstance(e, _InvalidHeader):
- raise InvalidHeader(e, request=request)
- else:
- raise
-
- return self.build_response(request, resp)
diff --git a/.venv/lib/python3.12/site-packages/requests/api.py b/.venv/lib/python3.12/site-packages/requests/api.py
deleted file mode 100644
index 5960744..0000000
--- a/.venv/lib/python3.12/site-packages/requests/api.py
+++ /dev/null
@@ -1,157 +0,0 @@
-"""
-requests.api
-~~~~~~~~~~~~
-
-This module implements the Requests API.
-
-:copyright: (c) 2012 by Kenneth Reitz.
-:license: Apache2, see LICENSE for more details.
-"""
-
-from . import sessions
-
-
-def request(method, url, **kwargs):
- """Constructs and sends a :class:`Request `.
-
- :param method: method for the new :class:`Request` object: ``GET``, ``OPTIONS``, ``HEAD``, ``POST``, ``PUT``, ``PATCH``, or ``DELETE``.
- :param url: URL for the new :class:`Request` object.
- :param params: (optional) Dictionary, list of tuples or bytes to send
- in the query string for the :class:`Request`.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
- :param headers: (optional) Dictionary of HTTP Headers to send with the :class:`Request`.
- :param cookies: (optional) Dict or CookieJar object to send with the :class:`Request`.
- :param files: (optional) Dictionary of ``'name': file-like-objects`` (or ``{'name': file-tuple}``) for multipart encoding upload.
- ``file-tuple`` can be a 2-tuple ``('filename', fileobj)``, 3-tuple ``('filename', fileobj, 'content_type')``
- or a 4-tuple ``('filename', fileobj, 'content_type', custom_headers)``, where ``'content_type'`` is a string
- defining the content type of the given file and ``custom_headers`` a dict-like object containing additional headers
- to add for the file.
- :param auth: (optional) Auth tuple to enable Basic/Digest/Custom HTTP Auth.
- :param timeout: (optional) How many seconds to wait for the server to send data
- before giving up, as a float, or a :ref:`(connect timeout, read
- timeout) ` tuple.
- :type timeout: float or tuple
- :param allow_redirects: (optional) Boolean. Enable/disable GET/OPTIONS/POST/PUT/PATCH/DELETE/HEAD redirection. Defaults to ``True``.
- :type allow_redirects: bool
- :param proxies: (optional) Dictionary mapping protocol to the URL of the proxy.
- :param verify: (optional) Either a boolean, in which case it controls whether we verify
- the server's TLS certificate, or a string, in which case it must be a path
- to a CA bundle to use. Defaults to ``True``.
- :param stream: (optional) if ``False``, the response content will be immediately downloaded.
- :param cert: (optional) if String, path to ssl client cert file (.pem). If Tuple, ('cert', 'key') pair.
- :return: :class:`Response ` object
- :rtype: requests.Response
-
- Usage::
-
- >>> import requests
- >>> req = requests.request('GET', 'https://httpbin.org/get')
- >>> req
-
- """
-
- # By using the 'with' statement we are sure the session is closed, thus we
- # avoid leaving sockets open which can trigger a ResourceWarning in some
- # cases, and look like a memory leak in others.
- with sessions.Session() as session:
- return session.request(method=method, url=url, **kwargs)
-
-
-def get(url, params=None, **kwargs):
- r"""Sends a GET request.
-
- :param url: URL for the new :class:`Request` object.
- :param params: (optional) Dictionary, list of tuples or bytes to send
- in the query string for the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("get", url, params=params, **kwargs)
-
-
-def options(url, **kwargs):
- r"""Sends an OPTIONS request.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("options", url, **kwargs)
-
-
-def head(url, **kwargs):
- r"""Sends a HEAD request.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes. If
- `allow_redirects` is not provided, it will be set to `False` (as
- opposed to the default :meth:`request` behavior).
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- kwargs.setdefault("allow_redirects", False)
- return request("head", url, **kwargs)
-
-
-def post(url, data=None, json=None, **kwargs):
- r"""Sends a POST request.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("post", url, data=data, json=json, **kwargs)
-
-
-def put(url, data=None, **kwargs):
- r"""Sends a PUT request.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("put", url, data=data, **kwargs)
-
-
-def patch(url, data=None, **kwargs):
- r"""Sends a PATCH request.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) A JSON serializable Python object to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("patch", url, data=data, **kwargs)
-
-
-def delete(url, **kwargs):
- r"""Sends a DELETE request.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :return: :class:`Response ` object
- :rtype: requests.Response
- """
-
- return request("delete", url, **kwargs)
diff --git a/.venv/lib/python3.12/site-packages/requests/auth.py b/.venv/lib/python3.12/site-packages/requests/auth.py
deleted file mode 100644
index 4a7ce6d..0000000
--- a/.venv/lib/python3.12/site-packages/requests/auth.py
+++ /dev/null
@@ -1,314 +0,0 @@
-"""
-requests.auth
-~~~~~~~~~~~~~
-
-This module contains the authentication handlers for Requests.
-"""
-
-import hashlib
-import os
-import re
-import threading
-import time
-import warnings
-from base64 import b64encode
-
-from ._internal_utils import to_native_string
-from .compat import basestring, str, urlparse
-from .cookies import extract_cookies_to_jar
-from .utils import parse_dict_header
-
-CONTENT_TYPE_FORM_URLENCODED = "application/x-www-form-urlencoded"
-CONTENT_TYPE_MULTI_PART = "multipart/form-data"
-
-
-def _basic_auth_str(username, password):
- """Returns a Basic Auth string."""
-
- # "I want us to put a big-ol' comment on top of it that
- # says that this behaviour is dumb but we need to preserve
- # it because people are relying on it."
- # - Lukasa
- #
- # These are here solely to maintain backwards compatibility
- # for things like ints. This will be removed in 3.0.0.
- if not isinstance(username, basestring):
- warnings.warn(
- "Non-string usernames will no longer be supported in Requests "
- "3.0.0. Please convert the object you've passed in ({!r}) to "
- "a string or bytes object in the near future to avoid "
- "problems.".format(username),
- category=DeprecationWarning,
- )
- username = str(username)
-
- if not isinstance(password, basestring):
- warnings.warn(
- "Non-string passwords will no longer be supported in Requests "
- "3.0.0. Please convert the object you've passed in ({!r}) to "
- "a string or bytes object in the near future to avoid "
- "problems.".format(type(password)),
- category=DeprecationWarning,
- )
- password = str(password)
- # -- End Removal --
-
- if isinstance(username, str):
- username = username.encode("latin1")
-
- if isinstance(password, str):
- password = password.encode("latin1")
-
- authstr = "Basic " + to_native_string(
- b64encode(b":".join((username, password))).strip()
- )
-
- return authstr
-
-
-class AuthBase:
- """Base class that all auth implementations derive from"""
-
- def __call__(self, r):
- raise NotImplementedError("Auth hooks must be callable.")
-
-
-class HTTPBasicAuth(AuthBase):
- """Attaches HTTP Basic Authentication to the given Request object."""
-
- def __init__(self, username, password):
- self.username = username
- self.password = password
-
- def __eq__(self, other):
- return all(
- [
- self.username == getattr(other, "username", None),
- self.password == getattr(other, "password", None),
- ]
- )
-
- def __ne__(self, other):
- return not self == other
-
- def __call__(self, r):
- r.headers["Authorization"] = _basic_auth_str(self.username, self.password)
- return r
-
-
-class HTTPProxyAuth(HTTPBasicAuth):
- """Attaches HTTP Proxy Authentication to a given Request object."""
-
- def __call__(self, r):
- r.headers["Proxy-Authorization"] = _basic_auth_str(self.username, self.password)
- return r
-
-
-class HTTPDigestAuth(AuthBase):
- """Attaches HTTP Digest Authentication to the given Request object."""
-
- def __init__(self, username, password):
- self.username = username
- self.password = password
- # Keep state in per-thread local storage
- self._thread_local = threading.local()
-
- def init_per_thread_state(self):
- # Ensure state is initialized just once per-thread
- if not hasattr(self._thread_local, "init"):
- self._thread_local.init = True
- self._thread_local.last_nonce = ""
- self._thread_local.nonce_count = 0
- self._thread_local.chal = {}
- self._thread_local.pos = None
- self._thread_local.num_401_calls = None
-
- def build_digest_header(self, method, url):
- """
- :rtype: str
- """
-
- realm = self._thread_local.chal["realm"]
- nonce = self._thread_local.chal["nonce"]
- qop = self._thread_local.chal.get("qop")
- algorithm = self._thread_local.chal.get("algorithm")
- opaque = self._thread_local.chal.get("opaque")
- hash_utf8 = None
-
- if algorithm is None:
- _algorithm = "MD5"
- else:
- _algorithm = algorithm.upper()
- # lambdas assume digest modules are imported at the top level
- if _algorithm == "MD5" or _algorithm == "MD5-SESS":
-
- def md5_utf8(x):
- if isinstance(x, str):
- x = x.encode("utf-8")
- return hashlib.md5(x).hexdigest()
-
- hash_utf8 = md5_utf8
- elif _algorithm == "SHA":
-
- def sha_utf8(x):
- if isinstance(x, str):
- x = x.encode("utf-8")
- return hashlib.sha1(x).hexdigest()
-
- hash_utf8 = sha_utf8
- elif _algorithm == "SHA-256":
-
- def sha256_utf8(x):
- if isinstance(x, str):
- x = x.encode("utf-8")
- return hashlib.sha256(x).hexdigest()
-
- hash_utf8 = sha256_utf8
- elif _algorithm == "SHA-512":
-
- def sha512_utf8(x):
- if isinstance(x, str):
- x = x.encode("utf-8")
- return hashlib.sha512(x).hexdigest()
-
- hash_utf8 = sha512_utf8
-
- KD = lambda s, d: hash_utf8(f"{s}:{d}") # noqa:E731
-
- if hash_utf8 is None:
- return None
-
- # XXX not implemented yet
- entdig = None
- p_parsed = urlparse(url)
- #: path is request-uri defined in RFC 2616 which should not be empty
- path = p_parsed.path or "/"
- if p_parsed.query:
- path += f"?{p_parsed.query}"
-
- A1 = f"{self.username}:{realm}:{self.password}"
- A2 = f"{method}:{path}"
-
- HA1 = hash_utf8(A1)
- HA2 = hash_utf8(A2)
-
- if nonce == self._thread_local.last_nonce:
- self._thread_local.nonce_count += 1
- else:
- self._thread_local.nonce_count = 1
- ncvalue = f"{self._thread_local.nonce_count:08x}"
- s = str(self._thread_local.nonce_count).encode("utf-8")
- s += nonce.encode("utf-8")
- s += time.ctime().encode("utf-8")
- s += os.urandom(8)
-
- cnonce = hashlib.sha1(s).hexdigest()[:16]
- if _algorithm == "MD5-SESS":
- HA1 = hash_utf8(f"{HA1}:{nonce}:{cnonce}")
-
- if not qop:
- respdig = KD(HA1, f"{nonce}:{HA2}")
- elif qop == "auth" or "auth" in qop.split(","):
- noncebit = f"{nonce}:{ncvalue}:{cnonce}:auth:{HA2}"
- respdig = KD(HA1, noncebit)
- else:
- # XXX handle auth-int.
- return None
-
- self._thread_local.last_nonce = nonce
-
- # XXX should the partial digests be encoded too?
- base = (
- f'username="{self.username}", realm="{realm}", nonce="{nonce}", '
- f'uri="{path}", response="{respdig}"'
- )
- if opaque:
- base += f', opaque="{opaque}"'
- if algorithm:
- base += f', algorithm="{algorithm}"'
- if entdig:
- base += f', digest="{entdig}"'
- if qop:
- base += f', qop="auth", nc={ncvalue}, cnonce="{cnonce}"'
-
- return f"Digest {base}"
-
- def handle_redirect(self, r, **kwargs):
- """Reset num_401_calls counter on redirects."""
- if r.is_redirect:
- self._thread_local.num_401_calls = 1
-
- def handle_401(self, r, **kwargs):
- """
- Takes the given response and tries digest-auth, if needed.
-
- :rtype: requests.Response
- """
-
- # If response is not 4xx, do not auth
- # See https://github.com/psf/requests/issues/3772
- if not 400 <= r.status_code < 500:
- self._thread_local.num_401_calls = 1
- return r
-
- if self._thread_local.pos is not None:
- # Rewind the file position indicator of the body to where
- # it was to resend the request.
- r.request.body.seek(self._thread_local.pos)
- s_auth = r.headers.get("www-authenticate", "")
-
- if "digest" in s_auth.lower() and self._thread_local.num_401_calls < 2:
- self._thread_local.num_401_calls += 1
- pat = re.compile(r"digest ", flags=re.IGNORECASE)
- self._thread_local.chal = parse_dict_header(pat.sub("", s_auth, count=1))
-
- # Consume content and release the original connection
- # to allow our new request to reuse the same one.
- r.content
- r.close()
- prep = r.request.copy()
- extract_cookies_to_jar(prep._cookies, r.request, r.raw)
- prep.prepare_cookies(prep._cookies)
-
- prep.headers["Authorization"] = self.build_digest_header(
- prep.method, prep.url
- )
- _r = r.connection.send(prep, **kwargs)
- _r.history.append(r)
- _r.request = prep
-
- return _r
-
- self._thread_local.num_401_calls = 1
- return r
-
- def __call__(self, r):
- # Initialize per-thread state, if needed
- self.init_per_thread_state()
- # If we have a saved nonce, skip the 401
- if self._thread_local.last_nonce:
- r.headers["Authorization"] = self.build_digest_header(r.method, r.url)
- try:
- self._thread_local.pos = r.body.tell()
- except AttributeError:
- # In the case of HTTPDigestAuth being reused and the body of
- # the previous request was a file-like object, pos has the
- # file position of the previous body. Ensure it's set to
- # None.
- self._thread_local.pos = None
- r.register_hook("response", self.handle_401)
- r.register_hook("response", self.handle_redirect)
- self._thread_local.num_401_calls = 1
-
- return r
-
- def __eq__(self, other):
- return all(
- [
- self.username == getattr(other, "username", None),
- self.password == getattr(other, "password", None),
- ]
- )
-
- def __ne__(self, other):
- return not self == other
diff --git a/.venv/lib/python3.12/site-packages/requests/certs.py b/.venv/lib/python3.12/site-packages/requests/certs.py
deleted file mode 100644
index be422c3..0000000
--- a/.venv/lib/python3.12/site-packages/requests/certs.py
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/usr/bin/env python
-
-"""
-requests.certs
-~~~~~~~~~~~~~~
-
-This module returns the preferred default CA certificate bundle. There is
-only one — the one from the certifi package.
-
-If you are packaging Requests, e.g., for a Linux distribution or a managed
-environment, you can change the definition of where() to return a separately
-packaged CA bundle.
-"""
-from certifi import where
-
-if __name__ == "__main__":
- print(where())
diff --git a/.venv/lib/python3.12/site-packages/requests/compat.py b/.venv/lib/python3.12/site-packages/requests/compat.py
deleted file mode 100644
index 095de1b..0000000
--- a/.venv/lib/python3.12/site-packages/requests/compat.py
+++ /dev/null
@@ -1,94 +0,0 @@
-"""
-requests.compat
-~~~~~~~~~~~~~~~
-
-This module previously handled import compatibility issues
-between Python 2 and Python 3. It remains for backwards
-compatibility until the next major version.
-"""
-
-import importlib
-import sys
-
-# -------------------
-# Character Detection
-# -------------------
-
-
-def _resolve_char_detection():
- """Find supported character detection libraries."""
- chardet = None
- for lib in ("chardet", "charset_normalizer"):
- if chardet is None:
- try:
- chardet = importlib.import_module(lib)
- except ImportError:
- pass
- return chardet
-
-
-chardet = _resolve_char_detection()
-
-# -------
-# Pythons
-# -------
-
-# Syntax sugar.
-_ver = sys.version_info
-
-#: Python 2.x?
-is_py2 = _ver[0] == 2
-
-#: Python 3.x?
-is_py3 = _ver[0] == 3
-
-# json/simplejson module import resolution
-has_simplejson = False
-try:
- import simplejson as json
-
- has_simplejson = True
-except ImportError:
- import json
-
-if has_simplejson:
- from simplejson import JSONDecodeError
-else:
- from json import JSONDecodeError
-
-# Keep OrderedDict for backwards compatibility.
-from collections import OrderedDict
-from collections.abc import Callable, Mapping, MutableMapping
-from http import cookiejar as cookielib
-from http.cookies import Morsel
-from io import StringIO
-
-# --------------
-# Legacy Imports
-# --------------
-from urllib.parse import (
- quote,
- quote_plus,
- unquote,
- unquote_plus,
- urldefrag,
- urlencode,
- urljoin,
- urlparse,
- urlsplit,
- urlunparse,
-)
-from urllib.request import (
- getproxies,
- getproxies_environment,
- parse_http_list,
- proxy_bypass,
- proxy_bypass_environment,
-)
-
-builtin_str = str
-str = str
-bytes = bytes
-basestring = (str, bytes)
-numeric_types = (int, float)
-integer_types = (int,)
diff --git a/.venv/lib/python3.12/site-packages/requests/cookies.py b/.venv/lib/python3.12/site-packages/requests/cookies.py
deleted file mode 100644
index f69d0cd..0000000
--- a/.venv/lib/python3.12/site-packages/requests/cookies.py
+++ /dev/null
@@ -1,561 +0,0 @@
-"""
-requests.cookies
-~~~~~~~~~~~~~~~~
-
-Compatibility code to be able to use `http.cookiejar.CookieJar` with requests.
-
-requests.utils imports from here, so be careful with imports.
-"""
-
-import calendar
-import copy
-import time
-
-from ._internal_utils import to_native_string
-from .compat import Morsel, MutableMapping, cookielib, urlparse, urlunparse
-
-try:
- import threading
-except ImportError:
- import dummy_threading as threading
-
-
-class MockRequest:
- """Wraps a `requests.Request` to mimic a `urllib2.Request`.
-
- The code in `http.cookiejar.CookieJar` expects this interface in order to correctly
- manage cookie policies, i.e., determine whether a cookie can be set, given the
- domains of the request and the cookie.
-
- The original request object is read-only. The client is responsible for collecting
- the new headers via `get_new_headers()` and interpreting them appropriately. You
- probably want `get_cookie_header`, defined below.
- """
-
- def __init__(self, request):
- self._r = request
- self._new_headers = {}
- self.type = urlparse(self._r.url).scheme
-
- def get_type(self):
- return self.type
-
- def get_host(self):
- return urlparse(self._r.url).netloc
-
- def get_origin_req_host(self):
- return self.get_host()
-
- def get_full_url(self):
- # Only return the response's URL if the user hadn't set the Host
- # header
- if not self._r.headers.get("Host"):
- return self._r.url
- # If they did set it, retrieve it and reconstruct the expected domain
- host = to_native_string(self._r.headers["Host"], encoding="utf-8")
- parsed = urlparse(self._r.url)
- # Reconstruct the URL as we expect it
- return urlunparse(
- [
- parsed.scheme,
- host,
- parsed.path,
- parsed.params,
- parsed.query,
- parsed.fragment,
- ]
- )
-
- def is_unverifiable(self):
- return True
-
- def has_header(self, name):
- return name in self._r.headers or name in self._new_headers
-
- def get_header(self, name, default=None):
- return self._r.headers.get(name, self._new_headers.get(name, default))
-
- def add_header(self, key, val):
- """cookiejar has no legitimate use for this method; add it back if you find one."""
- raise NotImplementedError(
- "Cookie headers should be added with add_unredirected_header()"
- )
-
- def add_unredirected_header(self, name, value):
- self._new_headers[name] = value
-
- def get_new_headers(self):
- return self._new_headers
-
- @property
- def unverifiable(self):
- return self.is_unverifiable()
-
- @property
- def origin_req_host(self):
- return self.get_origin_req_host()
-
- @property
- def host(self):
- return self.get_host()
-
-
-class MockResponse:
- """Wraps a `httplib.HTTPMessage` to mimic a `urllib.addinfourl`.
-
- ...what? Basically, expose the parsed HTTP headers from the server response
- the way `http.cookiejar` expects to see them.
- """
-
- def __init__(self, headers):
- """Make a MockResponse for `cookiejar` to read.
-
- :param headers: a httplib.HTTPMessage or analogous carrying the headers
- """
- self._headers = headers
-
- def info(self):
- return self._headers
-
- def getheaders(self, name):
- self._headers.getheaders(name)
-
-
-def extract_cookies_to_jar(jar, request, response):
- """Extract the cookies from the response into a CookieJar.
-
- :param jar: http.cookiejar.CookieJar (not necessarily a RequestsCookieJar)
- :param request: our own requests.Request object
- :param response: urllib3.HTTPResponse object
- """
- if not (hasattr(response, "_original_response") and response._original_response):
- return
- # the _original_response field is the wrapped httplib.HTTPResponse object,
- req = MockRequest(request)
- # pull out the HTTPMessage with the headers and put it in the mock:
- res = MockResponse(response._original_response.msg)
- jar.extract_cookies(res, req)
-
-
-def get_cookie_header(jar, request):
- """
- Produce an appropriate Cookie header string to be sent with `request`, or None.
-
- :rtype: str
- """
- r = MockRequest(request)
- jar.add_cookie_header(r)
- return r.get_new_headers().get("Cookie")
-
-
-def remove_cookie_by_name(cookiejar, name, domain=None, path=None):
- """Unsets a cookie by name, by default over all domains and paths.
-
- Wraps CookieJar.clear(), is O(n).
- """
- clearables = []
- for cookie in cookiejar:
- if cookie.name != name:
- continue
- if domain is not None and domain != cookie.domain:
- continue
- if path is not None and path != cookie.path:
- continue
- clearables.append((cookie.domain, cookie.path, cookie.name))
-
- for domain, path, name in clearables:
- cookiejar.clear(domain, path, name)
-
-
-class CookieConflictError(RuntimeError):
- """There are two cookies that meet the criteria specified in the cookie jar.
- Use .get and .set and include domain and path args in order to be more specific.
- """
-
-
-class RequestsCookieJar(cookielib.CookieJar, MutableMapping):
- """Compatibility class; is a http.cookiejar.CookieJar, but exposes a dict
- interface.
-
- This is the CookieJar we create by default for requests and sessions that
- don't specify one, since some clients may expect response.cookies and
- session.cookies to support dict operations.
-
- Requests does not use the dict interface internally; it's just for
- compatibility with external client code. All requests code should work
- out of the box with externally provided instances of ``CookieJar``, e.g.
- ``LWPCookieJar`` and ``FileCookieJar``.
-
- Unlike a regular CookieJar, this class is pickleable.
-
- .. warning:: dictionary operations that are normally O(1) may be O(n).
- """
-
- def get(self, name, default=None, domain=None, path=None):
- """Dict-like get() that also supports optional domain and path args in
- order to resolve naming collisions from using one cookie jar over
- multiple domains.
-
- .. warning:: operation is O(n), not O(1).
- """
- try:
- return self._find_no_duplicates(name, domain, path)
- except KeyError:
- return default
-
- def set(self, name, value, **kwargs):
- """Dict-like set() that also supports optional domain and path args in
- order to resolve naming collisions from using one cookie jar over
- multiple domains.
- """
- # support client code that unsets cookies by assignment of a None value:
- if value is None:
- remove_cookie_by_name(
- self, name, domain=kwargs.get("domain"), path=kwargs.get("path")
- )
- return
-
- if isinstance(value, Morsel):
- c = morsel_to_cookie(value)
- else:
- c = create_cookie(name, value, **kwargs)
- self.set_cookie(c)
- return c
-
- def iterkeys(self):
- """Dict-like iterkeys() that returns an iterator of names of cookies
- from the jar.
-
- .. seealso:: itervalues() and iteritems().
- """
- for cookie in iter(self):
- yield cookie.name
-
- def keys(self):
- """Dict-like keys() that returns a list of names of cookies from the
- jar.
-
- .. seealso:: values() and items().
- """
- return list(self.iterkeys())
-
- def itervalues(self):
- """Dict-like itervalues() that returns an iterator of values of cookies
- from the jar.
-
- .. seealso:: iterkeys() and iteritems().
- """
- for cookie in iter(self):
- yield cookie.value
-
- def values(self):
- """Dict-like values() that returns a list of values of cookies from the
- jar.
-
- .. seealso:: keys() and items().
- """
- return list(self.itervalues())
-
- def iteritems(self):
- """Dict-like iteritems() that returns an iterator of name-value tuples
- from the jar.
-
- .. seealso:: iterkeys() and itervalues().
- """
- for cookie in iter(self):
- yield cookie.name, cookie.value
-
- def items(self):
- """Dict-like items() that returns a list of name-value tuples from the
- jar. Allows client-code to call ``dict(RequestsCookieJar)`` and get a
- vanilla python dict of key value pairs.
-
- .. seealso:: keys() and values().
- """
- return list(self.iteritems())
-
- def list_domains(self):
- """Utility method to list all the domains in the jar."""
- domains = []
- for cookie in iter(self):
- if cookie.domain not in domains:
- domains.append(cookie.domain)
- return domains
-
- def list_paths(self):
- """Utility method to list all the paths in the jar."""
- paths = []
- for cookie in iter(self):
- if cookie.path not in paths:
- paths.append(cookie.path)
- return paths
-
- def multiple_domains(self):
- """Returns True if there are multiple domains in the jar.
- Returns False otherwise.
-
- :rtype: bool
- """
- domains = []
- for cookie in iter(self):
- if cookie.domain is not None and cookie.domain in domains:
- return True
- domains.append(cookie.domain)
- return False # there is only one domain in jar
-
- def get_dict(self, domain=None, path=None):
- """Takes as an argument an optional domain and path and returns a plain
- old Python dict of name-value pairs of cookies that meet the
- requirements.
-
- :rtype: dict
- """
- dictionary = {}
- for cookie in iter(self):
- if (domain is None or cookie.domain == domain) and (
- path is None or cookie.path == path
- ):
- dictionary[cookie.name] = cookie.value
- return dictionary
-
- def __contains__(self, name):
- try:
- return super().__contains__(name)
- except CookieConflictError:
- return True
-
- def __getitem__(self, name):
- """Dict-like __getitem__() for compatibility with client code. Throws
- exception if there are more than one cookie with name. In that case,
- use the more explicit get() method instead.
-
- .. warning:: operation is O(n), not O(1).
- """
- return self._find_no_duplicates(name)
-
- def __setitem__(self, name, value):
- """Dict-like __setitem__ for compatibility with client code. Throws
- exception if there is already a cookie of that name in the jar. In that
- case, use the more explicit set() method instead.
- """
- self.set(name, value)
-
- def __delitem__(self, name):
- """Deletes a cookie given a name. Wraps ``http.cookiejar.CookieJar``'s
- ``remove_cookie_by_name()``.
- """
- remove_cookie_by_name(self, name)
-
- def set_cookie(self, cookie, *args, **kwargs):
- if (
- hasattr(cookie.value, "startswith")
- and cookie.value.startswith('"')
- and cookie.value.endswith('"')
- ):
- cookie.value = cookie.value.replace('\\"', "")
- return super().set_cookie(cookie, *args, **kwargs)
-
- def update(self, other):
- """Updates this jar with cookies from another CookieJar or dict-like"""
- if isinstance(other, cookielib.CookieJar):
- for cookie in other:
- self.set_cookie(copy.copy(cookie))
- else:
- super().update(other)
-
- def _find(self, name, domain=None, path=None):
- """Requests uses this method internally to get cookie values.
-
- If there are conflicting cookies, _find arbitrarily chooses one.
- See _find_no_duplicates if you want an exception thrown if there are
- conflicting cookies.
-
- :param name: a string containing name of cookie
- :param domain: (optional) string containing domain of cookie
- :param path: (optional) string containing path of cookie
- :return: cookie.value
- """
- for cookie in iter(self):
- if cookie.name == name:
- if domain is None or cookie.domain == domain:
- if path is None or cookie.path == path:
- return cookie.value
-
- raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
-
- def _find_no_duplicates(self, name, domain=None, path=None):
- """Both ``__get_item__`` and ``get`` call this function: it's never
- used elsewhere in Requests.
-
- :param name: a string containing name of cookie
- :param domain: (optional) string containing domain of cookie
- :param path: (optional) string containing path of cookie
- :raises KeyError: if cookie is not found
- :raises CookieConflictError: if there are multiple cookies
- that match name and optionally domain and path
- :return: cookie.value
- """
- toReturn = None
- for cookie in iter(self):
- if cookie.name == name:
- if domain is None or cookie.domain == domain:
- if path is None or cookie.path == path:
- if toReturn is not None:
- # if there are multiple cookies that meet passed in criteria
- raise CookieConflictError(
- f"There are multiple cookies with name, {name!r}"
- )
- # we will eventually return this as long as no cookie conflict
- toReturn = cookie.value
-
- if toReturn:
- return toReturn
- raise KeyError(f"name={name!r}, domain={domain!r}, path={path!r}")
-
- def __getstate__(self):
- """Unlike a normal CookieJar, this class is pickleable."""
- state = self.__dict__.copy()
- # remove the unpickleable RLock object
- state.pop("_cookies_lock")
- return state
-
- def __setstate__(self, state):
- """Unlike a normal CookieJar, this class is pickleable."""
- self.__dict__.update(state)
- if "_cookies_lock" not in self.__dict__:
- self._cookies_lock = threading.RLock()
-
- def copy(self):
- """Return a copy of this RequestsCookieJar."""
- new_cj = RequestsCookieJar()
- new_cj.set_policy(self.get_policy())
- new_cj.update(self)
- return new_cj
-
- def get_policy(self):
- """Return the CookiePolicy instance used."""
- return self._policy
-
-
-def _copy_cookie_jar(jar):
- if jar is None:
- return None
-
- if hasattr(jar, "copy"):
- # We're dealing with an instance of RequestsCookieJar
- return jar.copy()
- # We're dealing with a generic CookieJar instance
- new_jar = copy.copy(jar)
- new_jar.clear()
- for cookie in jar:
- new_jar.set_cookie(copy.copy(cookie))
- return new_jar
-
-
-def create_cookie(name, value, **kwargs):
- """Make a cookie from underspecified parameters.
-
- By default, the pair of `name` and `value` will be set for the domain ''
- and sent on every request (this is sometimes called a "supercookie").
- """
- result = {
- "version": 0,
- "name": name,
- "value": value,
- "port": None,
- "domain": "",
- "path": "/",
- "secure": False,
- "expires": None,
- "discard": True,
- "comment": None,
- "comment_url": None,
- "rest": {"HttpOnly": None},
- "rfc2109": False,
- }
-
- badargs = set(kwargs) - set(result)
- if badargs:
- raise TypeError(
- f"create_cookie() got unexpected keyword arguments: {list(badargs)}"
- )
-
- result.update(kwargs)
- result["port_specified"] = bool(result["port"])
- result["domain_specified"] = bool(result["domain"])
- result["domain_initial_dot"] = result["domain"].startswith(".")
- result["path_specified"] = bool(result["path"])
-
- return cookielib.Cookie(**result)
-
-
-def morsel_to_cookie(morsel):
- """Convert a Morsel object into a Cookie containing the one k/v pair."""
-
- expires = None
- if morsel["max-age"]:
- try:
- expires = int(time.time() + int(morsel["max-age"]))
- except ValueError:
- raise TypeError(f"max-age: {morsel['max-age']} must be integer")
- elif morsel["expires"]:
- time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
- expires = calendar.timegm(time.strptime(morsel["expires"], time_template))
- return create_cookie(
- comment=morsel["comment"],
- comment_url=bool(morsel["comment"]),
- discard=False,
- domain=morsel["domain"],
- expires=expires,
- name=morsel.key,
- path=morsel["path"],
- port=None,
- rest={"HttpOnly": morsel["httponly"]},
- rfc2109=False,
- secure=bool(morsel["secure"]),
- value=morsel.value,
- version=morsel["version"] or 0,
- )
-
-
-def cookiejar_from_dict(cookie_dict, cookiejar=None, overwrite=True):
- """Returns a CookieJar from a key/value dictionary.
-
- :param cookie_dict: Dict of key/values to insert into CookieJar.
- :param cookiejar: (optional) A cookiejar to add the cookies to.
- :param overwrite: (optional) If False, will not replace cookies
- already in the jar with new ones.
- :rtype: CookieJar
- """
- if cookiejar is None:
- cookiejar = RequestsCookieJar()
-
- if cookie_dict is not None:
- names_from_jar = [cookie.name for cookie in cookiejar]
- for name in cookie_dict:
- if overwrite or (name not in names_from_jar):
- cookiejar.set_cookie(create_cookie(name, cookie_dict[name]))
-
- return cookiejar
-
-
-def merge_cookies(cookiejar, cookies):
- """Add cookies to cookiejar and returns a merged CookieJar.
-
- :param cookiejar: CookieJar object to add the cookies to.
- :param cookies: Dictionary or CookieJar object to be added.
- :rtype: CookieJar
- """
- if not isinstance(cookiejar, cookielib.CookieJar):
- raise ValueError("You can only merge into CookieJar")
-
- if isinstance(cookies, dict):
- cookiejar = cookiejar_from_dict(cookies, cookiejar=cookiejar, overwrite=False)
- elif isinstance(cookies, cookielib.CookieJar):
- try:
- cookiejar.update(cookies)
- except AttributeError:
- for cookie_in_jar in cookies:
- cookiejar.set_cookie(cookie_in_jar)
-
- return cookiejar
diff --git a/.venv/lib/python3.12/site-packages/requests/exceptions.py b/.venv/lib/python3.12/site-packages/requests/exceptions.py
deleted file mode 100644
index 83986b4..0000000
--- a/.venv/lib/python3.12/site-packages/requests/exceptions.py
+++ /dev/null
@@ -1,151 +0,0 @@
-"""
-requests.exceptions
-~~~~~~~~~~~~~~~~~~~
-
-This module contains the set of Requests' exceptions.
-"""
-from urllib3.exceptions import HTTPError as BaseHTTPError
-
-from .compat import JSONDecodeError as CompatJSONDecodeError
-
-
-class RequestException(IOError):
- """There was an ambiguous exception that occurred while handling your
- request.
- """
-
- def __init__(self, *args, **kwargs):
- """Initialize RequestException with `request` and `response` objects."""
- response = kwargs.pop("response", None)
- self.response = response
- self.request = kwargs.pop("request", None)
- if response is not None and not self.request and hasattr(response, "request"):
- self.request = self.response.request
- super().__init__(*args, **kwargs)
-
-
-class InvalidJSONError(RequestException):
- """A JSON error occurred."""
-
-
-class JSONDecodeError(InvalidJSONError, CompatJSONDecodeError):
- """Couldn't decode the text into json"""
-
- def __init__(self, *args, **kwargs):
- """
- Construct the JSONDecodeError instance first with all
- args. Then use it's args to construct the IOError so that
- the json specific args aren't used as IOError specific args
- and the error message from JSONDecodeError is preserved.
- """
- CompatJSONDecodeError.__init__(self, *args)
- InvalidJSONError.__init__(self, *self.args, **kwargs)
-
- def __reduce__(self):
- """
- The __reduce__ method called when pickling the object must
- be the one from the JSONDecodeError (be it json/simplejson)
- as it expects all the arguments for instantiation, not just
- one like the IOError, and the MRO would by default call the
- __reduce__ method from the IOError due to the inheritance order.
- """
- return CompatJSONDecodeError.__reduce__(self)
-
-
-class HTTPError(RequestException):
- """An HTTP error occurred."""
-
-
-class ConnectionError(RequestException):
- """A Connection error occurred."""
-
-
-class ProxyError(ConnectionError):
- """A proxy error occurred."""
-
-
-class SSLError(ConnectionError):
- """An SSL error occurred."""
-
-
-class Timeout(RequestException):
- """The request timed out.
-
- Catching this error will catch both
- :exc:`~requests.exceptions.ConnectTimeout` and
- :exc:`~requests.exceptions.ReadTimeout` errors.
- """
-
-
-class ConnectTimeout(ConnectionError, Timeout):
- """The request timed out while trying to connect to the remote server.
-
- Requests that produced this error are safe to retry.
- """
-
-
-class ReadTimeout(Timeout):
- """The server did not send any data in the allotted amount of time."""
-
-
-class URLRequired(RequestException):
- """A valid URL is required to make a request."""
-
-
-class TooManyRedirects(RequestException):
- """Too many redirects."""
-
-
-class MissingSchema(RequestException, ValueError):
- """The URL scheme (e.g. http or https) is missing."""
-
-
-class InvalidSchema(RequestException, ValueError):
- """The URL scheme provided is either invalid or unsupported."""
-
-
-class InvalidURL(RequestException, ValueError):
- """The URL provided was somehow invalid."""
-
-
-class InvalidHeader(RequestException, ValueError):
- """The header value provided was somehow invalid."""
-
-
-class InvalidProxyURL(InvalidURL):
- """The proxy URL provided is invalid."""
-
-
-class ChunkedEncodingError(RequestException):
- """The server declared chunked encoding but sent an invalid chunk."""
-
-
-class ContentDecodingError(RequestException, BaseHTTPError):
- """Failed to decode response content."""
-
-
-class StreamConsumedError(RequestException, TypeError):
- """The content for this response was already consumed."""
-
-
-class RetryError(RequestException):
- """Custom retries logic failed"""
-
-
-class UnrewindableBodyError(RequestException):
- """Requests encountered an error when trying to rewind a body."""
-
-
-# Warnings
-
-
-class RequestsWarning(Warning):
- """Base warning for Requests."""
-
-
-class FileModeWarning(RequestsWarning, DeprecationWarning):
- """A file was opened in text mode, but Requests determined its binary length."""
-
-
-class RequestsDependencyWarning(RequestsWarning):
- """An imported dependency doesn't match the expected version range."""
diff --git a/.venv/lib/python3.12/site-packages/requests/help.py b/.venv/lib/python3.12/site-packages/requests/help.py
deleted file mode 100644
index 8fbcd65..0000000
--- a/.venv/lib/python3.12/site-packages/requests/help.py
+++ /dev/null
@@ -1,134 +0,0 @@
-"""Module containing bug report helper(s)."""
-
-import json
-import platform
-import ssl
-import sys
-
-import idna
-import urllib3
-
-from . import __version__ as requests_version
-
-try:
- import charset_normalizer
-except ImportError:
- charset_normalizer = None
-
-try:
- import chardet
-except ImportError:
- chardet = None
-
-try:
- from urllib3.contrib import pyopenssl
-except ImportError:
- pyopenssl = None
- OpenSSL = None
- cryptography = None
-else:
- import cryptography
- import OpenSSL
-
-
-def _implementation():
- """Return a dict with the Python implementation and version.
-
- Provide both the name and the version of the Python implementation
- currently running. For example, on CPython 3.10.3 it will return
- {'name': 'CPython', 'version': '3.10.3'}.
-
- This function works best on CPython and PyPy: in particular, it probably
- doesn't work for Jython or IronPython. Future investigation should be done
- to work out the correct shape of the code for those platforms.
- """
- implementation = platform.python_implementation()
-
- if implementation == "CPython":
- implementation_version = platform.python_version()
- elif implementation == "PyPy":
- implementation_version = "{}.{}.{}".format(
- sys.pypy_version_info.major,
- sys.pypy_version_info.minor,
- sys.pypy_version_info.micro,
- )
- if sys.pypy_version_info.releaselevel != "final":
- implementation_version = "".join(
- [implementation_version, sys.pypy_version_info.releaselevel]
- )
- elif implementation == "Jython":
- implementation_version = platform.python_version() # Complete Guess
- elif implementation == "IronPython":
- implementation_version = platform.python_version() # Complete Guess
- else:
- implementation_version = "Unknown"
-
- return {"name": implementation, "version": implementation_version}
-
-
-def info():
- """Generate information for a bug report."""
- try:
- platform_info = {
- "system": platform.system(),
- "release": platform.release(),
- }
- except OSError:
- platform_info = {
- "system": "Unknown",
- "release": "Unknown",
- }
-
- implementation_info = _implementation()
- urllib3_info = {"version": urllib3.__version__}
- charset_normalizer_info = {"version": None}
- chardet_info = {"version": None}
- if charset_normalizer:
- charset_normalizer_info = {"version": charset_normalizer.__version__}
- if chardet:
- chardet_info = {"version": chardet.__version__}
-
- pyopenssl_info = {
- "version": None,
- "openssl_version": "",
- }
- if OpenSSL:
- pyopenssl_info = {
- "version": OpenSSL.__version__,
- "openssl_version": f"{OpenSSL.SSL.OPENSSL_VERSION_NUMBER:x}",
- }
- cryptography_info = {
- "version": getattr(cryptography, "__version__", ""),
- }
- idna_info = {
- "version": getattr(idna, "__version__", ""),
- }
-
- system_ssl = ssl.OPENSSL_VERSION_NUMBER
- system_ssl_info = {"version": f"{system_ssl:x}" if system_ssl is not None else ""}
-
- return {
- "platform": platform_info,
- "implementation": implementation_info,
- "system_ssl": system_ssl_info,
- "using_pyopenssl": pyopenssl is not None,
- "using_charset_normalizer": chardet is None,
- "pyOpenSSL": pyopenssl_info,
- "urllib3": urllib3_info,
- "chardet": chardet_info,
- "charset_normalizer": charset_normalizer_info,
- "cryptography": cryptography_info,
- "idna": idna_info,
- "requests": {
- "version": requests_version,
- },
- }
-
-
-def main():
- """Pretty-print the bug information as JSON."""
- print(json.dumps(info(), sort_keys=True, indent=2))
-
-
-if __name__ == "__main__":
- main()
diff --git a/.venv/lib/python3.12/site-packages/requests/hooks.py b/.venv/lib/python3.12/site-packages/requests/hooks.py
deleted file mode 100644
index d181ba2..0000000
--- a/.venv/lib/python3.12/site-packages/requests/hooks.py
+++ /dev/null
@@ -1,33 +0,0 @@
-"""
-requests.hooks
-~~~~~~~~~~~~~~
-
-This module provides the capabilities for the Requests hooks system.
-
-Available hooks:
-
-``response``:
- The response generated from a Request.
-"""
-HOOKS = ["response"]
-
-
-def default_hooks():
- return {event: [] for event in HOOKS}
-
-
-# TODO: response is the only one
-
-
-def dispatch_hook(key, hooks, hook_data, **kwargs):
- """Dispatches a hook dictionary on a given piece of data."""
- hooks = hooks or {}
- hooks = hooks.get(key)
- if hooks:
- if hasattr(hooks, "__call__"):
- hooks = [hooks]
- for hook in hooks:
- _hook_data = hook(hook_data, **kwargs)
- if _hook_data is not None:
- hook_data = _hook_data
- return hook_data
diff --git a/.venv/lib/python3.12/site-packages/requests/models.py b/.venv/lib/python3.12/site-packages/requests/models.py
deleted file mode 100644
index 8f56ca7..0000000
--- a/.venv/lib/python3.12/site-packages/requests/models.py
+++ /dev/null
@@ -1,1037 +0,0 @@
-"""
-requests.models
-~~~~~~~~~~~~~~~
-
-This module contains the primary objects that power Requests.
-"""
-
-import datetime
-
-# Import encoding now, to avoid implicit import later.
-# Implicit import within threads may cause LookupError when standard library is in a ZIP,
-# such as in Embedded Python. See https://github.com/psf/requests/issues/3578.
-import encodings.idna # noqa: F401
-from io import UnsupportedOperation
-
-from urllib3.exceptions import (
- DecodeError,
- LocationParseError,
- ProtocolError,
- ReadTimeoutError,
- SSLError,
-)
-from urllib3.fields import RequestField
-from urllib3.filepost import encode_multipart_formdata
-from urllib3.util import parse_url
-
-from ._internal_utils import to_native_string, unicode_is_ascii
-from .auth import HTTPBasicAuth
-from .compat import (
- Callable,
- JSONDecodeError,
- Mapping,
- basestring,
- builtin_str,
- chardet,
- cookielib,
-)
-from .compat import json as complexjson
-from .compat import urlencode, urlsplit, urlunparse
-from .cookies import _copy_cookie_jar, cookiejar_from_dict, get_cookie_header
-from .exceptions import (
- ChunkedEncodingError,
- ConnectionError,
- ContentDecodingError,
- HTTPError,
- InvalidJSONError,
- InvalidURL,
-)
-from .exceptions import JSONDecodeError as RequestsJSONDecodeError
-from .exceptions import MissingSchema
-from .exceptions import SSLError as RequestsSSLError
-from .exceptions import StreamConsumedError
-from .hooks import default_hooks
-from .status_codes import codes
-from .structures import CaseInsensitiveDict
-from .utils import (
- check_header_validity,
- get_auth_from_url,
- guess_filename,
- guess_json_utf,
- iter_slices,
- parse_header_links,
- requote_uri,
- stream_decode_response_unicode,
- super_len,
- to_key_val_list,
-)
-
-#: The set of HTTP status codes that indicate an automatically
-#: processable redirect.
-REDIRECT_STATI = (
- codes.moved, # 301
- codes.found, # 302
- codes.other, # 303
- codes.temporary_redirect, # 307
- codes.permanent_redirect, # 308
-)
-
-DEFAULT_REDIRECT_LIMIT = 30
-CONTENT_CHUNK_SIZE = 10 * 1024
-ITER_CHUNK_SIZE = 512
-
-
-class RequestEncodingMixin:
- @property
- def path_url(self):
- """Build the path URL to use."""
-
- url = []
-
- p = urlsplit(self.url)
-
- path = p.path
- if not path:
- path = "/"
-
- url.append(path)
-
- query = p.query
- if query:
- url.append("?")
- url.append(query)
-
- return "".join(url)
-
- @staticmethod
- def _encode_params(data):
- """Encode parameters in a piece of data.
-
- Will successfully encode parameters when passed as a dict or a list of
- 2-tuples. Order is retained if data is a list of 2-tuples but arbitrary
- if parameters are supplied as a dict.
- """
-
- if isinstance(data, (str, bytes)):
- return data
- elif hasattr(data, "read"):
- return data
- elif hasattr(data, "__iter__"):
- result = []
- for k, vs in to_key_val_list(data):
- if isinstance(vs, basestring) or not hasattr(vs, "__iter__"):
- vs = [vs]
- for v in vs:
- if v is not None:
- result.append(
- (
- k.encode("utf-8") if isinstance(k, str) else k,
- v.encode("utf-8") if isinstance(v, str) else v,
- )
- )
- return urlencode(result, doseq=True)
- else:
- return data
-
- @staticmethod
- def _encode_files(files, data):
- """Build the body for a multipart/form-data request.
-
- Will successfully encode files when passed as a dict or a list of
- tuples. Order is retained if data is a list of tuples but arbitrary
- if parameters are supplied as a dict.
- The tuples may be 2-tuples (filename, fileobj), 3-tuples (filename, fileobj, contentype)
- or 4-tuples (filename, fileobj, contentype, custom_headers).
- """
- if not files:
- raise ValueError("Files must be provided.")
- elif isinstance(data, basestring):
- raise ValueError("Data must not be a string.")
-
- new_fields = []
- fields = to_key_val_list(data or {})
- files = to_key_val_list(files or {})
-
- for field, val in fields:
- if isinstance(val, basestring) or not hasattr(val, "__iter__"):
- val = [val]
- for v in val:
- if v is not None:
- # Don't call str() on bytestrings: in Py3 it all goes wrong.
- if not isinstance(v, bytes):
- v = str(v)
-
- new_fields.append(
- (
- field.decode("utf-8")
- if isinstance(field, bytes)
- else field,
- v.encode("utf-8") if isinstance(v, str) else v,
- )
- )
-
- for k, v in files:
- # support for explicit filename
- ft = None
- fh = None
- if isinstance(v, (tuple, list)):
- if len(v) == 2:
- fn, fp = v
- elif len(v) == 3:
- fn, fp, ft = v
- else:
- fn, fp, ft, fh = v
- else:
- fn = guess_filename(v) or k
- fp = v
-
- if isinstance(fp, (str, bytes, bytearray)):
- fdata = fp
- elif hasattr(fp, "read"):
- fdata = fp.read()
- elif fp is None:
- continue
- else:
- fdata = fp
-
- rf = RequestField(name=k, data=fdata, filename=fn, headers=fh)
- rf.make_multipart(content_type=ft)
- new_fields.append(rf)
-
- body, content_type = encode_multipart_formdata(new_fields)
-
- return body, content_type
-
-
-class RequestHooksMixin:
- def register_hook(self, event, hook):
- """Properly register a hook."""
-
- if event not in self.hooks:
- raise ValueError(f'Unsupported event specified, with event name "{event}"')
-
- if isinstance(hook, Callable):
- self.hooks[event].append(hook)
- elif hasattr(hook, "__iter__"):
- self.hooks[event].extend(h for h in hook if isinstance(h, Callable))
-
- def deregister_hook(self, event, hook):
- """Deregister a previously registered hook.
- Returns True if the hook existed, False if not.
- """
-
- try:
- self.hooks[event].remove(hook)
- return True
- except ValueError:
- return False
-
-
-class Request(RequestHooksMixin):
- """A user-created :class:`Request ` object.
-
- Used to prepare a :class:`PreparedRequest `, which is sent to the server.
-
- :param method: HTTP method to use.
- :param url: URL to send.
- :param headers: dictionary of headers to send.
- :param files: dictionary of {filename: fileobject} files to multipart upload.
- :param data: the body to attach to the request. If a dictionary or
- list of tuples ``[(key, value)]`` is provided, form-encoding will
- take place.
- :param json: json for the body to attach to the request (if files or data is not specified).
- :param params: URL parameters to append to the URL. If a dictionary or
- list of tuples ``[(key, value)]`` is provided, form-encoding will
- take place.
- :param auth: Auth handler or (user, pass) tuple.
- :param cookies: dictionary or CookieJar of cookies to attach to this request.
- :param hooks: dictionary of callback hooks, for internal usage.
-
- Usage::
-
- >>> import requests
- >>> req = requests.Request('GET', 'https://httpbin.org/get')
- >>> req.prepare()
-
- """
-
- def __init__(
- self,
- method=None,
- url=None,
- headers=None,
- files=None,
- data=None,
- params=None,
- auth=None,
- cookies=None,
- hooks=None,
- json=None,
- ):
- # Default empty dicts for dict params.
- data = [] if data is None else data
- files = [] if files is None else files
- headers = {} if headers is None else headers
- params = {} if params is None else params
- hooks = {} if hooks is None else hooks
-
- self.hooks = default_hooks()
- for k, v in list(hooks.items()):
- self.register_hook(event=k, hook=v)
-
- self.method = method
- self.url = url
- self.headers = headers
- self.files = files
- self.data = data
- self.json = json
- self.params = params
- self.auth = auth
- self.cookies = cookies
-
- def __repr__(self):
- return f""
-
- def prepare(self):
- """Constructs a :class:`PreparedRequest ` for transmission and returns it."""
- p = PreparedRequest()
- p.prepare(
- method=self.method,
- url=self.url,
- headers=self.headers,
- files=self.files,
- data=self.data,
- json=self.json,
- params=self.params,
- auth=self.auth,
- cookies=self.cookies,
- hooks=self.hooks,
- )
- return p
-
-
-class PreparedRequest(RequestEncodingMixin, RequestHooksMixin):
- """The fully mutable :class:`PreparedRequest ` object,
- containing the exact bytes that will be sent to the server.
-
- Instances are generated from a :class:`Request ` object, and
- should not be instantiated manually; doing so may produce undesirable
- effects.
-
- Usage::
-
- >>> import requests
- >>> req = requests.Request('GET', 'https://httpbin.org/get')
- >>> r = req.prepare()
- >>> r
-
-
- >>> s = requests.Session()
- >>> s.send(r)
-
- """
-
- def __init__(self):
- #: HTTP verb to send to the server.
- self.method = None
- #: HTTP URL to send the request to.
- self.url = None
- #: dictionary of HTTP headers.
- self.headers = None
- # The `CookieJar` used to create the Cookie header will be stored here
- # after prepare_cookies is called
- self._cookies = None
- #: request body to send to the server.
- self.body = None
- #: dictionary of callback hooks, for internal usage.
- self.hooks = default_hooks()
- #: integer denoting starting position of a readable file-like body.
- self._body_position = None
-
- def prepare(
- self,
- method=None,
- url=None,
- headers=None,
- files=None,
- data=None,
- params=None,
- auth=None,
- cookies=None,
- hooks=None,
- json=None,
- ):
- """Prepares the entire request with the given parameters."""
-
- self.prepare_method(method)
- self.prepare_url(url, params)
- self.prepare_headers(headers)
- self.prepare_cookies(cookies)
- self.prepare_body(data, files, json)
- self.prepare_auth(auth, url)
-
- # Note that prepare_auth must be last to enable authentication schemes
- # such as OAuth to work on a fully prepared request.
-
- # This MUST go after prepare_auth. Authenticators could add a hook
- self.prepare_hooks(hooks)
-
- def __repr__(self):
- return f""
-
- def copy(self):
- p = PreparedRequest()
- p.method = self.method
- p.url = self.url
- p.headers = self.headers.copy() if self.headers is not None else None
- p._cookies = _copy_cookie_jar(self._cookies)
- p.body = self.body
- p.hooks = self.hooks
- p._body_position = self._body_position
- return p
-
- def prepare_method(self, method):
- """Prepares the given HTTP method."""
- self.method = method
- if self.method is not None:
- self.method = to_native_string(self.method.upper())
-
- @staticmethod
- def _get_idna_encoded_host(host):
- import idna
-
- try:
- host = idna.encode(host, uts46=True).decode("utf-8")
- except idna.IDNAError:
- raise UnicodeError
- return host
-
- def prepare_url(self, url, params):
- """Prepares the given HTTP URL."""
- #: Accept objects that have string representations.
- #: We're unable to blindly call unicode/str functions
- #: as this will include the bytestring indicator (b'')
- #: on python 3.x.
- #: https://github.com/psf/requests/pull/2238
- if isinstance(url, bytes):
- url = url.decode("utf8")
- else:
- url = str(url)
-
- # Remove leading whitespaces from url
- url = url.lstrip()
-
- # Don't do any URL preparation for non-HTTP schemes like `mailto`,
- # `data` etc to work around exceptions from `url_parse`, which
- # handles RFC 3986 only.
- if ":" in url and not url.lower().startswith("http"):
- self.url = url
- return
-
- # Support for unicode domain names and paths.
- try:
- scheme, auth, host, port, path, query, fragment = parse_url(url)
- except LocationParseError as e:
- raise InvalidURL(*e.args)
-
- if not scheme:
- raise MissingSchema(
- f"Invalid URL {url!r}: No scheme supplied. "
- f"Perhaps you meant https://{url}?"
- )
-
- if not host:
- raise InvalidURL(f"Invalid URL {url!r}: No host supplied")
-
- # In general, we want to try IDNA encoding the hostname if the string contains
- # non-ASCII characters. This allows users to automatically get the correct IDNA
- # behaviour. For strings containing only ASCII characters, we need to also verify
- # it doesn't start with a wildcard (*), before allowing the unencoded hostname.
- if not unicode_is_ascii(host):
- try:
- host = self._get_idna_encoded_host(host)
- except UnicodeError:
- raise InvalidURL("URL has an invalid label.")
- elif host.startswith(("*", ".")):
- raise InvalidURL("URL has an invalid label.")
-
- # Carefully reconstruct the network location
- netloc = auth or ""
- if netloc:
- netloc += "@"
- netloc += host
- if port:
- netloc += f":{port}"
-
- # Bare domains aren't valid URLs.
- if not path:
- path = "/"
-
- if isinstance(params, (str, bytes)):
- params = to_native_string(params)
-
- enc_params = self._encode_params(params)
- if enc_params:
- if query:
- query = f"{query}&{enc_params}"
- else:
- query = enc_params
-
- url = requote_uri(urlunparse([scheme, netloc, path, None, query, fragment]))
- self.url = url
-
- def prepare_headers(self, headers):
- """Prepares the given HTTP headers."""
-
- self.headers = CaseInsensitiveDict()
- if headers:
- for header in headers.items():
- # Raise exception on invalid header value.
- check_header_validity(header)
- name, value = header
- self.headers[to_native_string(name)] = value
-
- def prepare_body(self, data, files, json=None):
- """Prepares the given HTTP body data."""
-
- # Check if file, fo, generator, iterator.
- # If not, run through normal process.
-
- # Nottin' on you.
- body = None
- content_type = None
-
- if not data and json is not None:
- # urllib3 requires a bytes-like body. Python 2's json.dumps
- # provides this natively, but Python 3 gives a Unicode string.
- content_type = "application/json"
-
- try:
- body = complexjson.dumps(json, allow_nan=False)
- except ValueError as ve:
- raise InvalidJSONError(ve, request=self)
-
- if not isinstance(body, bytes):
- body = body.encode("utf-8")
-
- is_stream = all(
- [
- hasattr(data, "__iter__"),
- not isinstance(data, (basestring, list, tuple, Mapping)),
- ]
- )
-
- if is_stream:
- try:
- length = super_len(data)
- except (TypeError, AttributeError, UnsupportedOperation):
- length = None
-
- body = data
-
- if getattr(body, "tell", None) is not None:
- # Record the current file position before reading.
- # This will allow us to rewind a file in the event
- # of a redirect.
- try:
- self._body_position = body.tell()
- except OSError:
- # This differentiates from None, allowing us to catch
- # a failed `tell()` later when trying to rewind the body
- self._body_position = object()
-
- if files:
- raise NotImplementedError(
- "Streamed bodies and files are mutually exclusive."
- )
-
- if length:
- self.headers["Content-Length"] = builtin_str(length)
- else:
- self.headers["Transfer-Encoding"] = "chunked"
- else:
- # Multi-part file uploads.
- if files:
- (body, content_type) = self._encode_files(files, data)
- else:
- if data:
- body = self._encode_params(data)
- if isinstance(data, basestring) or hasattr(data, "read"):
- content_type = None
- else:
- content_type = "application/x-www-form-urlencoded"
-
- self.prepare_content_length(body)
-
- # Add content-type if it wasn't explicitly provided.
- if content_type and ("content-type" not in self.headers):
- self.headers["Content-Type"] = content_type
-
- self.body = body
-
- def prepare_content_length(self, body):
- """Prepare Content-Length header based on request method and body"""
- if body is not None:
- length = super_len(body)
- if length:
- # If length exists, set it. Otherwise, we fallback
- # to Transfer-Encoding: chunked.
- self.headers["Content-Length"] = builtin_str(length)
- elif (
- self.method not in ("GET", "HEAD")
- and self.headers.get("Content-Length") is None
- ):
- # Set Content-Length to 0 for methods that can have a body
- # but don't provide one. (i.e. not GET or HEAD)
- self.headers["Content-Length"] = "0"
-
- def prepare_auth(self, auth, url=""):
- """Prepares the given HTTP auth data."""
-
- # If no Auth is explicitly provided, extract it from the URL first.
- if auth is None:
- url_auth = get_auth_from_url(self.url)
- auth = url_auth if any(url_auth) else None
-
- if auth:
- if isinstance(auth, tuple) and len(auth) == 2:
- # special-case basic HTTP auth
- auth = HTTPBasicAuth(*auth)
-
- # Allow auth to make its changes.
- r = auth(self)
-
- # Update self to reflect the auth changes.
- self.__dict__.update(r.__dict__)
-
- # Recompute Content-Length
- self.prepare_content_length(self.body)
-
- def prepare_cookies(self, cookies):
- """Prepares the given HTTP cookie data.
-
- This function eventually generates a ``Cookie`` header from the
- given cookies using cookielib. Due to cookielib's design, the header
- will not be regenerated if it already exists, meaning this function
- can only be called once for the life of the
- :class:`PreparedRequest ` object. Any subsequent calls
- to ``prepare_cookies`` will have no actual effect, unless the "Cookie"
- header is removed beforehand.
- """
- if isinstance(cookies, cookielib.CookieJar):
- self._cookies = cookies
- else:
- self._cookies = cookiejar_from_dict(cookies)
-
- cookie_header = get_cookie_header(self._cookies, self)
- if cookie_header is not None:
- self.headers["Cookie"] = cookie_header
-
- def prepare_hooks(self, hooks):
- """Prepares the given hooks."""
- # hooks can be passed as None to the prepare method and to this
- # method. To prevent iterating over None, simply use an empty list
- # if hooks is False-y
- hooks = hooks or []
- for event in hooks:
- self.register_hook(event, hooks[event])
-
-
-class Response:
- """The :class:`Response ` object, which contains a
- server's response to an HTTP request.
- """
-
- __attrs__ = [
- "_content",
- "status_code",
- "headers",
- "url",
- "history",
- "encoding",
- "reason",
- "cookies",
- "elapsed",
- "request",
- ]
-
- def __init__(self):
- self._content = False
- self._content_consumed = False
- self._next = None
-
- #: Integer Code of responded HTTP Status, e.g. 404 or 200.
- self.status_code = None
-
- #: Case-insensitive Dictionary of Response Headers.
- #: For example, ``headers['content-encoding']`` will return the
- #: value of a ``'Content-Encoding'`` response header.
- self.headers = CaseInsensitiveDict()
-
- #: File-like object representation of response (for advanced usage).
- #: Use of ``raw`` requires that ``stream=True`` be set on the request.
- #: This requirement does not apply for use internally to Requests.
- self.raw = None
-
- #: Final URL location of Response.
- self.url = None
-
- #: Encoding to decode with when accessing r.text.
- self.encoding = None
-
- #: A list of :class:`Response ` objects from
- #: the history of the Request. Any redirect responses will end
- #: up here. The list is sorted from the oldest to the most recent request.
- self.history = []
-
- #: Textual reason of responded HTTP Status, e.g. "Not Found" or "OK".
- self.reason = None
-
- #: A CookieJar of Cookies the server sent back.
- self.cookies = cookiejar_from_dict({})
-
- #: The amount of time elapsed between sending the request
- #: and the arrival of the response (as a timedelta).
- #: This property specifically measures the time taken between sending
- #: the first byte of the request and finishing parsing the headers. It
- #: is therefore unaffected by consuming the response content or the
- #: value of the ``stream`` keyword argument.
- self.elapsed = datetime.timedelta(0)
-
- #: The :class:`PreparedRequest ` object to which this
- #: is a response.
- self.request = None
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- self.close()
-
- def __getstate__(self):
- # Consume everything; accessing the content attribute makes
- # sure the content has been fully read.
- if not self._content_consumed:
- self.content
-
- return {attr: getattr(self, attr, None) for attr in self.__attrs__}
-
- def __setstate__(self, state):
- for name, value in state.items():
- setattr(self, name, value)
-
- # pickled objects do not have .raw
- setattr(self, "_content_consumed", True)
- setattr(self, "raw", None)
-
- def __repr__(self):
- return f""
-
- def __bool__(self):
- """Returns True if :attr:`status_code` is less than 400.
-
- This attribute checks if the status code of the response is between
- 400 and 600 to see if there was a client error or a server error. If
- the status code, is between 200 and 400, this will return True. This
- is **not** a check to see if the response code is ``200 OK``.
- """
- return self.ok
-
- def __nonzero__(self):
- """Returns True if :attr:`status_code` is less than 400.
-
- This attribute checks if the status code of the response is between
- 400 and 600 to see if there was a client error or a server error. If
- the status code, is between 200 and 400, this will return True. This
- is **not** a check to see if the response code is ``200 OK``.
- """
- return self.ok
-
- def __iter__(self):
- """Allows you to use a response as an iterator."""
- return self.iter_content(128)
-
- @property
- def ok(self):
- """Returns True if :attr:`status_code` is less than 400, False if not.
-
- This attribute checks if the status code of the response is between
- 400 and 600 to see if there was a client error or a server error. If
- the status code is between 200 and 400, this will return True. This
- is **not** a check to see if the response code is ``200 OK``.
- """
- try:
- self.raise_for_status()
- except HTTPError:
- return False
- return True
-
- @property
- def is_redirect(self):
- """True if this Response is a well-formed HTTP redirect that could have
- been processed automatically (by :meth:`Session.resolve_redirects`).
- """
- return "location" in self.headers and self.status_code in REDIRECT_STATI
-
- @property
- def is_permanent_redirect(self):
- """True if this Response one of the permanent versions of redirect."""
- return "location" in self.headers and self.status_code in (
- codes.moved_permanently,
- codes.permanent_redirect,
- )
-
- @property
- def next(self):
- """Returns a PreparedRequest for the next request in a redirect chain, if there is one."""
- return self._next
-
- @property
- def apparent_encoding(self):
- """The apparent encoding, provided by the charset_normalizer or chardet libraries."""
- if chardet is not None:
- return chardet.detect(self.content)["encoding"]
- else:
- # If no character detection library is available, we'll fall back
- # to a standard Python utf-8 str.
- return "utf-8"
-
- def iter_content(self, chunk_size=1, decode_unicode=False):
- """Iterates over the response data. When stream=True is set on the
- request, this avoids reading the content at once into memory for
- large responses. The chunk size is the number of bytes it should
- read into memory. This is not necessarily the length of each item
- returned as decoding can take place.
-
- chunk_size must be of type int or None. A value of None will
- function differently depending on the value of `stream`.
- stream=True will read data as it arrives in whatever size the
- chunks are received. If stream=False, data is returned as
- a single chunk.
-
- If decode_unicode is True, content will be decoded using the best
- available encoding based on the response.
- """
-
- def generate():
- # Special case for urllib3.
- if hasattr(self.raw, "stream"):
- try:
- yield from self.raw.stream(chunk_size, decode_content=True)
- except ProtocolError as e:
- raise ChunkedEncodingError(e)
- except DecodeError as e:
- raise ContentDecodingError(e)
- except ReadTimeoutError as e:
- raise ConnectionError(e)
- except SSLError as e:
- raise RequestsSSLError(e)
- else:
- # Standard file-like object.
- while True:
- chunk = self.raw.read(chunk_size)
- if not chunk:
- break
- yield chunk
-
- self._content_consumed = True
-
- if self._content_consumed and isinstance(self._content, bool):
- raise StreamConsumedError()
- elif chunk_size is not None and not isinstance(chunk_size, int):
- raise TypeError(
- f"chunk_size must be an int, it is instead a {type(chunk_size)}."
- )
- # simulate reading small chunks of the content
- reused_chunks = iter_slices(self._content, chunk_size)
-
- stream_chunks = generate()
-
- chunks = reused_chunks if self._content_consumed else stream_chunks
-
- if decode_unicode:
- chunks = stream_decode_response_unicode(chunks, self)
-
- return chunks
-
- def iter_lines(
- self, chunk_size=ITER_CHUNK_SIZE, decode_unicode=False, delimiter=None
- ):
- """Iterates over the response data, one line at a time. When
- stream=True is set on the request, this avoids reading the
- content at once into memory for large responses.
-
- .. note:: This method is not reentrant safe.
- """
-
- pending = None
-
- for chunk in self.iter_content(
- chunk_size=chunk_size, decode_unicode=decode_unicode
- ):
- if pending is not None:
- chunk = pending + chunk
-
- if delimiter:
- lines = chunk.split(delimiter)
- else:
- lines = chunk.splitlines()
-
- if lines and lines[-1] and chunk and lines[-1][-1] == chunk[-1]:
- pending = lines.pop()
- else:
- pending = None
-
- yield from lines
-
- if pending is not None:
- yield pending
-
- @property
- def content(self):
- """Content of the response, in bytes."""
-
- if self._content is False:
- # Read the contents.
- if self._content_consumed:
- raise RuntimeError("The content for this response was already consumed")
-
- if self.status_code == 0 or self.raw is None:
- self._content = None
- else:
- self._content = b"".join(self.iter_content(CONTENT_CHUNK_SIZE)) or b""
-
- self._content_consumed = True
- # don't need to release the connection; that's been handled by urllib3
- # since we exhausted the data.
- return self._content
-
- @property
- def text(self):
- """Content of the response, in unicode.
-
- If Response.encoding is None, encoding will be guessed using
- ``charset_normalizer`` or ``chardet``.
-
- The encoding of the response content is determined based solely on HTTP
- headers, following RFC 2616 to the letter. If you can take advantage of
- non-HTTP knowledge to make a better guess at the encoding, you should
- set ``r.encoding`` appropriately before accessing this property.
- """
-
- # Try charset from content-type
- content = None
- encoding = self.encoding
-
- if not self.content:
- return ""
-
- # Fallback to auto-detected encoding.
- if self.encoding is None:
- encoding = self.apparent_encoding
-
- # Decode unicode from given encoding.
- try:
- content = str(self.content, encoding, errors="replace")
- except (LookupError, TypeError):
- # A LookupError is raised if the encoding was not found which could
- # indicate a misspelling or similar mistake.
- #
- # A TypeError can be raised if encoding is None
- #
- # So we try blindly encoding.
- content = str(self.content, errors="replace")
-
- return content
-
- def json(self, **kwargs):
- r"""Returns the json-encoded content of a response, if any.
-
- :param \*\*kwargs: Optional arguments that ``json.loads`` takes.
- :raises requests.exceptions.JSONDecodeError: If the response body does not
- contain valid json.
- """
-
- if not self.encoding and self.content and len(self.content) > 3:
- # No encoding set. JSON RFC 4627 section 3 states we should expect
- # UTF-8, -16 or -32. Detect which one to use; If the detection or
- # decoding fails, fall back to `self.text` (using charset_normalizer to make
- # a best guess).
- encoding = guess_json_utf(self.content)
- if encoding is not None:
- try:
- return complexjson.loads(self.content.decode(encoding), **kwargs)
- except UnicodeDecodeError:
- # Wrong UTF codec detected; usually because it's not UTF-8
- # but some other 8-bit codec. This is an RFC violation,
- # and the server didn't bother to tell us what codec *was*
- # used.
- pass
- except JSONDecodeError as e:
- raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
-
- try:
- return complexjson.loads(self.text, **kwargs)
- except JSONDecodeError as e:
- # Catch JSON-related errors and raise as requests.JSONDecodeError
- # This aliases json.JSONDecodeError and simplejson.JSONDecodeError
- raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
-
- @property
- def links(self):
- """Returns the parsed header links of the response, if any."""
-
- header = self.headers.get("link")
-
- resolved_links = {}
-
- if header:
- links = parse_header_links(header)
-
- for link in links:
- key = link.get("rel") or link.get("url")
- resolved_links[key] = link
-
- return resolved_links
-
- def raise_for_status(self):
- """Raises :class:`HTTPError`, if one occurred."""
-
- http_error_msg = ""
- if isinstance(self.reason, bytes):
- # We attempt to decode utf-8 first because some servers
- # choose to localize their reason strings. If the string
- # isn't utf-8, we fall back to iso-8859-1 for all other
- # encodings. (See PR #3538)
- try:
- reason = self.reason.decode("utf-8")
- except UnicodeDecodeError:
- reason = self.reason.decode("iso-8859-1")
- else:
- reason = self.reason
-
- if 400 <= self.status_code < 500:
- http_error_msg = (
- f"{self.status_code} Client Error: {reason} for url: {self.url}"
- )
-
- elif 500 <= self.status_code < 600:
- http_error_msg = (
- f"{self.status_code} Server Error: {reason} for url: {self.url}"
- )
-
- if http_error_msg:
- raise HTTPError(http_error_msg, response=self)
-
- def close(self):
- """Releases the connection back to the pool. Once this method has been
- called the underlying ``raw`` object must not be accessed again.
-
- *Note: Should not normally need to be called explicitly.*
- """
- if not self._content_consumed:
- self.raw.close()
-
- release_conn = getattr(self.raw, "release_conn", None)
- if release_conn is not None:
- release_conn()
diff --git a/.venv/lib/python3.12/site-packages/requests/packages.py b/.venv/lib/python3.12/site-packages/requests/packages.py
deleted file mode 100644
index 5ab3d8e..0000000
--- a/.venv/lib/python3.12/site-packages/requests/packages.py
+++ /dev/null
@@ -1,23 +0,0 @@
-import sys
-
-from .compat import chardet
-
-# This code exists for backwards compatibility reasons.
-# I don't like it either. Just look the other way. :)
-
-for package in ("urllib3", "idna"):
- locals()[package] = __import__(package)
- # This traversal is apparently necessary such that the identities are
- # preserved (requests.packages.urllib3.* is urllib3.*)
- for mod in list(sys.modules):
- if mod == package or mod.startswith(f"{package}."):
- sys.modules[f"requests.packages.{mod}"] = sys.modules[mod]
-
-if chardet is not None:
- target = chardet.__name__
- for mod in list(sys.modules):
- if mod == target or mod.startswith(f"{target}."):
- imported_mod = sys.modules[mod]
- sys.modules[f"requests.packages.{mod}"] = imported_mod
- mod = mod.replace(target, "chardet")
- sys.modules[f"requests.packages.{mod}"] = imported_mod
diff --git a/.venv/lib/python3.12/site-packages/requests/sessions.py b/.venv/lib/python3.12/site-packages/requests/sessions.py
deleted file mode 100644
index b387bc3..0000000
--- a/.venv/lib/python3.12/site-packages/requests/sessions.py
+++ /dev/null
@@ -1,831 +0,0 @@
-"""
-requests.sessions
-~~~~~~~~~~~~~~~~~
-
-This module provides a Session object to manage and persist settings across
-requests (cookies, auth, proxies).
-"""
-import os
-import sys
-import time
-from collections import OrderedDict
-from datetime import timedelta
-
-from ._internal_utils import to_native_string
-from .adapters import HTTPAdapter
-from .auth import _basic_auth_str
-from .compat import Mapping, cookielib, urljoin, urlparse
-from .cookies import (
- RequestsCookieJar,
- cookiejar_from_dict,
- extract_cookies_to_jar,
- merge_cookies,
-)
-from .exceptions import (
- ChunkedEncodingError,
- ContentDecodingError,
- InvalidSchema,
- TooManyRedirects,
-)
-from .hooks import default_hooks, dispatch_hook
-
-# formerly defined here, reexposed here for backward compatibility
-from .models import ( # noqa: F401
- DEFAULT_REDIRECT_LIMIT,
- REDIRECT_STATI,
- PreparedRequest,
- Request,
-)
-from .status_codes import codes
-from .structures import CaseInsensitiveDict
-from .utils import ( # noqa: F401
- DEFAULT_PORTS,
- default_headers,
- get_auth_from_url,
- get_environ_proxies,
- get_netrc_auth,
- requote_uri,
- resolve_proxies,
- rewind_body,
- should_bypass_proxies,
- to_key_val_list,
-)
-
-# Preferred clock, based on which one is more accurate on a given system.
-if sys.platform == "win32":
- preferred_clock = time.perf_counter
-else:
- preferred_clock = time.time
-
-
-def merge_setting(request_setting, session_setting, dict_class=OrderedDict):
- """Determines appropriate setting for a given request, taking into account
- the explicit setting on that request, and the setting in the session. If a
- setting is a dictionary, they will be merged together using `dict_class`
- """
-
- if session_setting is None:
- return request_setting
-
- if request_setting is None:
- return session_setting
-
- # Bypass if not a dictionary (e.g. verify)
- if not (
- isinstance(session_setting, Mapping) and isinstance(request_setting, Mapping)
- ):
- return request_setting
-
- merged_setting = dict_class(to_key_val_list(session_setting))
- merged_setting.update(to_key_val_list(request_setting))
-
- # Remove keys that are set to None. Extract keys first to avoid altering
- # the dictionary during iteration.
- none_keys = [k for (k, v) in merged_setting.items() if v is None]
- for key in none_keys:
- del merged_setting[key]
-
- return merged_setting
-
-
-def merge_hooks(request_hooks, session_hooks, dict_class=OrderedDict):
- """Properly merges both requests and session hooks.
-
- This is necessary because when request_hooks == {'response': []}, the
- merge breaks Session hooks entirely.
- """
- if session_hooks is None or session_hooks.get("response") == []:
- return request_hooks
-
- if request_hooks is None or request_hooks.get("response") == []:
- return session_hooks
-
- return merge_setting(request_hooks, session_hooks, dict_class)
-
-
-class SessionRedirectMixin:
- def get_redirect_target(self, resp):
- """Receives a Response. Returns a redirect URI or ``None``"""
- # Due to the nature of how requests processes redirects this method will
- # be called at least once upon the original response and at least twice
- # on each subsequent redirect response (if any).
- # If a custom mixin is used to handle this logic, it may be advantageous
- # to cache the redirect location onto the response object as a private
- # attribute.
- if resp.is_redirect:
- location = resp.headers["location"]
- # Currently the underlying http module on py3 decode headers
- # in latin1, but empirical evidence suggests that latin1 is very
- # rarely used with non-ASCII characters in HTTP headers.
- # It is more likely to get UTF8 header rather than latin1.
- # This causes incorrect handling of UTF8 encoded location headers.
- # To solve this, we re-encode the location in latin1.
- location = location.encode("latin1")
- return to_native_string(location, "utf8")
- return None
-
- def should_strip_auth(self, old_url, new_url):
- """Decide whether Authorization header should be removed when redirecting"""
- old_parsed = urlparse(old_url)
- new_parsed = urlparse(new_url)
- if old_parsed.hostname != new_parsed.hostname:
- return True
- # Special case: allow http -> https redirect when using the standard
- # ports. This isn't specified by RFC 7235, but is kept to avoid
- # breaking backwards compatibility with older versions of requests
- # that allowed any redirects on the same host.
- if (
- old_parsed.scheme == "http"
- and old_parsed.port in (80, None)
- and new_parsed.scheme == "https"
- and new_parsed.port in (443, None)
- ):
- return False
-
- # Handle default port usage corresponding to scheme.
- changed_port = old_parsed.port != new_parsed.port
- changed_scheme = old_parsed.scheme != new_parsed.scheme
- default_port = (DEFAULT_PORTS.get(old_parsed.scheme, None), None)
- if (
- not changed_scheme
- and old_parsed.port in default_port
- and new_parsed.port in default_port
- ):
- return False
-
- # Standard case: root URI must match
- return changed_port or changed_scheme
-
- def resolve_redirects(
- self,
- resp,
- req,
- stream=False,
- timeout=None,
- verify=True,
- cert=None,
- proxies=None,
- yield_requests=False,
- **adapter_kwargs,
- ):
- """Receives a Response. Returns a generator of Responses or Requests."""
-
- hist = [] # keep track of history
-
- url = self.get_redirect_target(resp)
- previous_fragment = urlparse(req.url).fragment
- while url:
- prepared_request = req.copy()
-
- # Update history and keep track of redirects.
- # resp.history must ignore the original request in this loop
- hist.append(resp)
- resp.history = hist[1:]
-
- try:
- resp.content # Consume socket so it can be released
- except (ChunkedEncodingError, ContentDecodingError, RuntimeError):
- resp.raw.read(decode_content=False)
-
- if len(resp.history) >= self.max_redirects:
- raise TooManyRedirects(
- f"Exceeded {self.max_redirects} redirects.", response=resp
- )
-
- # Release the connection back into the pool.
- resp.close()
-
- # Handle redirection without scheme (see: RFC 1808 Section 4)
- if url.startswith("//"):
- parsed_rurl = urlparse(resp.url)
- url = ":".join([to_native_string(parsed_rurl.scheme), url])
-
- # Normalize url case and attach previous fragment if needed (RFC 7231 7.1.2)
- parsed = urlparse(url)
- if parsed.fragment == "" and previous_fragment:
- parsed = parsed._replace(fragment=previous_fragment)
- elif parsed.fragment:
- previous_fragment = parsed.fragment
- url = parsed.geturl()
-
- # Facilitate relative 'location' headers, as allowed by RFC 7231.
- # (e.g. '/path/to/resource' instead of 'http://domain.tld/path/to/resource')
- # Compliant with RFC3986, we percent encode the url.
- if not parsed.netloc:
- url = urljoin(resp.url, requote_uri(url))
- else:
- url = requote_uri(url)
-
- prepared_request.url = to_native_string(url)
-
- self.rebuild_method(prepared_request, resp)
-
- # https://github.com/psf/requests/issues/1084
- if resp.status_code not in (
- codes.temporary_redirect,
- codes.permanent_redirect,
- ):
- # https://github.com/psf/requests/issues/3490
- purged_headers = ("Content-Length", "Content-Type", "Transfer-Encoding")
- for header in purged_headers:
- prepared_request.headers.pop(header, None)
- prepared_request.body = None
-
- headers = prepared_request.headers
- headers.pop("Cookie", None)
-
- # Extract any cookies sent on the response to the cookiejar
- # in the new request. Because we've mutated our copied prepared
- # request, use the old one that we haven't yet touched.
- extract_cookies_to_jar(prepared_request._cookies, req, resp.raw)
- merge_cookies(prepared_request._cookies, self.cookies)
- prepared_request.prepare_cookies(prepared_request._cookies)
-
- # Rebuild auth and proxy information.
- proxies = self.rebuild_proxies(prepared_request, proxies)
- self.rebuild_auth(prepared_request, resp)
-
- # A failed tell() sets `_body_position` to `object()`. This non-None
- # value ensures `rewindable` will be True, allowing us to raise an
- # UnrewindableBodyError, instead of hanging the connection.
- rewindable = prepared_request._body_position is not None and (
- "Content-Length" in headers or "Transfer-Encoding" in headers
- )
-
- # Attempt to rewind consumed file-like object.
- if rewindable:
- rewind_body(prepared_request)
-
- # Override the original request.
- req = prepared_request
-
- if yield_requests:
- yield req
- else:
- resp = self.send(
- req,
- stream=stream,
- timeout=timeout,
- verify=verify,
- cert=cert,
- proxies=proxies,
- allow_redirects=False,
- **adapter_kwargs,
- )
-
- extract_cookies_to_jar(self.cookies, prepared_request, resp.raw)
-
- # extract redirect url, if any, for the next loop
- url = self.get_redirect_target(resp)
- yield resp
-
- def rebuild_auth(self, prepared_request, response):
- """When being redirected we may want to strip authentication from the
- request to avoid leaking credentials. This method intelligently removes
- and reapplies authentication where possible to avoid credential loss.
- """
- headers = prepared_request.headers
- url = prepared_request.url
-
- if "Authorization" in headers and self.should_strip_auth(
- response.request.url, url
- ):
- # If we get redirected to a new host, we should strip out any
- # authentication headers.
- del headers["Authorization"]
-
- # .netrc might have more auth for us on our new host.
- new_auth = get_netrc_auth(url) if self.trust_env else None
- if new_auth is not None:
- prepared_request.prepare_auth(new_auth)
-
- def rebuild_proxies(self, prepared_request, proxies):
- """This method re-evaluates the proxy configuration by considering the
- environment variables. If we are redirected to a URL covered by
- NO_PROXY, we strip the proxy configuration. Otherwise, we set missing
- proxy keys for this URL (in case they were stripped by a previous
- redirect).
-
- This method also replaces the Proxy-Authorization header where
- necessary.
-
- :rtype: dict
- """
- headers = prepared_request.headers
- scheme = urlparse(prepared_request.url).scheme
- new_proxies = resolve_proxies(prepared_request, proxies, self.trust_env)
-
- if "Proxy-Authorization" in headers:
- del headers["Proxy-Authorization"]
-
- try:
- username, password = get_auth_from_url(new_proxies[scheme])
- except KeyError:
- username, password = None, None
-
- # urllib3 handles proxy authorization for us in the standard adapter.
- # Avoid appending this to TLS tunneled requests where it may be leaked.
- if not scheme.startswith("https") and username and password:
- headers["Proxy-Authorization"] = _basic_auth_str(username, password)
-
- return new_proxies
-
- def rebuild_method(self, prepared_request, response):
- """When being redirected we may want to change the method of the request
- based on certain specs or browser behavior.
- """
- method = prepared_request.method
-
- # https://tools.ietf.org/html/rfc7231#section-6.4.4
- if response.status_code == codes.see_other and method != "HEAD":
- method = "GET"
-
- # Do what the browsers do, despite standards...
- # First, turn 302s into GETs.
- if response.status_code == codes.found and method != "HEAD":
- method = "GET"
-
- # Second, if a POST is responded to with a 301, turn it into a GET.
- # This bizarre behaviour is explained in Issue 1704.
- if response.status_code == codes.moved and method == "POST":
- method = "GET"
-
- prepared_request.method = method
-
-
-class Session(SessionRedirectMixin):
- """A Requests session.
-
- Provides cookie persistence, connection-pooling, and configuration.
-
- Basic Usage::
-
- >>> import requests
- >>> s = requests.Session()
- >>> s.get('https://httpbin.org/get')
-
-
- Or as a context manager::
-
- >>> with requests.Session() as s:
- ... s.get('https://httpbin.org/get')
-
- """
-
- __attrs__ = [
- "headers",
- "cookies",
- "auth",
- "proxies",
- "hooks",
- "params",
- "verify",
- "cert",
- "adapters",
- "stream",
- "trust_env",
- "max_redirects",
- ]
-
- def __init__(self):
- #: A case-insensitive dictionary of headers to be sent on each
- #: :class:`Request ` sent from this
- #: :class:`Session `.
- self.headers = default_headers()
-
- #: Default Authentication tuple or object to attach to
- #: :class:`Request `.
- self.auth = None
-
- #: Dictionary mapping protocol or protocol and host to the URL of the proxy
- #: (e.g. {'http': 'foo.bar:3128', 'http://host.name': 'foo.bar:4012'}) to
- #: be used on each :class:`Request `.
- self.proxies = {}
-
- #: Event-handling hooks.
- self.hooks = default_hooks()
-
- #: Dictionary of querystring data to attach to each
- #: :class:`Request `. The dictionary values may be lists for
- #: representing multivalued query parameters.
- self.params = {}
-
- #: Stream response content default.
- self.stream = False
-
- #: SSL Verification default.
- #: Defaults to `True`, requiring requests to verify the TLS certificate at the
- #: remote end.
- #: If verify is set to `False`, requests will accept any TLS certificate
- #: presented by the server, and will ignore hostname mismatches and/or
- #: expired certificates, which will make your application vulnerable to
- #: man-in-the-middle (MitM) attacks.
- #: Only set this to `False` for testing.
- self.verify = True
-
- #: SSL client certificate default, if String, path to ssl client
- #: cert file (.pem). If Tuple, ('cert', 'key') pair.
- self.cert = None
-
- #: Maximum number of redirects allowed. If the request exceeds this
- #: limit, a :class:`TooManyRedirects` exception is raised.
- #: This defaults to requests.models.DEFAULT_REDIRECT_LIMIT, which is
- #: 30.
- self.max_redirects = DEFAULT_REDIRECT_LIMIT
-
- #: Trust environment settings for proxy configuration, default
- #: authentication and similar.
- self.trust_env = True
-
- #: A CookieJar containing all currently outstanding cookies set on this
- #: session. By default it is a
- #: :class:`RequestsCookieJar `, but
- #: may be any other ``cookielib.CookieJar`` compatible object.
- self.cookies = cookiejar_from_dict({})
-
- # Default connection adapters.
- self.adapters = OrderedDict()
- self.mount("https://", HTTPAdapter())
- self.mount("http://", HTTPAdapter())
-
- def __enter__(self):
- return self
-
- def __exit__(self, *args):
- self.close()
-
- def prepare_request(self, request):
- """Constructs a :class:`PreparedRequest ` for
- transmission and returns it. The :class:`PreparedRequest` has settings
- merged from the :class:`Request ` instance and those of the
- :class:`Session`.
-
- :param request: :class:`Request` instance to prepare with this
- session's settings.
- :rtype: requests.PreparedRequest
- """
- cookies = request.cookies or {}
-
- # Bootstrap CookieJar.
- if not isinstance(cookies, cookielib.CookieJar):
- cookies = cookiejar_from_dict(cookies)
-
- # Merge with session cookies
- merged_cookies = merge_cookies(
- merge_cookies(RequestsCookieJar(), self.cookies), cookies
- )
-
- # Set environment's basic authentication if not explicitly set.
- auth = request.auth
- if self.trust_env and not auth and not self.auth:
- auth = get_netrc_auth(request.url)
-
- p = PreparedRequest()
- p.prepare(
- method=request.method.upper(),
- url=request.url,
- files=request.files,
- data=request.data,
- json=request.json,
- headers=merge_setting(
- request.headers, self.headers, dict_class=CaseInsensitiveDict
- ),
- params=merge_setting(request.params, self.params),
- auth=merge_setting(auth, self.auth),
- cookies=merged_cookies,
- hooks=merge_hooks(request.hooks, self.hooks),
- )
- return p
-
- def request(
- self,
- method,
- url,
- params=None,
- data=None,
- headers=None,
- cookies=None,
- files=None,
- auth=None,
- timeout=None,
- allow_redirects=True,
- proxies=None,
- hooks=None,
- stream=None,
- verify=None,
- cert=None,
- json=None,
- ):
- """Constructs a :class:`Request `, prepares it and sends it.
- Returns :class:`Response ` object.
-
- :param method: method for the new :class:`Request` object.
- :param url: URL for the new :class:`Request` object.
- :param params: (optional) Dictionary or bytes to be sent in the query
- string for the :class:`Request`.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) json to send in the body of the
- :class:`Request`.
- :param headers: (optional) Dictionary of HTTP Headers to send with the
- :class:`Request`.
- :param cookies: (optional) Dict or CookieJar object to send with the
- :class:`Request`.
- :param files: (optional) Dictionary of ``'filename': file-like-objects``
- for multipart encoding upload.
- :param auth: (optional) Auth tuple or callable to enable
- Basic/Digest/Custom HTTP Auth.
- :param timeout: (optional) How long to wait for the server to send
- data before giving up, as a float, or a :ref:`(connect timeout,
- read timeout) ` tuple.
- :type timeout: float or tuple
- :param allow_redirects: (optional) Set to True by default.
- :type allow_redirects: bool
- :param proxies: (optional) Dictionary mapping protocol or protocol and
- hostname to the URL of the proxy.
- :param hooks: (optional) Dictionary mapping hook name to one event or
- list of events, event must be callable.
- :param stream: (optional) whether to immediately download the response
- content. Defaults to ``False``.
- :param verify: (optional) Either a boolean, in which case it controls whether we verify
- the server's TLS certificate, or a string, in which case it must be a path
- to a CA bundle to use. Defaults to ``True``. When set to
- ``False``, requests will accept any TLS certificate presented by
- the server, and will ignore hostname mismatches and/or expired
- certificates, which will make your application vulnerable to
- man-in-the-middle (MitM) attacks. Setting verify to ``False``
- may be useful during local development or testing.
- :param cert: (optional) if String, path to ssl client cert file (.pem).
- If Tuple, ('cert', 'key') pair.
- :rtype: requests.Response
- """
- # Create the Request.
- req = Request(
- method=method.upper(),
- url=url,
- headers=headers,
- files=files,
- data=data or {},
- json=json,
- params=params or {},
- auth=auth,
- cookies=cookies,
- hooks=hooks,
- )
- prep = self.prepare_request(req)
-
- proxies = proxies or {}
-
- settings = self.merge_environment_settings(
- prep.url, proxies, stream, verify, cert
- )
-
- # Send the request.
- send_kwargs = {
- "timeout": timeout,
- "allow_redirects": allow_redirects,
- }
- send_kwargs.update(settings)
- resp = self.send(prep, **send_kwargs)
-
- return resp
-
- def get(self, url, **kwargs):
- r"""Sends a GET request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- kwargs.setdefault("allow_redirects", True)
- return self.request("GET", url, **kwargs)
-
- def options(self, url, **kwargs):
- r"""Sends a OPTIONS request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- kwargs.setdefault("allow_redirects", True)
- return self.request("OPTIONS", url, **kwargs)
-
- def head(self, url, **kwargs):
- r"""Sends a HEAD request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- kwargs.setdefault("allow_redirects", False)
- return self.request("HEAD", url, **kwargs)
-
- def post(self, url, data=None, json=None, **kwargs):
- r"""Sends a POST request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param json: (optional) json to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- return self.request("POST", url, data=data, json=json, **kwargs)
-
- def put(self, url, data=None, **kwargs):
- r"""Sends a PUT request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- return self.request("PUT", url, data=data, **kwargs)
-
- def patch(self, url, data=None, **kwargs):
- r"""Sends a PATCH request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param data: (optional) Dictionary, list of tuples, bytes, or file-like
- object to send in the body of the :class:`Request`.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- return self.request("PATCH", url, data=data, **kwargs)
-
- def delete(self, url, **kwargs):
- r"""Sends a DELETE request. Returns :class:`Response` object.
-
- :param url: URL for the new :class:`Request` object.
- :param \*\*kwargs: Optional arguments that ``request`` takes.
- :rtype: requests.Response
- """
-
- return self.request("DELETE", url, **kwargs)
-
- def send(self, request, **kwargs):
- """Send a given PreparedRequest.
-
- :rtype: requests.Response
- """
- # Set defaults that the hooks can utilize to ensure they always have
- # the correct parameters to reproduce the previous request.
- kwargs.setdefault("stream", self.stream)
- kwargs.setdefault("verify", self.verify)
- kwargs.setdefault("cert", self.cert)
- if "proxies" not in kwargs:
- kwargs["proxies"] = resolve_proxies(request, self.proxies, self.trust_env)
-
- # It's possible that users might accidentally send a Request object.
- # Guard against that specific failure case.
- if isinstance(request, Request):
- raise ValueError("You can only send PreparedRequests.")
-
- # Set up variables needed for resolve_redirects and dispatching of hooks
- allow_redirects = kwargs.pop("allow_redirects", True)
- stream = kwargs.get("stream")
- hooks = request.hooks
-
- # Get the appropriate adapter to use
- adapter = self.get_adapter(url=request.url)
-
- # Start time (approximately) of the request
- start = preferred_clock()
-
- # Send the request
- r = adapter.send(request, **kwargs)
-
- # Total elapsed time of the request (approximately)
- elapsed = preferred_clock() - start
- r.elapsed = timedelta(seconds=elapsed)
-
- # Response manipulation hooks
- r = dispatch_hook("response", hooks, r, **kwargs)
-
- # Persist cookies
- if r.history:
- # If the hooks create history then we want those cookies too
- for resp in r.history:
- extract_cookies_to_jar(self.cookies, resp.request, resp.raw)
-
- extract_cookies_to_jar(self.cookies, request, r.raw)
-
- # Resolve redirects if allowed.
- if allow_redirects:
- # Redirect resolving generator.
- gen = self.resolve_redirects(r, request, **kwargs)
- history = [resp for resp in gen]
- else:
- history = []
-
- # Shuffle things around if there's history.
- if history:
- # Insert the first (original) request at the start
- history.insert(0, r)
- # Get the last request made
- r = history.pop()
- r.history = history
-
- # If redirects aren't being followed, store the response on the Request for Response.next().
- if not allow_redirects:
- try:
- r._next = next(
- self.resolve_redirects(r, request, yield_requests=True, **kwargs)
- )
- except StopIteration:
- pass
-
- if not stream:
- r.content
-
- return r
-
- def merge_environment_settings(self, url, proxies, stream, verify, cert):
- """
- Check the environment and merge it with some settings.
-
- :rtype: dict
- """
- # Gather clues from the surrounding environment.
- if self.trust_env:
- # Set environment's proxies.
- no_proxy = proxies.get("no_proxy") if proxies is not None else None
- env_proxies = get_environ_proxies(url, no_proxy=no_proxy)
- for k, v in env_proxies.items():
- proxies.setdefault(k, v)
-
- # Look for requests environment configuration
- # and be compatible with cURL.
- if verify is True or verify is None:
- verify = (
- os.environ.get("REQUESTS_CA_BUNDLE")
- or os.environ.get("CURL_CA_BUNDLE")
- or verify
- )
-
- # Merge all the kwargs.
- proxies = merge_setting(proxies, self.proxies)
- stream = merge_setting(stream, self.stream)
- verify = merge_setting(verify, self.verify)
- cert = merge_setting(cert, self.cert)
-
- return {"proxies": proxies, "stream": stream, "verify": verify, "cert": cert}
-
- def get_adapter(self, url):
- """
- Returns the appropriate connection adapter for the given URL.
-
- :rtype: requests.adapters.BaseAdapter
- """
- for prefix, adapter in self.adapters.items():
- if url.lower().startswith(prefix.lower()):
- return adapter
-
- # Nothing matches :-/
- raise InvalidSchema(f"No connection adapters were found for {url!r}")
-
- def close(self):
- """Closes all adapters and as such the session"""
- for v in self.adapters.values():
- v.close()
-
- def mount(self, prefix, adapter):
- """Registers a connection adapter to a prefix.
-
- Adapters are sorted in descending order by prefix length.
- """
- self.adapters[prefix] = adapter
- keys_to_move = [k for k in self.adapters if len(k) < len(prefix)]
-
- for key in keys_to_move:
- self.adapters[key] = self.adapters.pop(key)
-
- def __getstate__(self):
- state = {attr: getattr(self, attr, None) for attr in self.__attrs__}
- return state
-
- def __setstate__(self, state):
- for attr, value in state.items():
- setattr(self, attr, value)
-
-
-def session():
- """
- Returns a :class:`Session` for context-management.
-
- .. deprecated:: 1.0.0
-
- This method has been deprecated since version 1.0.0 and is only kept for
- backwards compatibility. New code should use :class:`~requests.sessions.Session`
- to create a session. This may be removed at a future date.
-
- :rtype: Session
- """
- return Session()
diff --git a/.venv/lib/python3.12/site-packages/requests/status_codes.py b/.venv/lib/python3.12/site-packages/requests/status_codes.py
deleted file mode 100644
index c7945a2..0000000
--- a/.venv/lib/python3.12/site-packages/requests/status_codes.py
+++ /dev/null
@@ -1,128 +0,0 @@
-r"""
-The ``codes`` object defines a mapping from common names for HTTP statuses
-to their numerical codes, accessible either as attributes or as dictionary
-items.
-
-Example::
-
- >>> import requests
- >>> requests.codes['temporary_redirect']
- 307
- >>> requests.codes.teapot
- 418
- >>> requests.codes['\o/']
- 200
-
-Some codes have multiple names, and both upper- and lower-case versions of
-the names are allowed. For example, ``codes.ok``, ``codes.OK``, and
-``codes.okay`` all correspond to the HTTP status code 200.
-"""
-
-from .structures import LookupDict
-
-_codes = {
- # Informational.
- 100: ("continue",),
- 101: ("switching_protocols",),
- 102: ("processing", "early-hints"),
- 103: ("checkpoint",),
- 122: ("uri_too_long", "request_uri_too_long"),
- 200: ("ok", "okay", "all_ok", "all_okay", "all_good", "\\o/", "✓"),
- 201: ("created",),
- 202: ("accepted",),
- 203: ("non_authoritative_info", "non_authoritative_information"),
- 204: ("no_content",),
- 205: ("reset_content", "reset"),
- 206: ("partial_content", "partial"),
- 207: ("multi_status", "multiple_status", "multi_stati", "multiple_stati"),
- 208: ("already_reported",),
- 226: ("im_used",),
- # Redirection.
- 300: ("multiple_choices",),
- 301: ("moved_permanently", "moved", "\\o-"),
- 302: ("found",),
- 303: ("see_other", "other"),
- 304: ("not_modified",),
- 305: ("use_proxy",),
- 306: ("switch_proxy",),
- 307: ("temporary_redirect", "temporary_moved", "temporary"),
- 308: (
- "permanent_redirect",
- "resume_incomplete",
- "resume",
- ), # "resume" and "resume_incomplete" to be removed in 3.0
- # Client Error.
- 400: ("bad_request", "bad"),
- 401: ("unauthorized",),
- 402: ("payment_required", "payment"),
- 403: ("forbidden",),
- 404: ("not_found", "-o-"),
- 405: ("method_not_allowed", "not_allowed"),
- 406: ("not_acceptable",),
- 407: ("proxy_authentication_required", "proxy_auth", "proxy_authentication"),
- 408: ("request_timeout", "timeout"),
- 409: ("conflict",),
- 410: ("gone",),
- 411: ("length_required",),
- 412: ("precondition_failed", "precondition"),
- 413: ("request_entity_too_large", "content_too_large"),
- 414: ("request_uri_too_large", "uri_too_long"),
- 415: ("unsupported_media_type", "unsupported_media", "media_type"),
- 416: (
- "requested_range_not_satisfiable",
- "requested_range",
- "range_not_satisfiable",
- ),
- 417: ("expectation_failed",),
- 418: ("im_a_teapot", "teapot", "i_am_a_teapot"),
- 421: ("misdirected_request",),
- 422: ("unprocessable_entity", "unprocessable", "unprocessable_content"),
- 423: ("locked",),
- 424: ("failed_dependency", "dependency"),
- 425: ("unordered_collection", "unordered", "too_early"),
- 426: ("upgrade_required", "upgrade"),
- 428: ("precondition_required", "precondition"),
- 429: ("too_many_requests", "too_many"),
- 431: ("header_fields_too_large", "fields_too_large"),
- 444: ("no_response", "none"),
- 449: ("retry_with", "retry"),
- 450: ("blocked_by_windows_parental_controls", "parental_controls"),
- 451: ("unavailable_for_legal_reasons", "legal_reasons"),
- 499: ("client_closed_request",),
- # Server Error.
- 500: ("internal_server_error", "server_error", "/o\\", "✗"),
- 501: ("not_implemented",),
- 502: ("bad_gateway",),
- 503: ("service_unavailable", "unavailable"),
- 504: ("gateway_timeout",),
- 505: ("http_version_not_supported", "http_version"),
- 506: ("variant_also_negotiates",),
- 507: ("insufficient_storage",),
- 509: ("bandwidth_limit_exceeded", "bandwidth"),
- 510: ("not_extended",),
- 511: ("network_authentication_required", "network_auth", "network_authentication"),
-}
-
-codes = LookupDict(name="status_codes")
-
-
-def _init():
- for code, titles in _codes.items():
- for title in titles:
- setattr(codes, title, code)
- if not title.startswith(("\\", "/")):
- setattr(codes, title.upper(), code)
-
- def doc(code):
- names = ", ".join(f"``{n}``" for n in _codes[code])
- return "* %d: %s" % (code, names)
-
- global __doc__
- __doc__ = (
- __doc__ + "\n" + "\n".join(doc(code) for code in sorted(_codes))
- if __doc__ is not None
- else None
- )
-
-
-_init()
diff --git a/.venv/lib/python3.12/site-packages/requests/structures.py b/.venv/lib/python3.12/site-packages/requests/structures.py
deleted file mode 100644
index 188e13e..0000000
--- a/.venv/lib/python3.12/site-packages/requests/structures.py
+++ /dev/null
@@ -1,99 +0,0 @@
-"""
-requests.structures
-~~~~~~~~~~~~~~~~~~~
-
-Data structures that power Requests.
-"""
-
-from collections import OrderedDict
-
-from .compat import Mapping, MutableMapping
-
-
-class CaseInsensitiveDict(MutableMapping):
- """A case-insensitive ``dict``-like object.
-
- Implements all methods and operations of
- ``MutableMapping`` as well as dict's ``copy``. Also
- provides ``lower_items``.
-
- All keys are expected to be strings. The structure remembers the
- case of the last key to be set, and ``iter(instance)``,
- ``keys()``, ``items()``, ``iterkeys()``, and ``iteritems()``
- will contain case-sensitive keys. However, querying and contains
- testing is case insensitive::
-
- cid = CaseInsensitiveDict()
- cid['Accept'] = 'application/json'
- cid['aCCEPT'] == 'application/json' # True
- list(cid) == ['Accept'] # True
-
- For example, ``headers['content-encoding']`` will return the
- value of a ``'Content-Encoding'`` response header, regardless
- of how the header name was originally stored.
-
- If the constructor, ``.update``, or equality comparison
- operations are given keys that have equal ``.lower()``s, the
- behavior is undefined.
- """
-
- def __init__(self, data=None, **kwargs):
- self._store = OrderedDict()
- if data is None:
- data = {}
- self.update(data, **kwargs)
-
- def __setitem__(self, key, value):
- # Use the lowercased key for lookups, but store the actual
- # key alongside the value.
- self._store[key.lower()] = (key, value)
-
- def __getitem__(self, key):
- return self._store[key.lower()][1]
-
- def __delitem__(self, key):
- del self._store[key.lower()]
-
- def __iter__(self):
- return (casedkey for casedkey, mappedvalue in self._store.values())
-
- def __len__(self):
- return len(self._store)
-
- def lower_items(self):
- """Like iteritems(), but with all lowercase keys."""
- return ((lowerkey, keyval[1]) for (lowerkey, keyval) in self._store.items())
-
- def __eq__(self, other):
- if isinstance(other, Mapping):
- other = CaseInsensitiveDict(other)
- else:
- return NotImplemented
- # Compare insensitively
- return dict(self.lower_items()) == dict(other.lower_items())
-
- # Copy is required
- def copy(self):
- return CaseInsensitiveDict(self._store.values())
-
- def __repr__(self):
- return str(dict(self.items()))
-
-
-class LookupDict(dict):
- """Dictionary lookup object."""
-
- def __init__(self, name=None):
- self.name = name
- super().__init__()
-
- def __repr__(self):
- return f""
-
- def __getitem__(self, key):
- # We allow fall-through here, so values default to None
-
- return self.__dict__.get(key, None)
-
- def get(self, key, default=None):
- return self.__dict__.get(key, default)
diff --git a/.venv/lib/python3.12/site-packages/requests/utils.py b/.venv/lib/python3.12/site-packages/requests/utils.py
deleted file mode 100644
index ae6c42f..0000000
--- a/.venv/lib/python3.12/site-packages/requests/utils.py
+++ /dev/null
@@ -1,1096 +0,0 @@
-"""
-requests.utils
-~~~~~~~~~~~~~~
-
-This module provides utility functions that are used within Requests
-that are also useful for external consumption.
-"""
-
-import codecs
-import contextlib
-import io
-import os
-import re
-import socket
-import struct
-import sys
-import tempfile
-import warnings
-import zipfile
-from collections import OrderedDict
-
-from urllib3.util import make_headers, parse_url
-
-from . import certs
-from .__version__ import __version__
-
-# to_native_string is unused here, but imported here for backwards compatibility
-from ._internal_utils import ( # noqa: F401
- _HEADER_VALIDATORS_BYTE,
- _HEADER_VALIDATORS_STR,
- HEADER_VALIDATORS,
- to_native_string,
-)
-from .compat import (
- Mapping,
- basestring,
- bytes,
- getproxies,
- getproxies_environment,
- integer_types,
-)
-from .compat import parse_http_list as _parse_list_header
-from .compat import (
- proxy_bypass,
- proxy_bypass_environment,
- quote,
- str,
- unquote,
- urlparse,
- urlunparse,
-)
-from .cookies import cookiejar_from_dict
-from .exceptions import (
- FileModeWarning,
- InvalidHeader,
- InvalidURL,
- UnrewindableBodyError,
-)
-from .structures import CaseInsensitiveDict
-
-NETRC_FILES = (".netrc", "_netrc")
-
-DEFAULT_CA_BUNDLE_PATH = certs.where()
-
-DEFAULT_PORTS = {"http": 80, "https": 443}
-
-# Ensure that ', ' is used to preserve previous delimiter behavior.
-DEFAULT_ACCEPT_ENCODING = ", ".join(
- re.split(r",\s*", make_headers(accept_encoding=True)["accept-encoding"])
-)
-
-
-if sys.platform == "win32":
- # provide a proxy_bypass version on Windows without DNS lookups
-
- def proxy_bypass_registry(host):
- try:
- import winreg
- except ImportError:
- return False
-
- try:
- internetSettings = winreg.OpenKey(
- winreg.HKEY_CURRENT_USER,
- r"Software\Microsoft\Windows\CurrentVersion\Internet Settings",
- )
- # ProxyEnable could be REG_SZ or REG_DWORD, normalizing it
- proxyEnable = int(winreg.QueryValueEx(internetSettings, "ProxyEnable")[0])
- # ProxyOverride is almost always a string
- proxyOverride = winreg.QueryValueEx(internetSettings, "ProxyOverride")[0]
- except (OSError, ValueError):
- return False
- if not proxyEnable or not proxyOverride:
- return False
-
- # make a check value list from the registry entry: replace the
- # '' string by the localhost entry and the corresponding
- # canonical entry.
- proxyOverride = proxyOverride.split(";")
- # filter out empty strings to avoid re.match return true in the following code.
- proxyOverride = filter(None, proxyOverride)
- # now check if we match one of the registry values.
- for test in proxyOverride:
- if test == "":
- if "." not in host:
- return True
- test = test.replace(".", r"\.") # mask dots
- test = test.replace("*", r".*") # change glob sequence
- test = test.replace("?", r".") # change glob char
- if re.match(test, host, re.I):
- return True
- return False
-
- def proxy_bypass(host): # noqa
- """Return True, if the host should be bypassed.
-
- Checks proxy settings gathered from the environment, if specified,
- or the registry.
- """
- if getproxies_environment():
- return proxy_bypass_environment(host)
- else:
- return proxy_bypass_registry(host)
-
-
-def dict_to_sequence(d):
- """Returns an internal sequence dictionary update."""
-
- if hasattr(d, "items"):
- d = d.items()
-
- return d
-
-
-def super_len(o):
- total_length = None
- current_position = 0
-
- if isinstance(o, str):
- o = o.encode("utf-8")
-
- if hasattr(o, "__len__"):
- total_length = len(o)
-
- elif hasattr(o, "len"):
- total_length = o.len
-
- elif hasattr(o, "fileno"):
- try:
- fileno = o.fileno()
- except (io.UnsupportedOperation, AttributeError):
- # AttributeError is a surprising exception, seeing as how we've just checked
- # that `hasattr(o, 'fileno')`. It happens for objects obtained via
- # `Tarfile.extractfile()`, per issue 5229.
- pass
- else:
- total_length = os.fstat(fileno).st_size
-
- # Having used fstat to determine the file length, we need to
- # confirm that this file was opened up in binary mode.
- if "b" not in o.mode:
- warnings.warn(
- (
- "Requests has determined the content-length for this "
- "request using the binary size of the file: however, the "
- "file has been opened in text mode (i.e. without the 'b' "
- "flag in the mode). This may lead to an incorrect "
- "content-length. In Requests 3.0, support will be removed "
- "for files in text mode."
- ),
- FileModeWarning,
- )
-
- if hasattr(o, "tell"):
- try:
- current_position = o.tell()
- except OSError:
- # This can happen in some weird situations, such as when the file
- # is actually a special file descriptor like stdin. In this
- # instance, we don't know what the length is, so set it to zero and
- # let requests chunk it instead.
- if total_length is not None:
- current_position = total_length
- else:
- if hasattr(o, "seek") and total_length is None:
- # StringIO and BytesIO have seek but no usable fileno
- try:
- # seek to end of file
- o.seek(0, 2)
- total_length = o.tell()
-
- # seek back to current position to support
- # partially read file-like objects
- o.seek(current_position or 0)
- except OSError:
- total_length = 0
-
- if total_length is None:
- total_length = 0
-
- return max(0, total_length - current_position)
-
-
-def get_netrc_auth(url, raise_errors=False):
- """Returns the Requests tuple auth for a given url from netrc."""
-
- netrc_file = os.environ.get("NETRC")
- if netrc_file is not None:
- netrc_locations = (netrc_file,)
- else:
- netrc_locations = (f"~/{f}" for f in NETRC_FILES)
-
- try:
- from netrc import NetrcParseError, netrc
-
- netrc_path = None
-
- for f in netrc_locations:
- try:
- loc = os.path.expanduser(f)
- except KeyError:
- # os.path.expanduser can fail when $HOME is undefined and
- # getpwuid fails. See https://bugs.python.org/issue20164 &
- # https://github.com/psf/requests/issues/1846
- return
-
- if os.path.exists(loc):
- netrc_path = loc
- break
-
- # Abort early if there isn't one.
- if netrc_path is None:
- return
-
- ri = urlparse(url)
-
- # Strip port numbers from netloc. This weird `if...encode`` dance is
- # used for Python 3.2, which doesn't support unicode literals.
- splitstr = b":"
- if isinstance(url, str):
- splitstr = splitstr.decode("ascii")
- host = ri.netloc.split(splitstr)[0]
-
- try:
- _netrc = netrc(netrc_path).authenticators(host)
- if _netrc:
- # Return with login / password
- login_i = 0 if _netrc[0] else 1
- return (_netrc[login_i], _netrc[2])
- except (NetrcParseError, OSError):
- # If there was a parsing error or a permissions issue reading the file,
- # we'll just skip netrc auth unless explicitly asked to raise errors.
- if raise_errors:
- raise
-
- # App Engine hackiness.
- except (ImportError, AttributeError):
- pass
-
-
-def guess_filename(obj):
- """Tries to guess the filename of the given object."""
- name = getattr(obj, "name", None)
- if name and isinstance(name, basestring) and name[0] != "<" and name[-1] != ">":
- return os.path.basename(name)
-
-
-def extract_zipped_paths(path):
- """Replace nonexistent paths that look like they refer to a member of a zip
- archive with the location of an extracted copy of the target, or else
- just return the provided path unchanged.
- """
- if os.path.exists(path):
- # this is already a valid path, no need to do anything further
- return path
-
- # find the first valid part of the provided path and treat that as a zip archive
- # assume the rest of the path is the name of a member in the archive
- archive, member = os.path.split(path)
- while archive and not os.path.exists(archive):
- archive, prefix = os.path.split(archive)
- if not prefix:
- # If we don't check for an empty prefix after the split (in other words, archive remains unchanged after the split),
- # we _can_ end up in an infinite loop on a rare corner case affecting a small number of users
- break
- member = "/".join([prefix, member])
-
- if not zipfile.is_zipfile(archive):
- return path
-
- zip_file = zipfile.ZipFile(archive)
- if member not in zip_file.namelist():
- return path
-
- # we have a valid zip archive and a valid member of that archive
- tmp = tempfile.gettempdir()
- extracted_path = os.path.join(tmp, member.split("/")[-1])
- if not os.path.exists(extracted_path):
- # use read + write to avoid the creating nested folders, we only want the file, avoids mkdir racing condition
- with atomic_open(extracted_path) as file_handler:
- file_handler.write(zip_file.read(member))
- return extracted_path
-
-
-@contextlib.contextmanager
-def atomic_open(filename):
- """Write a file to the disk in an atomic fashion"""
- tmp_descriptor, tmp_name = tempfile.mkstemp(dir=os.path.dirname(filename))
- try:
- with os.fdopen(tmp_descriptor, "wb") as tmp_handler:
- yield tmp_handler
- os.replace(tmp_name, filename)
- except BaseException:
- os.remove(tmp_name)
- raise
-
-
-def from_key_val_list(value):
- """Take an object and test to see if it can be represented as a
- dictionary. Unless it can not be represented as such, return an
- OrderedDict, e.g.,
-
- ::
-
- >>> from_key_val_list([('key', 'val')])
- OrderedDict([('key', 'val')])
- >>> from_key_val_list('string')
- Traceback (most recent call last):
- ...
- ValueError: cannot encode objects that are not 2-tuples
- >>> from_key_val_list({'key': 'val'})
- OrderedDict([('key', 'val')])
-
- :rtype: OrderedDict
- """
- if value is None:
- return None
-
- if isinstance(value, (str, bytes, bool, int)):
- raise ValueError("cannot encode objects that are not 2-tuples")
-
- return OrderedDict(value)
-
-
-def to_key_val_list(value):
- """Take an object and test to see if it can be represented as a
- dictionary. If it can be, return a list of tuples, e.g.,
-
- ::
-
- >>> to_key_val_list([('key', 'val')])
- [('key', 'val')]
- >>> to_key_val_list({'key': 'val'})
- [('key', 'val')]
- >>> to_key_val_list('string')
- Traceback (most recent call last):
- ...
- ValueError: cannot encode objects that are not 2-tuples
-
- :rtype: list
- """
- if value is None:
- return None
-
- if isinstance(value, (str, bytes, bool, int)):
- raise ValueError("cannot encode objects that are not 2-tuples")
-
- if isinstance(value, Mapping):
- value = value.items()
-
- return list(value)
-
-
-# From mitsuhiko/werkzeug (used with permission).
-def parse_list_header(value):
- """Parse lists as described by RFC 2068 Section 2.
-
- In particular, parse comma-separated lists where the elements of
- the list may include quoted-strings. A quoted-string could
- contain a comma. A non-quoted string could have quotes in the
- middle. Quotes are removed automatically after parsing.
-
- It basically works like :func:`parse_set_header` just that items
- may appear multiple times and case sensitivity is preserved.
-
- The return value is a standard :class:`list`:
-
- >>> parse_list_header('token, "quoted value"')
- ['token', 'quoted value']
-
- To create a header from the :class:`list` again, use the
- :func:`dump_header` function.
-
- :param value: a string with a list header.
- :return: :class:`list`
- :rtype: list
- """
- result = []
- for item in _parse_list_header(value):
- if item[:1] == item[-1:] == '"':
- item = unquote_header_value(item[1:-1])
- result.append(item)
- return result
-
-
-# From mitsuhiko/werkzeug (used with permission).
-def parse_dict_header(value):
- """Parse lists of key, value pairs as described by RFC 2068 Section 2 and
- convert them into a python dict:
-
- >>> d = parse_dict_header('foo="is a fish", bar="as well"')
- >>> type(d) is dict
- True
- >>> sorted(d.items())
- [('bar', 'as well'), ('foo', 'is a fish')]
-
- If there is no value for a key it will be `None`:
-
- >>> parse_dict_header('key_without_value')
- {'key_without_value': None}
-
- To create a header from the :class:`dict` again, use the
- :func:`dump_header` function.
-
- :param value: a string with a dict header.
- :return: :class:`dict`
- :rtype: dict
- """
- result = {}
- for item in _parse_list_header(value):
- if "=" not in item:
- result[item] = None
- continue
- name, value = item.split("=", 1)
- if value[:1] == value[-1:] == '"':
- value = unquote_header_value(value[1:-1])
- result[name] = value
- return result
-
-
-# From mitsuhiko/werkzeug (used with permission).
-def unquote_header_value(value, is_filename=False):
- r"""Unquotes a header value. (Reversal of :func:`quote_header_value`).
- This does not use the real unquoting but what browsers are actually
- using for quoting.
-
- :param value: the header value to unquote.
- :rtype: str
- """
- if value and value[0] == value[-1] == '"':
- # this is not the real unquoting, but fixing this so that the
- # RFC is met will result in bugs with internet explorer and
- # probably some other browsers as well. IE for example is
- # uploading files with "C:\foo\bar.txt" as filename
- value = value[1:-1]
-
- # if this is a filename and the starting characters look like
- # a UNC path, then just return the value without quotes. Using the
- # replace sequence below on a UNC path has the effect of turning
- # the leading double slash into a single slash and then
- # _fix_ie_filename() doesn't work correctly. See #458.
- if not is_filename or value[:2] != "\\\\":
- return value.replace("\\\\", "\\").replace('\\"', '"')
- return value
-
-
-def dict_from_cookiejar(cj):
- """Returns a key/value dictionary from a CookieJar.
-
- :param cj: CookieJar object to extract cookies from.
- :rtype: dict
- """
-
- cookie_dict = {cookie.name: cookie.value for cookie in cj}
- return cookie_dict
-
-
-def add_dict_to_cookiejar(cj, cookie_dict):
- """Returns a CookieJar from a key/value dictionary.
-
- :param cj: CookieJar to insert cookies into.
- :param cookie_dict: Dict of key/values to insert into CookieJar.
- :rtype: CookieJar
- """
-
- return cookiejar_from_dict(cookie_dict, cj)
-
-
-def get_encodings_from_content(content):
- """Returns encodings from given content string.
-
- :param content: bytestring to extract encodings from.
- """
- warnings.warn(
- (
- "In requests 3.0, get_encodings_from_content will be removed. For "
- "more information, please see the discussion on issue #2266. (This"
- " warning should only appear once.)"
- ),
- DeprecationWarning,
- )
-
- charset_re = re.compile(r']', flags=re.I)
- pragma_re = re.compile(r']', flags=re.I)
- xml_re = re.compile(r'^<\?xml.*?encoding=["\']*(.+?)["\'>]')
-
- return (
- charset_re.findall(content)
- + pragma_re.findall(content)
- + xml_re.findall(content)
- )
-
-
-def _parse_content_type_header(header):
- """Returns content type and parameters from given header
-
- :param header: string
- :return: tuple containing content type and dictionary of
- parameters
- """
-
- tokens = header.split(";")
- content_type, params = tokens[0].strip(), tokens[1:]
- params_dict = {}
- items_to_strip = "\"' "
-
- for param in params:
- param = param.strip()
- if param:
- key, value = param, True
- index_of_equals = param.find("=")
- if index_of_equals != -1:
- key = param[:index_of_equals].strip(items_to_strip)
- value = param[index_of_equals + 1 :].strip(items_to_strip)
- params_dict[key.lower()] = value
- return content_type, params_dict
-
-
-def get_encoding_from_headers(headers):
- """Returns encodings from given HTTP Header Dict.
-
- :param headers: dictionary to extract encoding from.
- :rtype: str
- """
-
- content_type = headers.get("content-type")
-
- if not content_type:
- return None
-
- content_type, params = _parse_content_type_header(content_type)
-
- if "charset" in params:
- return params["charset"].strip("'\"")
-
- if "text" in content_type:
- return "ISO-8859-1"
-
- if "application/json" in content_type:
- # Assume UTF-8 based on RFC 4627: https://www.ietf.org/rfc/rfc4627.txt since the charset was unset
- return "utf-8"
-
-
-def stream_decode_response_unicode(iterator, r):
- """Stream decodes an iterator."""
-
- if r.encoding is None:
- yield from iterator
- return
-
- decoder = codecs.getincrementaldecoder(r.encoding)(errors="replace")
- for chunk in iterator:
- rv = decoder.decode(chunk)
- if rv:
- yield rv
- rv = decoder.decode(b"", final=True)
- if rv:
- yield rv
-
-
-def iter_slices(string, slice_length):
- """Iterate over slices of a string."""
- pos = 0
- if slice_length is None or slice_length <= 0:
- slice_length = len(string)
- while pos < len(string):
- yield string[pos : pos + slice_length]
- pos += slice_length
-
-
-def get_unicode_from_response(r):
- """Returns the requested content back in unicode.
-
- :param r: Response object to get unicode content from.
-
- Tried:
-
- 1. charset from content-type
- 2. fall back and replace all unicode characters
-
- :rtype: str
- """
- warnings.warn(
- (
- "In requests 3.0, get_unicode_from_response will be removed. For "
- "more information, please see the discussion on issue #2266. (This"
- " warning should only appear once.)"
- ),
- DeprecationWarning,
- )
-
- tried_encodings = []
-
- # Try charset from content-type
- encoding = get_encoding_from_headers(r.headers)
-
- if encoding:
- try:
- return str(r.content, encoding)
- except UnicodeError:
- tried_encodings.append(encoding)
-
- # Fall back:
- try:
- return str(r.content, encoding, errors="replace")
- except TypeError:
- return r.content
-
-
-# The unreserved URI characters (RFC 3986)
-UNRESERVED_SET = frozenset(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~"
-)
-
-
-def unquote_unreserved(uri):
- """Un-escape any percent-escape sequences in a URI that are unreserved
- characters. This leaves all reserved, illegal and non-ASCII bytes encoded.
-
- :rtype: str
- """
- parts = uri.split("%")
- for i in range(1, len(parts)):
- h = parts[i][0:2]
- if len(h) == 2 and h.isalnum():
- try:
- c = chr(int(h, 16))
- except ValueError:
- raise InvalidURL(f"Invalid percent-escape sequence: '{h}'")
-
- if c in UNRESERVED_SET:
- parts[i] = c + parts[i][2:]
- else:
- parts[i] = f"%{parts[i]}"
- else:
- parts[i] = f"%{parts[i]}"
- return "".join(parts)
-
-
-def requote_uri(uri):
- """Re-quote the given URI.
-
- This function passes the given URI through an unquote/quote cycle to
- ensure that it is fully and consistently quoted.
-
- :rtype: str
- """
- safe_with_percent = "!#$%&'()*+,/:;=?@[]~"
- safe_without_percent = "!#$&'()*+,/:;=?@[]~"
- try:
- # Unquote only the unreserved characters
- # Then quote only illegal characters (do not quote reserved,
- # unreserved, or '%')
- return quote(unquote_unreserved(uri), safe=safe_with_percent)
- except InvalidURL:
- # We couldn't unquote the given URI, so let's try quoting it, but
- # there may be unquoted '%'s in the URI. We need to make sure they're
- # properly quoted so they do not cause issues elsewhere.
- return quote(uri, safe=safe_without_percent)
-
-
-def address_in_network(ip, net):
- """This function allows you to check if an IP belongs to a network subnet
-
- Example: returns True if ip = 192.168.1.1 and net = 192.168.1.0/24
- returns False if ip = 192.168.1.1 and net = 192.168.100.0/24
-
- :rtype: bool
- """
- ipaddr = struct.unpack("=L", socket.inet_aton(ip))[0]
- netaddr, bits = net.split("/")
- netmask = struct.unpack("=L", socket.inet_aton(dotted_netmask(int(bits))))[0]
- network = struct.unpack("=L", socket.inet_aton(netaddr))[0] & netmask
- return (ipaddr & netmask) == (network & netmask)
-
-
-def dotted_netmask(mask):
- """Converts mask from /xx format to xxx.xxx.xxx.xxx
-
- Example: if mask is 24 function returns 255.255.255.0
-
- :rtype: str
- """
- bits = 0xFFFFFFFF ^ (1 << 32 - mask) - 1
- return socket.inet_ntoa(struct.pack(">I", bits))
-
-
-def is_ipv4_address(string_ip):
- """
- :rtype: bool
- """
- try:
- socket.inet_aton(string_ip)
- except OSError:
- return False
- return True
-
-
-def is_valid_cidr(string_network):
- """
- Very simple check of the cidr format in no_proxy variable.
-
- :rtype: bool
- """
- if string_network.count("/") == 1:
- try:
- mask = int(string_network.split("/")[1])
- except ValueError:
- return False
-
- if mask < 1 or mask > 32:
- return False
-
- try:
- socket.inet_aton(string_network.split("/")[0])
- except OSError:
- return False
- else:
- return False
- return True
-
-
-@contextlib.contextmanager
-def set_environ(env_name, value):
- """Set the environment variable 'env_name' to 'value'
-
- Save previous value, yield, and then restore the previous value stored in
- the environment variable 'env_name'.
-
- If 'value' is None, do nothing"""
- value_changed = value is not None
- if value_changed:
- old_value = os.environ.get(env_name)
- os.environ[env_name] = value
- try:
- yield
- finally:
- if value_changed:
- if old_value is None:
- del os.environ[env_name]
- else:
- os.environ[env_name] = old_value
-
-
-def should_bypass_proxies(url, no_proxy):
- """
- Returns whether we should bypass proxies or not.
-
- :rtype: bool
- """
-
- # Prioritize lowercase environment variables over uppercase
- # to keep a consistent behaviour with other http projects (curl, wget).
- def get_proxy(key):
- return os.environ.get(key) or os.environ.get(key.upper())
-
- # First check whether no_proxy is defined. If it is, check that the URL
- # we're getting isn't in the no_proxy list.
- no_proxy_arg = no_proxy
- if no_proxy is None:
- no_proxy = get_proxy("no_proxy")
- parsed = urlparse(url)
-
- if parsed.hostname is None:
- # URLs don't always have hostnames, e.g. file:/// urls.
- return True
-
- if no_proxy:
- # We need to check whether we match here. We need to see if we match
- # the end of the hostname, both with and without the port.
- no_proxy = (host for host in no_proxy.replace(" ", "").split(",") if host)
-
- if is_ipv4_address(parsed.hostname):
- for proxy_ip in no_proxy:
- if is_valid_cidr(proxy_ip):
- if address_in_network(parsed.hostname, proxy_ip):
- return True
- elif parsed.hostname == proxy_ip:
- # If no_proxy ip was defined in plain IP notation instead of cidr notation &
- # matches the IP of the index
- return True
- else:
- host_with_port = parsed.hostname
- if parsed.port:
- host_with_port += f":{parsed.port}"
-
- for host in no_proxy:
- if parsed.hostname.endswith(host) or host_with_port.endswith(host):
- # The URL does match something in no_proxy, so we don't want
- # to apply the proxies on this URL.
- return True
-
- with set_environ("no_proxy", no_proxy_arg):
- # parsed.hostname can be `None` in cases such as a file URI.
- try:
- bypass = proxy_bypass(parsed.hostname)
- except (TypeError, socket.gaierror):
- bypass = False
-
- if bypass:
- return True
-
- return False
-
-
-def get_environ_proxies(url, no_proxy=None):
- """
- Return a dict of environment proxies.
-
- :rtype: dict
- """
- if should_bypass_proxies(url, no_proxy=no_proxy):
- return {}
- else:
- return getproxies()
-
-
-def select_proxy(url, proxies):
- """Select a proxy for the url, if applicable.
-
- :param url: The url being for the request
- :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs
- """
- proxies = proxies or {}
- urlparts = urlparse(url)
- if urlparts.hostname is None:
- return proxies.get(urlparts.scheme, proxies.get("all"))
-
- proxy_keys = [
- urlparts.scheme + "://" + urlparts.hostname,
- urlparts.scheme,
- "all://" + urlparts.hostname,
- "all",
- ]
- proxy = None
- for proxy_key in proxy_keys:
- if proxy_key in proxies:
- proxy = proxies[proxy_key]
- break
-
- return proxy
-
-
-def resolve_proxies(request, proxies, trust_env=True):
- """This method takes proxy information from a request and configuration
- input to resolve a mapping of target proxies. This will consider settings
- such as NO_PROXY to strip proxy configurations.
-
- :param request: Request or PreparedRequest
- :param proxies: A dictionary of schemes or schemes and hosts to proxy URLs
- :param trust_env: Boolean declaring whether to trust environment configs
-
- :rtype: dict
- """
- proxies = proxies if proxies is not None else {}
- url = request.url
- scheme = urlparse(url).scheme
- no_proxy = proxies.get("no_proxy")
- new_proxies = proxies.copy()
-
- if trust_env and not should_bypass_proxies(url, no_proxy=no_proxy):
- environ_proxies = get_environ_proxies(url, no_proxy=no_proxy)
-
- proxy = environ_proxies.get(scheme, environ_proxies.get("all"))
-
- if proxy:
- new_proxies.setdefault(scheme, proxy)
- return new_proxies
-
-
-def default_user_agent(name="python-requests"):
- """
- Return a string representing the default user agent.
-
- :rtype: str
- """
- return f"{name}/{__version__}"
-
-
-def default_headers():
- """
- :rtype: requests.structures.CaseInsensitiveDict
- """
- return CaseInsensitiveDict(
- {
- "User-Agent": default_user_agent(),
- "Accept-Encoding": DEFAULT_ACCEPT_ENCODING,
- "Accept": "*/*",
- "Connection": "keep-alive",
- }
- )
-
-
-def parse_header_links(value):
- """Return a list of parsed link headers proxies.
-
- i.e. Link: ; rel=front; type="image/jpeg",; rel=back;type="image/jpeg"
-
- :rtype: list
- """
-
- links = []
-
- replace_chars = " '\""
-
- value = value.strip(replace_chars)
- if not value:
- return links
-
- for val in re.split(", *<", value):
- try:
- url, params = val.split(";", 1)
- except ValueError:
- url, params = val, ""
-
- link = {"url": url.strip("<> '\"")}
-
- for param in params.split(";"):
- try:
- key, value = param.split("=")
- except ValueError:
- break
-
- link[key.strip(replace_chars)] = value.strip(replace_chars)
-
- links.append(link)
-
- return links
-
-
-# Null bytes; no need to recreate these on each call to guess_json_utf
-_null = "\x00".encode("ascii") # encoding to ASCII for Python 3
-_null2 = _null * 2
-_null3 = _null * 3
-
-
-def guess_json_utf(data):
- """
- :rtype: str
- """
- # JSON always starts with two ASCII characters, so detection is as
- # easy as counting the nulls and from their location and count
- # determine the encoding. Also detect a BOM, if present.
- sample = data[:4]
- if sample in (codecs.BOM_UTF32_LE, codecs.BOM_UTF32_BE):
- return "utf-32" # BOM included
- if sample[:3] == codecs.BOM_UTF8:
- return "utf-8-sig" # BOM included, MS style (discouraged)
- if sample[:2] in (codecs.BOM_UTF16_LE, codecs.BOM_UTF16_BE):
- return "utf-16" # BOM included
- nullcount = sample.count(_null)
- if nullcount == 0:
- return "utf-8"
- if nullcount == 2:
- if sample[::2] == _null2: # 1st and 3rd are null
- return "utf-16-be"
- if sample[1::2] == _null2: # 2nd and 4th are null
- return "utf-16-le"
- # Did not detect 2 valid UTF-16 ascii-range characters
- if nullcount == 3:
- if sample[:3] == _null3:
- return "utf-32-be"
- if sample[1:] == _null3:
- return "utf-32-le"
- # Did not detect a valid UTF-32 ascii-range character
- return None
-
-
-def prepend_scheme_if_needed(url, new_scheme):
- """Given a URL that may or may not have a scheme, prepend the given scheme.
- Does not replace a present scheme with the one provided as an argument.
-
- :rtype: str
- """
- parsed = parse_url(url)
- scheme, auth, host, port, path, query, fragment = parsed
-
- # A defect in urlparse determines that there isn't a netloc present in some
- # urls. We previously assumed parsing was overly cautious, and swapped the
- # netloc and path. Due to a lack of tests on the original defect, this is
- # maintained with parse_url for backwards compatibility.
- netloc = parsed.netloc
- if not netloc:
- netloc, path = path, netloc
-
- if auth:
- # parse_url doesn't provide the netloc with auth
- # so we'll add it ourselves.
- netloc = "@".join([auth, netloc])
- if scheme is None:
- scheme = new_scheme
- if path is None:
- path = ""
-
- return urlunparse((scheme, netloc, path, "", query, fragment))
-
-
-def get_auth_from_url(url):
- """Given a url with authentication components, extract them into a tuple of
- username,password.
-
- :rtype: (str,str)
- """
- parsed = urlparse(url)
-
- try:
- auth = (unquote(parsed.username), unquote(parsed.password))
- except (AttributeError, TypeError):
- auth = ("", "")
-
- return auth
-
-
-def check_header_validity(header):
- """Verifies that header parts don't contain leading whitespace
- reserved characters, or return characters.
-
- :param header: tuple, in the format (name, value).
- """
- name, value = header
- _validate_header_part(header, name, 0)
- _validate_header_part(header, value, 1)
-
-
-def _validate_header_part(header, header_part, header_validator_index):
- if isinstance(header_part, str):
- validator = _HEADER_VALIDATORS_STR[header_validator_index]
- elif isinstance(header_part, bytes):
- validator = _HEADER_VALIDATORS_BYTE[header_validator_index]
- else:
- raise InvalidHeader(
- f"Header part ({header_part!r}) from {header} "
- f"must be of type str or bytes, not {type(header_part)}"
- )
-
- if not validator.match(header_part):
- header_kind = "name" if header_validator_index == 0 else "value"
- raise InvalidHeader(
- f"Invalid leading whitespace, reserved character(s), or return "
- f"character(s) in header {header_kind}: {header_part!r}"
- )
-
-
-def urldefragauth(url):
- """
- Given a url remove the fragment and the authentication part.
-
- :rtype: str
- """
- scheme, netloc, path, params, query, fragment = urlparse(url)
-
- # see func:`prepend_scheme_if_needed`
- if not netloc:
- netloc, path = path, netloc
-
- netloc = netloc.rsplit("@", 1)[-1]
-
- return urlunparse((scheme, netloc, path, params, query, ""))
-
-
-def rewind_body(prepared_request):
- """Move file pointer back to its recorded starting position
- so it can be read again on redirect.
- """
- body_seek = getattr(prepared_request.body, "seek", None)
- if body_seek is not None and isinstance(
- prepared_request._body_position, integer_types
- ):
- try:
- body_seek(prepared_request._body_position)
- except OSError:
- raise UnrewindableBodyError(
- "An error occurred when rewinding request body for redirect."
- )
- else:
- raise UnrewindableBodyError("Unable to rewind request body for redirect.")
diff --git a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/INSTALLER b/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/INSTALLER
deleted file mode 100644
index a1b589e..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/INSTALLER
+++ /dev/null
@@ -1 +0,0 @@
-pip
diff --git a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/METADATA b/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/METADATA
deleted file mode 100644
index baeb1dd..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/METADATA
+++ /dev/null
@@ -1,154 +0,0 @@
-Metadata-Version: 2.3
-Name: urllib3
-Version: 2.2.2
-Summary: HTTP library with thread-safe connection pooling, file post, and more.
-Project-URL: Changelog, https://github.com/urllib3/urllib3/blob/main/CHANGES.rst
-Project-URL: Documentation, https://urllib3.readthedocs.io
-Project-URL: Code, https://github.com/urllib3/urllib3
-Project-URL: Issue tracker, https://github.com/urllib3/urllib3/issues
-Author-email: Andrey Petrov
-Maintainer-email: Seth Michael Larson , Quentin Pradet , Illia Volochii
-License-File: LICENSE.txt
-Keywords: filepost,http,httplib,https,pooling,ssl,threadsafe,urllib
-Classifier: Environment :: Web Environment
-Classifier: Intended Audience :: Developers
-Classifier: License :: OSI Approved :: MIT License
-Classifier: Operating System :: OS Independent
-Classifier: Programming Language :: Python
-Classifier: Programming Language :: Python :: 3
-Classifier: Programming Language :: Python :: 3 :: Only
-Classifier: Programming Language :: Python :: 3.8
-Classifier: Programming Language :: Python :: 3.9
-Classifier: Programming Language :: Python :: 3.10
-Classifier: Programming Language :: Python :: 3.11
-Classifier: Programming Language :: Python :: 3.12
-Classifier: Programming Language :: Python :: Implementation :: CPython
-Classifier: Programming Language :: Python :: Implementation :: PyPy
-Classifier: Topic :: Internet :: WWW/HTTP
-Classifier: Topic :: Software Development :: Libraries
-Requires-Python: >=3.8
-Provides-Extra: brotli
-Requires-Dist: brotli>=1.0.9; (platform_python_implementation == 'CPython') and extra == 'brotli'
-Requires-Dist: brotlicffi>=0.8.0; (platform_python_implementation != 'CPython') and extra == 'brotli'
-Provides-Extra: h2
-Requires-Dist: h2<5,>=4; extra == 'h2'
-Provides-Extra: socks
-Requires-Dist: pysocks!=1.5.7,<2.0,>=1.5.6; extra == 'socks'
-Provides-Extra: zstd
-Requires-Dist: zstandard>=0.18.0; extra == 'zstd'
-Description-Content-Type: text/markdown
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-urllib3 is a powerful, *user-friendly* HTTP client for Python. Much of the
-Python ecosystem already uses urllib3 and you should too.
-urllib3 brings many critical features that are missing from the Python
-standard libraries:
-
-- Thread safety.
-- Connection pooling.
-- Client-side SSL/TLS verification.
-- File uploads with multipart encoding.
-- Helpers for retrying requests and dealing with HTTP redirects.
-- Support for gzip, deflate, brotli, and zstd encoding.
-- Proxy support for HTTP and SOCKS.
-- 100% test coverage.
-
-urllib3 is powerful and easy to use:
-
-```python3
->>> import urllib3
->>> resp = urllib3.request("GET", "http://httpbin.org/robots.txt")
->>> resp.status
-200
->>> resp.data
-b"User-agent: *\nDisallow: /deny\n"
-```
-
-## Installing
-
-urllib3 can be installed with [pip](https://pip.pypa.io):
-
-```bash
-$ python -m pip install urllib3
-```
-
-Alternatively, you can grab the latest source code from [GitHub](https://github.com/urllib3/urllib3):
-
-```bash
-$ git clone https://github.com/urllib3/urllib3.git
-$ cd urllib3
-$ pip install .
-```
-
-
-## Documentation
-
-urllib3 has usage and reference documentation at [urllib3.readthedocs.io](https://urllib3.readthedocs.io).
-
-
-## Community
-
-urllib3 has a [community Discord channel](https://discord.gg/urllib3) for asking questions and
-collaborating with other contributors. Drop by and say hello 👋
-
-
-## Contributing
-
-urllib3 happily accepts contributions. Please see our
-[contributing documentation](https://urllib3.readthedocs.io/en/latest/contributing.html)
-for some tips on getting started.
-
-
-## Security Disclosures
-
-To report a security vulnerability, please use the
-[Tidelift security contact](https://tidelift.com/security).
-Tidelift will coordinate the fix and disclosure with maintainers.
-
-
-## Maintainers
-
-- [@sethmlarson](https://github.com/sethmlarson) (Seth M. Larson)
-- [@pquentin](https://github.com/pquentin) (Quentin Pradet)
-- [@illia-v](https://github.com/illia-v) (Illia Volochii)
-- [@theacodes](https://github.com/theacodes) (Thea Flowers)
-- [@haikuginger](https://github.com/haikuginger) (Jess Shapiro)
-- [@lukasa](https://github.com/lukasa) (Cory Benfield)
-- [@sigmavirus24](https://github.com/sigmavirus24) (Ian Stapleton Cordasco)
-- [@shazow](https://github.com/shazow) (Andrey Petrov)
-
-👋
-
-
-## Sponsorship
-
-If your company benefits from this library, please consider [sponsoring its
-development](https://urllib3.readthedocs.io/en/latest/sponsors.html).
-
-
-## For Enterprise
-
-Professional support for urllib3 is available as part of the [Tidelift
-Subscription][1]. Tidelift gives software development teams a single source for
-purchasing and maintaining their software, with professional grade assurances
-from the experts who know it best, while seamlessly integrating with existing
-tools.
-
-[1]: https://tidelift.com/subscription/pkg/pypi-urllib3?utm_source=pypi-urllib3&utm_medium=referral&utm_campaign=readme
diff --git a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/RECORD b/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/RECORD
deleted file mode 100644
index 7c9ac85..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/RECORD
+++ /dev/null
@@ -1,75 +0,0 @@
-urllib3-2.2.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
-urllib3-2.2.2.dist-info/METADATA,sha256=1lFmEu2KSrvTuzjDf_UQxhN3hm5dHoUoUe8iX0XpK20,6434
-urllib3-2.2.2.dist-info/RECORD,,
-urllib3-2.2.2.dist-info/WHEEL,sha256=zEMcRr9Kr03x1ozGwg5v9NQBKn3kndp6LSoSlVg-jhU,87
-urllib3-2.2.2.dist-info/licenses/LICENSE.txt,sha256=Ew46ZNX91dCWp1JpRjSn2d8oRGnehuVzIQAmgEHj1oY,1093
-urllib3/__init__.py,sha256=JMo1tg1nIV1AeJ2vENC_Txfl0e5h6Gzl9DGVk1rWRbo,6979
-urllib3/__pycache__/__init__.cpython-312.pyc,,
-urllib3/__pycache__/_base_connection.cpython-312.pyc,,
-urllib3/__pycache__/_collections.cpython-312.pyc,,
-urllib3/__pycache__/_request_methods.cpython-312.pyc,,
-urllib3/__pycache__/_version.cpython-312.pyc,,
-urllib3/__pycache__/connection.cpython-312.pyc,,
-urllib3/__pycache__/connectionpool.cpython-312.pyc,,
-urllib3/__pycache__/exceptions.cpython-312.pyc,,
-urllib3/__pycache__/fields.cpython-312.pyc,,
-urllib3/__pycache__/filepost.cpython-312.pyc,,
-urllib3/__pycache__/http2.cpython-312.pyc,,
-urllib3/__pycache__/poolmanager.cpython-312.pyc,,
-urllib3/__pycache__/response.cpython-312.pyc,,
-urllib3/_base_connection.py,sha256=tH0ZlOxWKika-S9NW-MuIlI_PLFQUUmSnoE_9MeywkM,5652
-urllib3/_collections.py,sha256=aGhh9zCYce3o-5FW9DPSUay6O9LjHx8z6T7wDtdhrkY,17370
-urllib3/_request_methods.py,sha256=ucEpHQyQf06b9o1RxKLkCpzGH0ct-v7X2xGpU6rmmlo,9984
-urllib3/_version.py,sha256=NcS90vVEriRXqG3ygXh7bjsUTZrTaLODQB3cjBtxkAw,98
-urllib3/connection.py,sha256=jSJmWOwEfzghV-P9F5dU4opSt6TFG6g6Y23JAaN2Bxg,34762
-urllib3/connectionpool.py,sha256=5fPIHypPwlbKBASMs6bESTEJVEGlsj9FOY9_GGU2GpM,43393
-urllib3/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-urllib3/contrib/__pycache__/__init__.cpython-312.pyc,,
-urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc,,
-urllib3/contrib/__pycache__/socks.cpython-312.pyc,,
-urllib3/contrib/emscripten/__init__.py,sha256=u6KNgzjlFZbuAAXa_ybCR7gQ71VJESnF-IIdDA73brw,733
-urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc,,
-urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc,,
-urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc,,
-urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc,,
-urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc,,
-urllib3/contrib/emscripten/connection.py,sha256=kaBe2tWt7Yy9vNUFRBV7CSyDnfhCYILGxju9KTZj8Sw,8755
-urllib3/contrib/emscripten/emscripten_fetch_worker.js,sha256=CDfYF_9CDobtx2lGidyJ1zjDEvwNT5F-dchmVWXDh0E,3655
-urllib3/contrib/emscripten/fetch.py,sha256=ymwJlHBBuw6WTpKgPHpdmmrNBxlsr75HqoD4Rn27YXk,14131
-urllib3/contrib/emscripten/request.py,sha256=mL28szy1KvE3NJhWor5jNmarp8gwplDU-7gwGZY5g0Q,566
-urllib3/contrib/emscripten/response.py,sha256=wEYWPHCL-JsgCtpCpfnWGYA1-DcjDGpFGqWCXZLwbHY,10017
-urllib3/contrib/pyopenssl.py,sha256=X31eCYGwB09EkAHX8RhDKC0X0Ki7d0cCVWoMJZUM5bQ,19161
-urllib3/contrib/socks.py,sha256=-iardc61GypsJzD6W6yuRS7KVCyfowcQrl_719H7lIM,7549
-urllib3/exceptions.py,sha256=RDaiudtR7rqbVKTKpLSgZBBtwaIqV7eZtervZV_mZag,9393
-urllib3/fields.py,sha256=8vi0PeRo_pE5chPmJA07LZtMkVls4UrBS1k2xM506jM,10843
-urllib3/filepost.py,sha256=-9qJT11cNGjO9dqnI20-oErZuTvNaM18xZZPCjZSbOE,2395
-urllib3/http2.py,sha256=ZfXCqoeKqMoC2JOn9ajMFwNgdyqJozj-6oBZNAUcqd0,7517
-urllib3/poolmanager.py,sha256=2_L2AjVDgoQ0qBmYbX9u9QqyU1u5J37zQbtv_-ueZQA,22913
-urllib3/py.typed,sha256=UaCuPFa3H8UAakbt-5G8SPacldTOGvJv18pPjUJ5gDY,93
-urllib3/response.py,sha256=NS0rqwRmtwWtC_6XDqgDJN_uo-jEmBVzx0V6KCsHlwg,44801
-urllib3/util/__init__.py,sha256=-qeS0QceivazvBEKDNFCAI-6ACcdDOE4TMvo7SLNlAQ,1001
-urllib3/util/__pycache__/__init__.cpython-312.pyc,,
-urllib3/util/__pycache__/connection.cpython-312.pyc,,
-urllib3/util/__pycache__/proxy.cpython-312.pyc,,
-urllib3/util/__pycache__/request.cpython-312.pyc,,
-urllib3/util/__pycache__/response.cpython-312.pyc,,
-urllib3/util/__pycache__/retry.cpython-312.pyc,,
-urllib3/util/__pycache__/ssl_.cpython-312.pyc,,
-urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc,,
-urllib3/util/__pycache__/ssltransport.cpython-312.pyc,,
-urllib3/util/__pycache__/timeout.cpython-312.pyc,,
-urllib3/util/__pycache__/url.cpython-312.pyc,,
-urllib3/util/__pycache__/util.cpython-312.pyc,,
-urllib3/util/__pycache__/wait.cpython-312.pyc,,
-urllib3/util/connection.py,sha256=QeUUEuNmhznpuKNPL-B0IVOkMdMCu8oJX62OC0Vpzug,4462
-urllib3/util/proxy.py,sha256=seP8-Q5B6bB0dMtwPj-YcZZQ30vHuLqRu-tI0JZ2fzs,1148
-urllib3/util/request.py,sha256=QIZWYzQ6Y4MpJsD_kssVEIrWNu69ioUMuE6fjd4qhPM,8069
-urllib3/util/response.py,sha256=vQE639uoEhj1vpjEdxu5lNIhJCSUZkd7pqllUI0BZOA,3374
-urllib3/util/retry.py,sha256=bj-2YUqblxLlv8THg5fxww-DM54XCbjgZXIQ71XioCY,18459
-urllib3/util/ssl_.py,sha256=DevjBk-8GNMgZjHzgCHHaxmWlXb-dKjcgymNd3ZT-ew,19107
-urllib3/util/ssl_match_hostname.py,sha256=gaWqixoYtQ_GKO8fcRGFj3VXeMoqyxQQuUTPgWeiL_M,5812
-urllib3/util/ssltransport.py,sha256=HHvjU0i-PjPThvNYQ8R1SEsseY0x07tPfVntiXg72n0,8990
-urllib3/util/timeout.py,sha256=4eT1FVeZZU7h7mYD1Jq2OXNe4fxekdNvhoWUkZusRpA,10346
-urllib3/util/url.py,sha256=wHORhp80RAXyTlAIkTqLFzSrkU7J34ZDxX-tN65MBZk,15213
-urllib3/util/util.py,sha256=j3lbZK1jPyiwD34T8IgJzdWEZVT-4E-0vYIJi9UjeNA,1146
-urllib3/util/wait.py,sha256=_ph8IrUR3sqPqi0OopQgJUlH4wzkGeM5CiyA7XGGtmI,4423
diff --git a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/WHEEL b/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/WHEEL
deleted file mode 100644
index 516596c..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/WHEEL
+++ /dev/null
@@ -1,4 +0,0 @@
-Wheel-Version: 1.0
-Generator: hatchling 1.24.2
-Root-Is-Purelib: true
-Tag: py3-none-any
diff --git a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/licenses/LICENSE.txt b/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/licenses/LICENSE.txt
deleted file mode 100644
index e6183d0..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3-2.2.2.dist-info/licenses/LICENSE.txt
+++ /dev/null
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2008-2020 Andrey Petrov and contributors.
-
-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.
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__init__.py b/.venv/lib/python3.12/site-packages/urllib3/__init__.py
deleted file mode 100644
index 3fe782c..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/__init__.py
+++ /dev/null
@@ -1,211 +0,0 @@
-"""
-Python HTTP library with thread-safe connection pooling, file post support, user friendly, and more
-"""
-
-from __future__ import annotations
-
-# Set default logging handler to avoid "No handler found" warnings.
-import logging
-import sys
-import typing
-import warnings
-from logging import NullHandler
-
-from . import exceptions
-from ._base_connection import _TYPE_BODY
-from ._collections import HTTPHeaderDict
-from ._version import __version__
-from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, connection_from_url
-from .filepost import _TYPE_FIELDS, encode_multipart_formdata
-from .poolmanager import PoolManager, ProxyManager, proxy_from_url
-from .response import BaseHTTPResponse, HTTPResponse
-from .util.request import make_headers
-from .util.retry import Retry
-from .util.timeout import Timeout
-
-# Ensure that Python is compiled with OpenSSL 1.1.1+
-# If the 'ssl' module isn't available at all that's
-# fine, we only care if the module is available.
-try:
- import ssl
-except ImportError:
- pass
-else:
- if not ssl.OPENSSL_VERSION.startswith("OpenSSL "): # Defensive:
- warnings.warn(
- "urllib3 v2 only supports OpenSSL 1.1.1+, currently "
- f"the 'ssl' module is compiled with {ssl.OPENSSL_VERSION!r}. "
- "See: https://github.com/urllib3/urllib3/issues/3020",
- exceptions.NotOpenSSLWarning,
- )
- elif ssl.OPENSSL_VERSION_INFO < (1, 1, 1): # Defensive:
- raise ImportError(
- "urllib3 v2 only supports OpenSSL 1.1.1+, currently "
- f"the 'ssl' module is compiled with {ssl.OPENSSL_VERSION!r}. "
- "See: https://github.com/urllib3/urllib3/issues/2168"
- )
-
-__author__ = "Andrey Petrov (andrey.petrov@shazow.net)"
-__license__ = "MIT"
-__version__ = __version__
-
-__all__ = (
- "HTTPConnectionPool",
- "HTTPHeaderDict",
- "HTTPSConnectionPool",
- "PoolManager",
- "ProxyManager",
- "HTTPResponse",
- "Retry",
- "Timeout",
- "add_stderr_logger",
- "connection_from_url",
- "disable_warnings",
- "encode_multipart_formdata",
- "make_headers",
- "proxy_from_url",
- "request",
- "BaseHTTPResponse",
-)
-
-logging.getLogger(__name__).addHandler(NullHandler())
-
-
-def add_stderr_logger(
- level: int = logging.DEBUG,
-) -> logging.StreamHandler[typing.TextIO]:
- """
- Helper for quickly adding a StreamHandler to the logger. Useful for
- debugging.
-
- Returns the handler after adding it.
- """
- # This method needs to be in this __init__.py to get the __name__ correct
- # even if urllib3 is vendored within another package.
- logger = logging.getLogger(__name__)
- handler = logging.StreamHandler()
- handler.setFormatter(logging.Formatter("%(asctime)s %(levelname)s %(message)s"))
- logger.addHandler(handler)
- logger.setLevel(level)
- logger.debug("Added a stderr logging handler to logger: %s", __name__)
- return handler
-
-
-# ... Clean up.
-del NullHandler
-
-
-# All warning filters *must* be appended unless you're really certain that they
-# shouldn't be: otherwise, it's very hard for users to use most Python
-# mechanisms to silence them.
-# SecurityWarning's always go off by default.
-warnings.simplefilter("always", exceptions.SecurityWarning, append=True)
-# InsecurePlatformWarning's don't vary between requests, so we keep it default.
-warnings.simplefilter("default", exceptions.InsecurePlatformWarning, append=True)
-
-
-def disable_warnings(category: type[Warning] = exceptions.HTTPWarning) -> None:
- """
- Helper for quickly disabling all urllib3 warnings.
- """
- warnings.simplefilter("ignore", category)
-
-
-_DEFAULT_POOL = PoolManager()
-
-
-def request(
- method: str,
- url: str,
- *,
- body: _TYPE_BODY | None = None,
- fields: _TYPE_FIELDS | None = None,
- headers: typing.Mapping[str, str] | None = None,
- preload_content: bool | None = True,
- decode_content: bool | None = True,
- redirect: bool | None = True,
- retries: Retry | bool | int | None = None,
- timeout: Timeout | float | int | None = 3,
- json: typing.Any | None = None,
-) -> BaseHTTPResponse:
- """
- A convenience, top-level request method. It uses a module-global ``PoolManager`` instance.
- Therefore, its side effects could be shared across dependencies relying on it.
- To avoid side effects create a new ``PoolManager`` instance and use it instead.
- The method does not accept low-level ``**urlopen_kw`` keyword arguments.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param body:
- Data to send in the request body, either :class:`str`, :class:`bytes`,
- an iterable of :class:`str`/:class:`bytes`, or a file-like object.
-
- :param fields:
- Data to encode and send in the request body.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc.
-
- :param bool preload_content:
- If True, the response's body will be preloaded into memory.
-
- :param bool decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param redirect:
- If True, automatically handle redirects (status codes 301, 302,
- 303, 307, 308). Each redirect counts as a retry. Disabling retries
- will disable redirect, too.
-
- :param retries:
- Configure the number of retries to allow before raising a
- :class:`~urllib3.exceptions.MaxRetryError` exception.
-
- If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a
- :class:`~urllib3.util.retry.Retry` object for fine-grained control
- over different types of retries.
- Pass an integer number to retry connection errors that many times,
- but no other types of errors. Pass zero to never retry.
-
- If ``False``, then retries are disabled and any exception is raised
- immediately. Also, instead of raising a MaxRetryError on redirects,
- the redirect response will be returned.
-
- :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
-
- :param timeout:
- If specified, overrides the default timeout for this one
- request. It may be a float (in seconds) or an instance of
- :class:`urllib3.util.Timeout`.
-
- :param json:
- Data to encode and send as JSON with UTF-encoded in the request body.
- The ``"Content-Type"`` header will be set to ``"application/json"``
- unless specified otherwise.
- """
-
- return _DEFAULT_POOL.request(
- method,
- url,
- body=body,
- fields=fields,
- headers=headers,
- preload_content=preload_content,
- decode_content=decode_content,
- redirect=redirect,
- retries=retries,
- timeout=timeout,
- json=json,
- )
-
-
-if sys.platform == "emscripten":
- from .contrib.emscripten import inject_into_urllib3 # noqa: 401
-
- inject_into_urllib3()
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 12a1fb8..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc
deleted file mode 100644
index 348e82c..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_base_connection.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc
deleted file mode 100644
index 0bd2cd5..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_collections.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc
deleted file mode 100644
index 96609d2..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_request_methods.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_version.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_version.cpython-312.pyc
deleted file mode 100644
index e6a33a4..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/_version.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connection.cpython-312.pyc
deleted file mode 100644
index a3a6976..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connection.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc
deleted file mode 100644
index a943d5e..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/connectionpool.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc
deleted file mode 100644
index 12bf9a1..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/exceptions.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/fields.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/fields.cpython-312.pyc
deleted file mode 100644
index 4b2f3af..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/fields.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc
deleted file mode 100644
index ff85f1f..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/filepost.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/http2.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/http2.cpython-312.pyc
deleted file mode 100644
index 4b26a70..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/http2.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc
deleted file mode 100644
index 16051e4..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/poolmanager.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/response.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/__pycache__/response.cpython-312.pyc
deleted file mode 100644
index 15c72ea..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/__pycache__/response.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/_base_connection.py b/.venv/lib/python3.12/site-packages/urllib3/_base_connection.py
deleted file mode 100644
index 29ca334..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/_base_connection.py
+++ /dev/null
@@ -1,172 +0,0 @@
-from __future__ import annotations
-
-import typing
-
-from .util.connection import _TYPE_SOCKET_OPTIONS
-from .util.timeout import _DEFAULT_TIMEOUT, _TYPE_TIMEOUT
-from .util.url import Url
-
-_TYPE_BODY = typing.Union[bytes, typing.IO[typing.Any], typing.Iterable[bytes], str]
-
-
-class ProxyConfig(typing.NamedTuple):
- ssl_context: ssl.SSLContext | None
- use_forwarding_for_https: bool
- assert_hostname: None | str | typing.Literal[False]
- assert_fingerprint: str | None
-
-
-class _ResponseOptions(typing.NamedTuple):
- # TODO: Remove this in favor of a better
- # HTTP request/response lifecycle tracking.
- request_method: str
- request_url: str
- preload_content: bool
- decode_content: bool
- enforce_content_length: bool
-
-
-if typing.TYPE_CHECKING:
- import ssl
- from typing import Protocol
-
- from .response import BaseHTTPResponse
-
- class BaseHTTPConnection(Protocol):
- default_port: typing.ClassVar[int]
- default_socket_options: typing.ClassVar[_TYPE_SOCKET_OPTIONS]
-
- host: str
- port: int
- timeout: None | (
- float
- ) # Instance doesn't store _DEFAULT_TIMEOUT, must be resolved.
- blocksize: int
- source_address: tuple[str, int] | None
- socket_options: _TYPE_SOCKET_OPTIONS | None
-
- proxy: Url | None
- proxy_config: ProxyConfig | None
-
- is_verified: bool
- proxy_is_verified: bool | None
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 8192,
- socket_options: _TYPE_SOCKET_OPTIONS | None = ...,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- ) -> None:
- ...
-
- def set_tunnel(
- self,
- host: str,
- port: int | None = None,
- headers: typing.Mapping[str, str] | None = None,
- scheme: str = "http",
- ) -> None:
- ...
-
- def connect(self) -> None:
- ...
-
- def request(
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- # We know *at least* botocore is depending on the order of the
- # first 3 parameters so to be safe we only mark the later ones
- # as keyword-only to ensure we have space to extend.
- *,
- chunked: bool = False,
- preload_content: bool = True,
- decode_content: bool = True,
- enforce_content_length: bool = True,
- ) -> None:
- ...
-
- def getresponse(self) -> BaseHTTPResponse:
- ...
-
- def close(self) -> None:
- ...
-
- @property
- def is_closed(self) -> bool:
- """Whether the connection either is brand new or has been previously closed.
- If this property is True then both ``is_connected`` and ``has_connected_to_proxy``
- properties must be False.
- """
-
- @property
- def is_connected(self) -> bool:
- """Whether the connection is actively connected to any origin (proxy or target)"""
-
- @property
- def has_connected_to_proxy(self) -> bool:
- """Whether the connection has successfully connected to its proxy.
- This returns False if no proxy is in use. Used to determine whether
- errors are coming from the proxy layer or from tunnelling to the target origin.
- """
-
- class BaseHTTPSConnection(BaseHTTPConnection, Protocol):
- default_port: typing.ClassVar[int]
- default_socket_options: typing.ClassVar[_TYPE_SOCKET_OPTIONS]
-
- # Certificate verification methods
- cert_reqs: int | str | None
- assert_hostname: None | str | typing.Literal[False]
- assert_fingerprint: str | None
- ssl_context: ssl.SSLContext | None
-
- # Trusted CAs
- ca_certs: str | None
- ca_cert_dir: str | None
- ca_cert_data: None | str | bytes
-
- # TLS version
- ssl_minimum_version: int | None
- ssl_maximum_version: int | None
- ssl_version: int | str | None # Deprecated
-
- # Client certificates
- cert_file: str | None
- key_file: str | None
- key_password: str | None
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 16384,
- socket_options: _TYPE_SOCKET_OPTIONS | None = ...,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- cert_reqs: int | str | None = None,
- assert_hostname: None | str | typing.Literal[False] = None,
- assert_fingerprint: str | None = None,
- server_hostname: str | None = None,
- ssl_context: ssl.SSLContext | None = None,
- ca_certs: str | None = None,
- ca_cert_dir: str | None = None,
- ca_cert_data: None | str | bytes = None,
- ssl_minimum_version: int | None = None,
- ssl_maximum_version: int | None = None,
- ssl_version: int | str | None = None, # Deprecated
- cert_file: str | None = None,
- key_file: str | None = None,
- key_password: str | None = None,
- ) -> None:
- ...
diff --git a/.venv/lib/python3.12/site-packages/urllib3/_collections.py b/.venv/lib/python3.12/site-packages/urllib3/_collections.py
deleted file mode 100644
index 8a4409a..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/_collections.py
+++ /dev/null
@@ -1,483 +0,0 @@
-from __future__ import annotations
-
-import typing
-from collections import OrderedDict
-from enum import Enum, auto
-from threading import RLock
-
-if typing.TYPE_CHECKING:
- # We can only import Protocol if TYPE_CHECKING because it's a development
- # dependency, and is not available at runtime.
- from typing import Protocol
-
- from typing_extensions import Self
-
- class HasGettableStringKeys(Protocol):
- def keys(self) -> typing.Iterator[str]:
- ...
-
- def __getitem__(self, key: str) -> str:
- ...
-
-
-__all__ = ["RecentlyUsedContainer", "HTTPHeaderDict"]
-
-
-# Key type
-_KT = typing.TypeVar("_KT")
-# Value type
-_VT = typing.TypeVar("_VT")
-# Default type
-_DT = typing.TypeVar("_DT")
-
-ValidHTTPHeaderSource = typing.Union[
- "HTTPHeaderDict",
- typing.Mapping[str, str],
- typing.Iterable[typing.Tuple[str, str]],
- "HasGettableStringKeys",
-]
-
-
-class _Sentinel(Enum):
- not_passed = auto()
-
-
-def ensure_can_construct_http_header_dict(
- potential: object,
-) -> ValidHTTPHeaderSource | None:
- if isinstance(potential, HTTPHeaderDict):
- return potential
- elif isinstance(potential, typing.Mapping):
- # Full runtime checking of the contents of a Mapping is expensive, so for the
- # purposes of typechecking, we assume that any Mapping is the right shape.
- return typing.cast(typing.Mapping[str, str], potential)
- elif isinstance(potential, typing.Iterable):
- # Similarly to Mapping, full runtime checking of the contents of an Iterable is
- # expensive, so for the purposes of typechecking, we assume that any Iterable
- # is the right shape.
- return typing.cast(typing.Iterable[typing.Tuple[str, str]], potential)
- elif hasattr(potential, "keys") and hasattr(potential, "__getitem__"):
- return typing.cast("HasGettableStringKeys", potential)
- else:
- return None
-
-
-class RecentlyUsedContainer(typing.Generic[_KT, _VT], typing.MutableMapping[_KT, _VT]):
- """
- Provides a thread-safe dict-like container which maintains up to
- ``maxsize`` keys while throwing away the least-recently-used keys beyond
- ``maxsize``.
-
- :param maxsize:
- Maximum number of recent elements to retain.
-
- :param dispose_func:
- Every time an item is evicted from the container,
- ``dispose_func(value)`` is called. Callback which will get called
- """
-
- _container: typing.OrderedDict[_KT, _VT]
- _maxsize: int
- dispose_func: typing.Callable[[_VT], None] | None
- lock: RLock
-
- def __init__(
- self,
- maxsize: int = 10,
- dispose_func: typing.Callable[[_VT], None] | None = None,
- ) -> None:
- super().__init__()
- self._maxsize = maxsize
- self.dispose_func = dispose_func
- self._container = OrderedDict()
- self.lock = RLock()
-
- def __getitem__(self, key: _KT) -> _VT:
- # Re-insert the item, moving it to the end of the eviction line.
- with self.lock:
- item = self._container.pop(key)
- self._container[key] = item
- return item
-
- def __setitem__(self, key: _KT, value: _VT) -> None:
- evicted_item = None
- with self.lock:
- # Possibly evict the existing value of 'key'
- try:
- # If the key exists, we'll overwrite it, which won't change the
- # size of the pool. Because accessing a key should move it to
- # the end of the eviction line, we pop it out first.
- evicted_item = key, self._container.pop(key)
- self._container[key] = value
- except KeyError:
- # When the key does not exist, we insert the value first so that
- # evicting works in all cases, including when self._maxsize is 0
- self._container[key] = value
- if len(self._container) > self._maxsize:
- # If we didn't evict an existing value, and we've hit our maximum
- # size, then we have to evict the least recently used item from
- # the beginning of the container.
- evicted_item = self._container.popitem(last=False)
-
- # After releasing the lock on the pool, dispose of any evicted value.
- if evicted_item is not None and self.dispose_func:
- _, evicted_value = evicted_item
- self.dispose_func(evicted_value)
-
- def __delitem__(self, key: _KT) -> None:
- with self.lock:
- value = self._container.pop(key)
-
- if self.dispose_func:
- self.dispose_func(value)
-
- def __len__(self) -> int:
- with self.lock:
- return len(self._container)
-
- def __iter__(self) -> typing.NoReturn:
- raise NotImplementedError(
- "Iteration over this class is unlikely to be threadsafe."
- )
-
- def clear(self) -> None:
- with self.lock:
- # Copy pointers to all values, then wipe the mapping
- values = list(self._container.values())
- self._container.clear()
-
- if self.dispose_func:
- for value in values:
- self.dispose_func(value)
-
- def keys(self) -> set[_KT]: # type: ignore[override]
- with self.lock:
- return set(self._container.keys())
-
-
-class HTTPHeaderDictItemView(typing.Set[typing.Tuple[str, str]]):
- """
- HTTPHeaderDict is unusual for a Mapping[str, str] in that it has two modes of
- address.
-
- If we directly try to get an item with a particular name, we will get a string
- back that is the concatenated version of all the values:
-
- >>> d['X-Header-Name']
- 'Value1, Value2, Value3'
-
- However, if we iterate over an HTTPHeaderDict's items, we will optionally combine
- these values based on whether combine=True was called when building up the dictionary
-
- >>> d = HTTPHeaderDict({"A": "1", "B": "foo"})
- >>> d.add("A", "2", combine=True)
- >>> d.add("B", "bar")
- >>> list(d.items())
- [
- ('A', '1, 2'),
- ('B', 'foo'),
- ('B', 'bar'),
- ]
-
- This class conforms to the interface required by the MutableMapping ABC while
- also giving us the nonstandard iteration behavior we want; items with duplicate
- keys, ordered by time of first insertion.
- """
-
- _headers: HTTPHeaderDict
-
- def __init__(self, headers: HTTPHeaderDict) -> None:
- self._headers = headers
-
- def __len__(self) -> int:
- return len(list(self._headers.iteritems()))
-
- def __iter__(self) -> typing.Iterator[tuple[str, str]]:
- return self._headers.iteritems()
-
- def __contains__(self, item: object) -> bool:
- if isinstance(item, tuple) and len(item) == 2:
- passed_key, passed_val = item
- if isinstance(passed_key, str) and isinstance(passed_val, str):
- return self._headers._has_value_for_header(passed_key, passed_val)
- return False
-
-
-class HTTPHeaderDict(typing.MutableMapping[str, str]):
- """
- :param headers:
- An iterable of field-value pairs. Must not contain multiple field names
- when compared case-insensitively.
-
- :param kwargs:
- Additional field-value pairs to pass in to ``dict.update``.
-
- A ``dict`` like container for storing HTTP Headers.
-
- Field names are stored and compared case-insensitively in compliance with
- RFC 7230. Iteration provides the first case-sensitive key seen for each
- case-insensitive pair.
-
- Using ``__setitem__`` syntax overwrites fields that compare equal
- case-insensitively in order to maintain ``dict``'s api. For fields that
- compare equal, instead create a new ``HTTPHeaderDict`` and use ``.add``
- in a loop.
-
- If multiple fields that are equal case-insensitively are passed to the
- constructor or ``.update``, the behavior is undefined and some will be
- lost.
-
- >>> headers = HTTPHeaderDict()
- >>> headers.add('Set-Cookie', 'foo=bar')
- >>> headers.add('set-cookie', 'baz=quxx')
- >>> headers['content-length'] = '7'
- >>> headers['SET-cookie']
- 'foo=bar, baz=quxx'
- >>> headers['Content-Length']
- '7'
- """
-
- _container: typing.MutableMapping[str, list[str]]
-
- def __init__(self, headers: ValidHTTPHeaderSource | None = None, **kwargs: str):
- super().__init__()
- self._container = {} # 'dict' is insert-ordered
- if headers is not None:
- if isinstance(headers, HTTPHeaderDict):
- self._copy_from(headers)
- else:
- self.extend(headers)
- if kwargs:
- self.extend(kwargs)
-
- def __setitem__(self, key: str, val: str) -> None:
- # avoid a bytes/str comparison by decoding before httplib
- if isinstance(key, bytes):
- key = key.decode("latin-1")
- self._container[key.lower()] = [key, val]
-
- def __getitem__(self, key: str) -> str:
- val = self._container[key.lower()]
- return ", ".join(val[1:])
-
- def __delitem__(self, key: str) -> None:
- del self._container[key.lower()]
-
- def __contains__(self, key: object) -> bool:
- if isinstance(key, str):
- return key.lower() in self._container
- return False
-
- def setdefault(self, key: str, default: str = "") -> str:
- return super().setdefault(key, default)
-
- def __eq__(self, other: object) -> bool:
- maybe_constructable = ensure_can_construct_http_header_dict(other)
- if maybe_constructable is None:
- return False
- else:
- other_as_http_header_dict = type(self)(maybe_constructable)
-
- return {k.lower(): v for k, v in self.itermerged()} == {
- k.lower(): v for k, v in other_as_http_header_dict.itermerged()
- }
-
- def __ne__(self, other: object) -> bool:
- return not self.__eq__(other)
-
- def __len__(self) -> int:
- return len(self._container)
-
- def __iter__(self) -> typing.Iterator[str]:
- # Only provide the originally cased names
- for vals in self._container.values():
- yield vals[0]
-
- def discard(self, key: str) -> None:
- try:
- del self[key]
- except KeyError:
- pass
-
- def add(self, key: str, val: str, *, combine: bool = False) -> None:
- """Adds a (name, value) pair, doesn't overwrite the value if it already
- exists.
-
- If this is called with combine=True, instead of adding a new header value
- as a distinct item during iteration, this will instead append the value to
- any existing header value with a comma. If no existing header value exists
- for the key, then the value will simply be added, ignoring the combine parameter.
-
- >>> headers = HTTPHeaderDict(foo='bar')
- >>> headers.add('Foo', 'baz')
- >>> headers['foo']
- 'bar, baz'
- >>> list(headers.items())
- [('foo', 'bar'), ('foo', 'baz')]
- >>> headers.add('foo', 'quz', combine=True)
- >>> list(headers.items())
- [('foo', 'bar, baz, quz')]
- """
- # avoid a bytes/str comparison by decoding before httplib
- if isinstance(key, bytes):
- key = key.decode("latin-1")
- key_lower = key.lower()
- new_vals = [key, val]
- # Keep the common case aka no item present as fast as possible
- vals = self._container.setdefault(key_lower, new_vals)
- if new_vals is not vals:
- # if there are values here, then there is at least the initial
- # key/value pair
- assert len(vals) >= 2
- if combine:
- vals[-1] = vals[-1] + ", " + val
- else:
- vals.append(val)
-
- def extend(self, *args: ValidHTTPHeaderSource, **kwargs: str) -> None:
- """Generic import function for any type of header-like object.
- Adapted version of MutableMapping.update in order to insert items
- with self.add instead of self.__setitem__
- """
- if len(args) > 1:
- raise TypeError(
- f"extend() takes at most 1 positional arguments ({len(args)} given)"
- )
- other = args[0] if len(args) >= 1 else ()
-
- if isinstance(other, HTTPHeaderDict):
- for key, val in other.iteritems():
- self.add(key, val)
- elif isinstance(other, typing.Mapping):
- for key, val in other.items():
- self.add(key, val)
- elif isinstance(other, typing.Iterable):
- other = typing.cast(typing.Iterable[typing.Tuple[str, str]], other)
- for key, value in other:
- self.add(key, value)
- elif hasattr(other, "keys") and hasattr(other, "__getitem__"):
- # THIS IS NOT A TYPESAFE BRANCH
- # In this branch, the object has a `keys` attr but is not a Mapping or any of
- # the other types indicated in the method signature. We do some stuff with
- # it as though it partially implements the Mapping interface, but we're not
- # doing that stuff safely AT ALL.
- for key in other.keys():
- self.add(key, other[key])
-
- for key, value in kwargs.items():
- self.add(key, value)
-
- @typing.overload
- def getlist(self, key: str) -> list[str]:
- ...
-
- @typing.overload
- def getlist(self, key: str, default: _DT) -> list[str] | _DT:
- ...
-
- def getlist(
- self, key: str, default: _Sentinel | _DT = _Sentinel.not_passed
- ) -> list[str] | _DT:
- """Returns a list of all the values for the named field. Returns an
- empty list if the key doesn't exist."""
- try:
- vals = self._container[key.lower()]
- except KeyError:
- if default is _Sentinel.not_passed:
- # _DT is unbound; empty list is instance of List[str]
- return []
- # _DT is bound; default is instance of _DT
- return default
- else:
- # _DT may or may not be bound; vals[1:] is instance of List[str], which
- # meets our external interface requirement of `Union[List[str], _DT]`.
- return vals[1:]
-
- def _prepare_for_method_change(self) -> Self:
- """
- Remove content-specific header fields before changing the request
- method to GET or HEAD according to RFC 9110, Section 15.4.
- """
- content_specific_headers = [
- "Content-Encoding",
- "Content-Language",
- "Content-Location",
- "Content-Type",
- "Content-Length",
- "Digest",
- "Last-Modified",
- ]
- for header in content_specific_headers:
- self.discard(header)
- return self
-
- # Backwards compatibility for httplib
- getheaders = getlist
- getallmatchingheaders = getlist
- iget = getlist
-
- # Backwards compatibility for http.cookiejar
- get_all = getlist
-
- def __repr__(self) -> str:
- return f"{type(self).__name__}({dict(self.itermerged())})"
-
- def _copy_from(self, other: HTTPHeaderDict) -> None:
- for key in other:
- val = other.getlist(key)
- self._container[key.lower()] = [key, *val]
-
- def copy(self) -> Self:
- clone = type(self)()
- clone._copy_from(self)
- return clone
-
- def iteritems(self) -> typing.Iterator[tuple[str, str]]:
- """Iterate over all header lines, including duplicate ones."""
- for key in self:
- vals = self._container[key.lower()]
- for val in vals[1:]:
- yield vals[0], val
-
- def itermerged(self) -> typing.Iterator[tuple[str, str]]:
- """Iterate over all headers, merging duplicate ones together."""
- for key in self:
- val = self._container[key.lower()]
- yield val[0], ", ".join(val[1:])
-
- def items(self) -> HTTPHeaderDictItemView: # type: ignore[override]
- return HTTPHeaderDictItemView(self)
-
- def _has_value_for_header(self, header_name: str, potential_value: str) -> bool:
- if header_name in self:
- return potential_value in self._container[header_name.lower()][1:]
- return False
-
- def __ior__(self, other: object) -> HTTPHeaderDict:
- # Supports extending a header dict in-place using operator |=
- # combining items with add instead of __setitem__
- maybe_constructable = ensure_can_construct_http_header_dict(other)
- if maybe_constructable is None:
- return NotImplemented
- self.extend(maybe_constructable)
- return self
-
- def __or__(self, other: object) -> Self:
- # Supports merging header dicts using operator |
- # combining items with add instead of __setitem__
- maybe_constructable = ensure_can_construct_http_header_dict(other)
- if maybe_constructable is None:
- return NotImplemented
- result = self.copy()
- result.extend(maybe_constructable)
- return result
-
- def __ror__(self, other: object) -> Self:
- # Supports merging header dicts using operator | when other is on left side
- # combining items with add instead of __setitem__
- maybe_constructable = ensure_can_construct_http_header_dict(other)
- if maybe_constructable is None:
- return NotImplemented
- result = type(self)(maybe_constructable)
- result.extend(self)
- return result
diff --git a/.venv/lib/python3.12/site-packages/urllib3/_request_methods.py b/.venv/lib/python3.12/site-packages/urllib3/_request_methods.py
deleted file mode 100644
index 632042f..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/_request_methods.py
+++ /dev/null
@@ -1,279 +0,0 @@
-from __future__ import annotations
-
-import json as _json
-import typing
-from urllib.parse import urlencode
-
-from ._base_connection import _TYPE_BODY
-from ._collections import HTTPHeaderDict
-from .filepost import _TYPE_FIELDS, encode_multipart_formdata
-from .response import BaseHTTPResponse
-
-__all__ = ["RequestMethods"]
-
-_TYPE_ENCODE_URL_FIELDS = typing.Union[
- typing.Sequence[typing.Tuple[str, typing.Union[str, bytes]]],
- typing.Mapping[str, typing.Union[str, bytes]],
-]
-
-
-class RequestMethods:
- """
- Convenience mixin for classes who implement a :meth:`urlopen` method, such
- as :class:`urllib3.HTTPConnectionPool` and
- :class:`urllib3.PoolManager`.
-
- Provides behavior for making common types of HTTP request methods and
- decides which type of request field encoding to use.
-
- Specifically,
-
- :meth:`.request_encode_url` is for sending requests whose fields are
- encoded in the URL (such as GET, HEAD, DELETE).
-
- :meth:`.request_encode_body` is for sending requests whose fields are
- encoded in the *body* of the request using multipart or www-form-urlencoded
- (such as for POST, PUT, PATCH).
-
- :meth:`.request` is for making any kind of request, it will look up the
- appropriate encoding format and use one of the above two methods to make
- the request.
-
- Initializer parameters:
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
- """
-
- _encode_url_methods = {"DELETE", "GET", "HEAD", "OPTIONS"}
-
- def __init__(self, headers: typing.Mapping[str, str] | None = None) -> None:
- self.headers = headers or {}
-
- def urlopen(
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- encode_multipart: bool = True,
- multipart_boundary: str | None = None,
- **kw: typing.Any,
- ) -> BaseHTTPResponse: # Abstract
- raise NotImplementedError(
- "Classes extending RequestMethods must implement "
- "their own ``urlopen`` method."
- )
-
- def request(
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- fields: _TYPE_FIELDS | None = None,
- headers: typing.Mapping[str, str] | None = None,
- json: typing.Any | None = None,
- **urlopen_kw: typing.Any,
- ) -> BaseHTTPResponse:
- """
- Make a request using :meth:`urlopen` with the appropriate encoding of
- ``fields`` based on the ``method`` used.
-
- This is a convenience method that requires the least amount of manual
- effort. It can be used in most situations, while still having the
- option to drop down to more specific methods when necessary, such as
- :meth:`request_encode_url`, :meth:`request_encode_body`,
- or even the lowest level :meth:`urlopen`.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param body:
- Data to send in the request body, either :class:`str`, :class:`bytes`,
- an iterable of :class:`str`/:class:`bytes`, or a file-like object.
-
- :param fields:
- Data to encode and send in the request body. Values are processed
- by :func:`urllib.parse.urlencode`.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
-
- :param json:
- Data to encode and send as JSON with UTF-encoded in the request body.
- The ``"Content-Type"`` header will be set to ``"application/json"``
- unless specified otherwise.
- """
- method = method.upper()
-
- if json is not None and body is not None:
- raise TypeError(
- "request got values for both 'body' and 'json' parameters which are mutually exclusive"
- )
-
- if json is not None:
- if headers is None:
- headers = self.headers
-
- if not ("content-type" in map(str.lower, headers.keys())):
- headers = HTTPHeaderDict(headers)
- headers["Content-Type"] = "application/json"
-
- body = _json.dumps(json, separators=(",", ":"), ensure_ascii=False).encode(
- "utf-8"
- )
-
- if body is not None:
- urlopen_kw["body"] = body
-
- if method in self._encode_url_methods:
- return self.request_encode_url(
- method,
- url,
- fields=fields, # type: ignore[arg-type]
- headers=headers,
- **urlopen_kw,
- )
- else:
- return self.request_encode_body(
- method, url, fields=fields, headers=headers, **urlopen_kw
- )
-
- def request_encode_url(
- self,
- method: str,
- url: str,
- fields: _TYPE_ENCODE_URL_FIELDS | None = None,
- headers: typing.Mapping[str, str] | None = None,
- **urlopen_kw: str,
- ) -> BaseHTTPResponse:
- """
- Make a request using :meth:`urlopen` with the ``fields`` encoded in
- the url. This is useful for request methods like GET, HEAD, DELETE, etc.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param fields:
- Data to encode and send in the request body.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
- """
- if headers is None:
- headers = self.headers
-
- extra_kw: dict[str, typing.Any] = {"headers": headers}
- extra_kw.update(urlopen_kw)
-
- if fields:
- url += "?" + urlencode(fields)
-
- return self.urlopen(method, url, **extra_kw)
-
- def request_encode_body(
- self,
- method: str,
- url: str,
- fields: _TYPE_FIELDS | None = None,
- headers: typing.Mapping[str, str] | None = None,
- encode_multipart: bool = True,
- multipart_boundary: str | None = None,
- **urlopen_kw: str,
- ) -> BaseHTTPResponse:
- """
- Make a request using :meth:`urlopen` with the ``fields`` encoded in
- the body. This is useful for request methods like POST, PUT, PATCH, etc.
-
- When ``encode_multipart=True`` (default), then
- :func:`urllib3.encode_multipart_formdata` is used to encode
- the payload with the appropriate content type. Otherwise
- :func:`urllib.parse.urlencode` is used with the
- 'application/x-www-form-urlencoded' content type.
-
- Multipart encoding must be used when posting files, and it's reasonably
- safe to use it in other times too. However, it may break request
- signing, such as with OAuth.
-
- Supports an optional ``fields`` parameter of key/value strings AND
- key/filetuple. A filetuple is a (filename, data, MIME type) tuple where
- the MIME type is optional. For example::
-
- fields = {
- 'foo': 'bar',
- 'fakefile': ('foofile.txt', 'contents of foofile'),
- 'realfile': ('barfile.txt', open('realfile').read()),
- 'typedfile': ('bazfile.bin', open('bazfile').read(),
- 'image/jpeg'),
- 'nonamefile': 'contents of nonamefile field',
- }
-
- When uploading a file, providing a filename (the first parameter of the
- tuple) is optional but recommended to best mimic behavior of browsers.
-
- Note that if ``headers`` are supplied, the 'Content-Type' header will
- be overwritten because it depends on the dynamic random boundary string
- which is used to compose the body of the request. The random boundary
- string can be explicitly set with the ``multipart_boundary`` parameter.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param fields:
- Data to encode and send in the request body.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
-
- :param encode_multipart:
- If True, encode the ``fields`` using the multipart/form-data MIME
- format.
-
- :param multipart_boundary:
- If not specified, then a random boundary will be generated using
- :func:`urllib3.filepost.choose_boundary`.
- """
- if headers is None:
- headers = self.headers
-
- extra_kw: dict[str, typing.Any] = {"headers": HTTPHeaderDict(headers)}
- body: bytes | str
-
- if fields:
- if "body" in urlopen_kw:
- raise TypeError(
- "request got values for both 'fields' and 'body', can only specify one."
- )
-
- if encode_multipart:
- body, content_type = encode_multipart_formdata(
- fields, boundary=multipart_boundary
- )
- else:
- body, content_type = (
- urlencode(fields), # type: ignore[arg-type]
- "application/x-www-form-urlencoded",
- )
-
- extra_kw["body"] = body
- extra_kw["headers"].setdefault("Content-Type", content_type)
-
- extra_kw.update(urlopen_kw)
-
- return self.urlopen(method, url, **extra_kw)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/_version.py b/.venv/lib/python3.12/site-packages/urllib3/_version.py
deleted file mode 100644
index 7442f2b..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/_version.py
+++ /dev/null
@@ -1,4 +0,0 @@
-# This file is protected via CODEOWNERS
-from __future__ import annotations
-
-__version__ = "2.2.2"
diff --git a/.venv/lib/python3.12/site-packages/urllib3/connection.py b/.venv/lib/python3.12/site-packages/urllib3/connection.py
deleted file mode 100644
index 1b16279..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/connection.py
+++ /dev/null
@@ -1,929 +0,0 @@
-from __future__ import annotations
-
-import datetime
-import logging
-import os
-import re
-import socket
-import sys
-import typing
-import warnings
-from http.client import HTTPConnection as _HTTPConnection
-from http.client import HTTPException as HTTPException # noqa: F401
-from http.client import ResponseNotReady
-from socket import timeout as SocketTimeout
-
-if typing.TYPE_CHECKING:
- from .response import HTTPResponse
- from .util.ssl_ import _TYPE_PEER_CERT_RET_DICT
- from .util.ssltransport import SSLTransport
-
-from ._collections import HTTPHeaderDict
-from .util.response import assert_header_parsing
-from .util.timeout import _DEFAULT_TIMEOUT, _TYPE_TIMEOUT, Timeout
-from .util.util import to_str
-from .util.wait import wait_for_read
-
-try: # Compiled with SSL?
- import ssl
-
- BaseSSLError = ssl.SSLError
-except (ImportError, AttributeError):
- ssl = None # type: ignore[assignment]
-
- class BaseSSLError(BaseException): # type: ignore[no-redef]
- pass
-
-
-from ._base_connection import _TYPE_BODY
-from ._base_connection import ProxyConfig as ProxyConfig
-from ._base_connection import _ResponseOptions as _ResponseOptions
-from ._version import __version__
-from .exceptions import (
- ConnectTimeoutError,
- HeaderParsingError,
- NameResolutionError,
- NewConnectionError,
- ProxyError,
- SystemTimeWarning,
-)
-from .util import SKIP_HEADER, SKIPPABLE_HEADERS, connection, ssl_
-from .util.request import body_to_chunks
-from .util.ssl_ import assert_fingerprint as _assert_fingerprint
-from .util.ssl_ import (
- create_urllib3_context,
- is_ipaddress,
- resolve_cert_reqs,
- resolve_ssl_version,
- ssl_wrap_socket,
-)
-from .util.ssl_match_hostname import CertificateError, match_hostname
-from .util.url import Url
-
-# Not a no-op, we're adding this to the namespace so it can be imported.
-ConnectionError = ConnectionError
-BrokenPipeError = BrokenPipeError
-
-
-log = logging.getLogger(__name__)
-
-port_by_scheme = {"http": 80, "https": 443}
-
-# When it comes time to update this value as a part of regular maintenance
-# (ie test_recent_date is failing) update it to ~6 months before the current date.
-RECENT_DATE = datetime.date(2023, 6, 1)
-
-_CONTAINS_CONTROL_CHAR_RE = re.compile(r"[^-!#$%&'*+.^_`|~0-9a-zA-Z]")
-
-_HAS_SYS_AUDIT = hasattr(sys, "audit")
-
-
-class HTTPConnection(_HTTPConnection):
- """
- Based on :class:`http.client.HTTPConnection` but provides an extra constructor
- backwards-compatibility layer between older and newer Pythons.
-
- Additional keyword parameters are used to configure attributes of the connection.
- Accepted parameters include:
-
- - ``source_address``: Set the source address for the current connection.
- - ``socket_options``: Set specific options on the underlying socket. If not specified, then
- defaults are loaded from ``HTTPConnection.default_socket_options`` which includes disabling
- Nagle's algorithm (sets TCP_NODELAY to 1) unless the connection is behind a proxy.
-
- For example, if you wish to enable TCP Keep Alive in addition to the defaults,
- you might pass:
-
- .. code-block:: python
-
- HTTPConnection.default_socket_options + [
- (socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1),
- ]
-
- Or you may want to disable the defaults by passing an empty list (e.g., ``[]``).
- """
-
- default_port: typing.ClassVar[int] = port_by_scheme["http"] # type: ignore[misc]
-
- #: Disable Nagle's algorithm by default.
- #: ``[(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)]``
- default_socket_options: typing.ClassVar[connection._TYPE_SOCKET_OPTIONS] = [
- (socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
- ]
-
- #: Whether this connection verifies the host's certificate.
- is_verified: bool = False
-
- #: Whether this proxy connection verified the proxy host's certificate.
- # If no proxy is currently connected to the value will be ``None``.
- proxy_is_verified: bool | None = None
-
- blocksize: int
- source_address: tuple[str, int] | None
- socket_options: connection._TYPE_SOCKET_OPTIONS | None
-
- _has_connected_to_proxy: bool
- _response_options: _ResponseOptions | None
- _tunnel_host: str | None
- _tunnel_port: int | None
- _tunnel_scheme: str | None
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 16384,
- socket_options: None
- | (connection._TYPE_SOCKET_OPTIONS) = default_socket_options,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- ) -> None:
- super().__init__(
- host=host,
- port=port,
- timeout=Timeout.resolve_default_timeout(timeout),
- source_address=source_address,
- blocksize=blocksize,
- )
- self.socket_options = socket_options
- self.proxy = proxy
- self.proxy_config = proxy_config
-
- self._has_connected_to_proxy = False
- self._response_options = None
- self._tunnel_host: str | None = None
- self._tunnel_port: int | None = None
- self._tunnel_scheme: str | None = None
-
- @property
- def host(self) -> str:
- """
- Getter method to remove any trailing dots that indicate the hostname is an FQDN.
-
- In general, SSL certificates don't include the trailing dot indicating a
- fully-qualified domain name, and thus, they don't validate properly when
- checked against a domain name that includes the dot. In addition, some
- servers may not expect to receive the trailing dot when provided.
-
- However, the hostname with trailing dot is critical to DNS resolution; doing a
- lookup with the trailing dot will properly only resolve the appropriate FQDN,
- whereas a lookup without a trailing dot will search the system's search domain
- list. Thus, it's important to keep the original host around for use only in
- those cases where it's appropriate (i.e., when doing DNS lookup to establish the
- actual TCP connection across which we're going to send HTTP requests).
- """
- return self._dns_host.rstrip(".")
-
- @host.setter
- def host(self, value: str) -> None:
- """
- Setter for the `host` property.
-
- We assume that only urllib3 uses the _dns_host attribute; httplib itself
- only uses `host`, and it seems reasonable that other libraries follow suit.
- """
- self._dns_host = value
-
- def _new_conn(self) -> socket.socket:
- """Establish a socket connection and set nodelay settings on it.
-
- :return: New socket connection.
- """
- try:
- sock = connection.create_connection(
- (self._dns_host, self.port),
- self.timeout,
- source_address=self.source_address,
- socket_options=self.socket_options,
- )
- except socket.gaierror as e:
- raise NameResolutionError(self.host, self, e) from e
- except SocketTimeout as e:
- raise ConnectTimeoutError(
- self,
- f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
- ) from e
-
- except OSError as e:
- raise NewConnectionError(
- self, f"Failed to establish a new connection: {e}"
- ) from e
-
- # Audit hooks are only available in Python 3.8+
- if _HAS_SYS_AUDIT:
- sys.audit("http.client.connect", self, self.host, self.port)
-
- return sock
-
- def set_tunnel(
- self,
- host: str,
- port: int | None = None,
- headers: typing.Mapping[str, str] | None = None,
- scheme: str = "http",
- ) -> None:
- if scheme not in ("http", "https"):
- raise ValueError(
- f"Invalid proxy scheme for tunneling: {scheme!r}, must be either 'http' or 'https'"
- )
- super().set_tunnel(host, port=port, headers=headers)
- self._tunnel_scheme = scheme
-
- def connect(self) -> None:
- self.sock = self._new_conn()
- if self._tunnel_host:
- # If we're tunneling it means we're connected to our proxy.
- self._has_connected_to_proxy = True
-
- # TODO: Fix tunnel so it doesn't depend on self.sock state.
- self._tunnel() # type: ignore[attr-defined]
-
- # If there's a proxy to be connected to we are fully connected.
- # This is set twice (once above and here) due to forwarding proxies
- # not using tunnelling.
- self._has_connected_to_proxy = bool(self.proxy)
-
- if self._has_connected_to_proxy:
- self.proxy_is_verified = False
-
- @property
- def is_closed(self) -> bool:
- return self.sock is None
-
- @property
- def is_connected(self) -> bool:
- if self.sock is None:
- return False
- return not wait_for_read(self.sock, timeout=0.0)
-
- @property
- def has_connected_to_proxy(self) -> bool:
- return self._has_connected_to_proxy
-
- @property
- def proxy_is_forwarding(self) -> bool:
- """
- Return True if a forwarding proxy is configured, else return False
- """
- return bool(self.proxy) and self._tunnel_host is None
-
- def close(self) -> None:
- try:
- super().close()
- finally:
- # Reset all stateful properties so connection
- # can be re-used without leaking prior configs.
- self.sock = None
- self.is_verified = False
- self.proxy_is_verified = None
- self._has_connected_to_proxy = False
- self._response_options = None
- self._tunnel_host = None
- self._tunnel_port = None
- self._tunnel_scheme = None
-
- def putrequest(
- self,
- method: str,
- url: str,
- skip_host: bool = False,
- skip_accept_encoding: bool = False,
- ) -> None:
- """"""
- # Empty docstring because the indentation of CPython's implementation
- # is broken but we don't want this method in our documentation.
- match = _CONTAINS_CONTROL_CHAR_RE.search(method)
- if match:
- raise ValueError(
- f"Method cannot contain non-token characters {method!r} (found at least {match.group()!r})"
- )
-
- return super().putrequest(
- method, url, skip_host=skip_host, skip_accept_encoding=skip_accept_encoding
- )
-
- def putheader(self, header: str, *values: str) -> None: # type: ignore[override]
- """"""
- if not any(isinstance(v, str) and v == SKIP_HEADER for v in values):
- super().putheader(header, *values)
- elif to_str(header.lower()) not in SKIPPABLE_HEADERS:
- skippable_headers = "', '".join(
- [str.title(header) for header in sorted(SKIPPABLE_HEADERS)]
- )
- raise ValueError(
- f"urllib3.util.SKIP_HEADER only supports '{skippable_headers}'"
- )
-
- # `request` method's signature intentionally violates LSP.
- # urllib3's API is different from `http.client.HTTPConnection` and the subclassing is only incidental.
- def request( # type: ignore[override]
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- *,
- chunked: bool = False,
- preload_content: bool = True,
- decode_content: bool = True,
- enforce_content_length: bool = True,
- ) -> None:
- # Update the inner socket's timeout value to send the request.
- # This only triggers if the connection is re-used.
- if self.sock is not None:
- self.sock.settimeout(self.timeout)
-
- # Store these values to be fed into the HTTPResponse
- # object later. TODO: Remove this in favor of a real
- # HTTP lifecycle mechanism.
-
- # We have to store these before we call .request()
- # because sometimes we can still salvage a response
- # off the wire even if we aren't able to completely
- # send the request body.
- self._response_options = _ResponseOptions(
- request_method=method,
- request_url=url,
- preload_content=preload_content,
- decode_content=decode_content,
- enforce_content_length=enforce_content_length,
- )
-
- if headers is None:
- headers = {}
- header_keys = frozenset(to_str(k.lower()) for k in headers)
- skip_accept_encoding = "accept-encoding" in header_keys
- skip_host = "host" in header_keys
- self.putrequest(
- method, url, skip_accept_encoding=skip_accept_encoding, skip_host=skip_host
- )
-
- # Transform the body into an iterable of sendall()-able chunks
- # and detect if an explicit Content-Length is doable.
- chunks_and_cl = body_to_chunks(body, method=method, blocksize=self.blocksize)
- chunks = chunks_and_cl.chunks
- content_length = chunks_and_cl.content_length
-
- # When chunked is explicit set to 'True' we respect that.
- if chunked:
- if "transfer-encoding" not in header_keys:
- self.putheader("Transfer-Encoding", "chunked")
- else:
- # Detect whether a framing mechanism is already in use. If so
- # we respect that value, otherwise we pick chunked vs content-length
- # depending on the type of 'body'.
- if "content-length" in header_keys:
- chunked = False
- elif "transfer-encoding" in header_keys:
- chunked = True
-
- # Otherwise we go off the recommendation of 'body_to_chunks()'.
- else:
- chunked = False
- if content_length is None:
- if chunks is not None:
- chunked = True
- self.putheader("Transfer-Encoding", "chunked")
- else:
- self.putheader("Content-Length", str(content_length))
-
- # Now that framing headers are out of the way we send all the other headers.
- if "user-agent" not in header_keys:
- self.putheader("User-Agent", _get_default_user_agent())
- for header, value in headers.items():
- self.putheader(header, value)
- self.endheaders()
-
- # If we're given a body we start sending that in chunks.
- if chunks is not None:
- for chunk in chunks:
- # Sending empty chunks isn't allowed for TE: chunked
- # as it indicates the end of the body.
- if not chunk:
- continue
- if isinstance(chunk, str):
- chunk = chunk.encode("utf-8")
- if chunked:
- self.send(b"%x\r\n%b\r\n" % (len(chunk), chunk))
- else:
- self.send(chunk)
-
- # Regardless of whether we have a body or not, if we're in
- # chunked mode we want to send an explicit empty chunk.
- if chunked:
- self.send(b"0\r\n\r\n")
-
- def request_chunked(
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- ) -> None:
- """
- Alternative to the common request method, which sends the
- body with chunked encoding and not as one block
- """
- warnings.warn(
- "HTTPConnection.request_chunked() is deprecated and will be removed "
- "in urllib3 v2.1.0. Instead use HTTPConnection.request(..., chunked=True).",
- category=DeprecationWarning,
- stacklevel=2,
- )
- self.request(method, url, body=body, headers=headers, chunked=True)
-
- def getresponse( # type: ignore[override]
- self,
- ) -> HTTPResponse:
- """
- Get the response from the server.
-
- If the HTTPConnection is in the correct state, returns an instance of HTTPResponse or of whatever object is returned by the response_class variable.
-
- If a request has not been sent or if a previous response has not be handled, ResponseNotReady is raised. If the HTTP response indicates that the connection should be closed, then it will be closed before the response is returned. When the connection is closed, the underlying socket is closed.
- """
- # Raise the same error as http.client.HTTPConnection
- if self._response_options is None:
- raise ResponseNotReady()
-
- # Reset this attribute for being used again.
- resp_options = self._response_options
- self._response_options = None
-
- # Since the connection's timeout value may have been updated
- # we need to set the timeout on the socket.
- self.sock.settimeout(self.timeout)
-
- # This is needed here to avoid circular import errors
- from .response import HTTPResponse
-
- # Get the response from http.client.HTTPConnection
- httplib_response = super().getresponse()
-
- try:
- assert_header_parsing(httplib_response.msg)
- except (HeaderParsingError, TypeError) as hpe:
- log.warning(
- "Failed to parse headers (url=%s): %s",
- _url_from_connection(self, resp_options.request_url),
- hpe,
- exc_info=True,
- )
-
- headers = HTTPHeaderDict(httplib_response.msg.items())
-
- response = HTTPResponse(
- body=httplib_response,
- headers=headers,
- status=httplib_response.status,
- version=httplib_response.version,
- version_string=getattr(self, "_http_vsn_str", "HTTP/?"),
- reason=httplib_response.reason,
- preload_content=resp_options.preload_content,
- decode_content=resp_options.decode_content,
- original_response=httplib_response,
- enforce_content_length=resp_options.enforce_content_length,
- request_method=resp_options.request_method,
- request_url=resp_options.request_url,
- )
- return response
-
-
-class HTTPSConnection(HTTPConnection):
- """
- Many of the parameters to this constructor are passed to the underlying SSL
- socket by means of :py:func:`urllib3.util.ssl_wrap_socket`.
- """
-
- default_port = port_by_scheme["https"] # type: ignore[misc]
-
- cert_reqs: int | str | None = None
- ca_certs: str | None = None
- ca_cert_dir: str | None = None
- ca_cert_data: None | str | bytes = None
- ssl_version: int | str | None = None
- ssl_minimum_version: int | None = None
- ssl_maximum_version: int | None = None
- assert_fingerprint: str | None = None
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 16384,
- socket_options: None
- | (connection._TYPE_SOCKET_OPTIONS) = HTTPConnection.default_socket_options,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- cert_reqs: int | str | None = None,
- assert_hostname: None | str | typing.Literal[False] = None,
- assert_fingerprint: str | None = None,
- server_hostname: str | None = None,
- ssl_context: ssl.SSLContext | None = None,
- ca_certs: str | None = None,
- ca_cert_dir: str | None = None,
- ca_cert_data: None | str | bytes = None,
- ssl_minimum_version: int | None = None,
- ssl_maximum_version: int | None = None,
- ssl_version: int | str | None = None, # Deprecated
- cert_file: str | None = None,
- key_file: str | None = None,
- key_password: str | None = None,
- ) -> None:
- super().__init__(
- host,
- port=port,
- timeout=timeout,
- source_address=source_address,
- blocksize=blocksize,
- socket_options=socket_options,
- proxy=proxy,
- proxy_config=proxy_config,
- )
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.key_password = key_password
- self.ssl_context = ssl_context
- self.server_hostname = server_hostname
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
- self.ssl_version = ssl_version
- self.ssl_minimum_version = ssl_minimum_version
- self.ssl_maximum_version = ssl_maximum_version
- self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
- self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
- self.ca_cert_data = ca_cert_data
-
- # cert_reqs depends on ssl_context so calculate last.
- if cert_reqs is None:
- if self.ssl_context is not None:
- cert_reqs = self.ssl_context.verify_mode
- else:
- cert_reqs = resolve_cert_reqs(None)
- self.cert_reqs = cert_reqs
-
- def set_cert(
- self,
- key_file: str | None = None,
- cert_file: str | None = None,
- cert_reqs: int | str | None = None,
- key_password: str | None = None,
- ca_certs: str | None = None,
- assert_hostname: None | str | typing.Literal[False] = None,
- assert_fingerprint: str | None = None,
- ca_cert_dir: str | None = None,
- ca_cert_data: None | str | bytes = None,
- ) -> None:
- """
- This method should only be called once, before the connection is used.
- """
- warnings.warn(
- "HTTPSConnection.set_cert() is deprecated and will be removed "
- "in urllib3 v2.1.0. Instead provide the parameters to the "
- "HTTPSConnection constructor.",
- category=DeprecationWarning,
- stacklevel=2,
- )
-
- # If cert_reqs is not provided we'll assume CERT_REQUIRED unless we also
- # have an SSLContext object in which case we'll use its verify_mode.
- if cert_reqs is None:
- if self.ssl_context is not None:
- cert_reqs = self.ssl_context.verify_mode
- else:
- cert_reqs = resolve_cert_reqs(None)
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.cert_reqs = cert_reqs
- self.key_password = key_password
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
- self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
- self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
- self.ca_cert_data = ca_cert_data
-
- def connect(self) -> None:
- sock: socket.socket | ssl.SSLSocket
- self.sock = sock = self._new_conn()
- server_hostname: str = self.host
- tls_in_tls = False
-
- # Do we need to establish a tunnel?
- if self._tunnel_host is not None:
- # We're tunneling to an HTTPS origin so need to do TLS-in-TLS.
- if self._tunnel_scheme == "https":
- # _connect_tls_proxy will verify and assign proxy_is_verified
- self.sock = sock = self._connect_tls_proxy(self.host, sock)
- tls_in_tls = True
- elif self._tunnel_scheme == "http":
- self.proxy_is_verified = False
-
- # If we're tunneling it means we're connected to our proxy.
- self._has_connected_to_proxy = True
-
- self._tunnel() # type: ignore[attr-defined]
- # Override the host with the one we're requesting data from.
- server_hostname = self._tunnel_host
-
- if self.server_hostname is not None:
- server_hostname = self.server_hostname
-
- is_time_off = datetime.date.today() < RECENT_DATE
- if is_time_off:
- warnings.warn(
- (
- f"System time is way off (before {RECENT_DATE}). This will probably "
- "lead to SSL verification errors"
- ),
- SystemTimeWarning,
- )
-
- # Remove trailing '.' from fqdn hostnames to allow certificate validation
- server_hostname_rm_dot = server_hostname.rstrip(".")
-
- sock_and_verified = _ssl_wrap_socket_and_match_hostname(
- sock=sock,
- cert_reqs=self.cert_reqs,
- ssl_version=self.ssl_version,
- ssl_minimum_version=self.ssl_minimum_version,
- ssl_maximum_version=self.ssl_maximum_version,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- ca_cert_data=self.ca_cert_data,
- cert_file=self.cert_file,
- key_file=self.key_file,
- key_password=self.key_password,
- server_hostname=server_hostname_rm_dot,
- ssl_context=self.ssl_context,
- tls_in_tls=tls_in_tls,
- assert_hostname=self.assert_hostname,
- assert_fingerprint=self.assert_fingerprint,
- )
- self.sock = sock_and_verified.socket
-
- # Forwarding proxies can never have a verified target since
- # the proxy is the one doing the verification. Should instead
- # use a CONNECT tunnel in order to verify the target.
- # See: https://github.com/urllib3/urllib3/issues/3267.
- if self.proxy_is_forwarding:
- self.is_verified = False
- else:
- self.is_verified = sock_and_verified.is_verified
-
- # If there's a proxy to be connected to we are fully connected.
- # This is set twice (once above and here) due to forwarding proxies
- # not using tunnelling.
- self._has_connected_to_proxy = bool(self.proxy)
-
- # Set `self.proxy_is_verified` unless it's already set while
- # establishing a tunnel.
- if self._has_connected_to_proxy and self.proxy_is_verified is None:
- self.proxy_is_verified = sock_and_verified.is_verified
-
- def _connect_tls_proxy(self, hostname: str, sock: socket.socket) -> ssl.SSLSocket:
- """
- Establish a TLS connection to the proxy using the provided SSL context.
- """
- # `_connect_tls_proxy` is called when self._tunnel_host is truthy.
- proxy_config = typing.cast(ProxyConfig, self.proxy_config)
- ssl_context = proxy_config.ssl_context
- sock_and_verified = _ssl_wrap_socket_and_match_hostname(
- sock,
- cert_reqs=self.cert_reqs,
- ssl_version=self.ssl_version,
- ssl_minimum_version=self.ssl_minimum_version,
- ssl_maximum_version=self.ssl_maximum_version,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- ca_cert_data=self.ca_cert_data,
- server_hostname=hostname,
- ssl_context=ssl_context,
- assert_hostname=proxy_config.assert_hostname,
- assert_fingerprint=proxy_config.assert_fingerprint,
- # Features that aren't implemented for proxies yet:
- cert_file=None,
- key_file=None,
- key_password=None,
- tls_in_tls=False,
- )
- self.proxy_is_verified = sock_and_verified.is_verified
- return sock_and_verified.socket # type: ignore[return-value]
-
-
-class _WrappedAndVerifiedSocket(typing.NamedTuple):
- """
- Wrapped socket and whether the connection is
- verified after the TLS handshake
- """
-
- socket: ssl.SSLSocket | SSLTransport
- is_verified: bool
-
-
-def _ssl_wrap_socket_and_match_hostname(
- sock: socket.socket,
- *,
- cert_reqs: None | str | int,
- ssl_version: None | str | int,
- ssl_minimum_version: int | None,
- ssl_maximum_version: int | None,
- cert_file: str | None,
- key_file: str | None,
- key_password: str | None,
- ca_certs: str | None,
- ca_cert_dir: str | None,
- ca_cert_data: None | str | bytes,
- assert_hostname: None | str | typing.Literal[False],
- assert_fingerprint: str | None,
- server_hostname: str | None,
- ssl_context: ssl.SSLContext | None,
- tls_in_tls: bool = False,
-) -> _WrappedAndVerifiedSocket:
- """Logic for constructing an SSLContext from all TLS parameters, passing
- that down into ssl_wrap_socket, and then doing certificate verification
- either via hostname or fingerprint. This function exists to guarantee
- that both proxies and targets have the same behavior when connecting via TLS.
- """
- default_ssl_context = False
- if ssl_context is None:
- default_ssl_context = True
- context = create_urllib3_context(
- ssl_version=resolve_ssl_version(ssl_version),
- ssl_minimum_version=ssl_minimum_version,
- ssl_maximum_version=ssl_maximum_version,
- cert_reqs=resolve_cert_reqs(cert_reqs),
- )
- else:
- context = ssl_context
-
- context.verify_mode = resolve_cert_reqs(cert_reqs)
-
- # In some cases, we want to verify hostnames ourselves
- if (
- # `ssl` can't verify fingerprints or alternate hostnames
- assert_fingerprint
- or assert_hostname
- # assert_hostname can be set to False to disable hostname checking
- or assert_hostname is False
- # We still support OpenSSL 1.0.2, which prevents us from verifying
- # hostnames easily: https://github.com/pyca/pyopenssl/pull/933
- or ssl_.IS_PYOPENSSL
- or not ssl_.HAS_NEVER_CHECK_COMMON_NAME
- ):
- context.check_hostname = False
-
- # Try to load OS default certs if none are given. We need to do the hasattr() check
- # for custom pyOpenSSL SSLContext objects because they don't support
- # load_default_certs().
- if (
- not ca_certs
- and not ca_cert_dir
- and not ca_cert_data
- and default_ssl_context
- and hasattr(context, "load_default_certs")
- ):
- context.load_default_certs()
-
- # Ensure that IPv6 addresses are in the proper format and don't have a
- # scope ID. Python's SSL module fails to recognize scoped IPv6 addresses
- # and interprets them as DNS hostnames.
- if server_hostname is not None:
- normalized = server_hostname.strip("[]")
- if "%" in normalized:
- normalized = normalized[: normalized.rfind("%")]
- if is_ipaddress(normalized):
- server_hostname = normalized
-
- ssl_sock = ssl_wrap_socket(
- sock=sock,
- keyfile=key_file,
- certfile=cert_file,
- key_password=key_password,
- ca_certs=ca_certs,
- ca_cert_dir=ca_cert_dir,
- ca_cert_data=ca_cert_data,
- server_hostname=server_hostname,
- ssl_context=context,
- tls_in_tls=tls_in_tls,
- )
-
- try:
- if assert_fingerprint:
- _assert_fingerprint(
- ssl_sock.getpeercert(binary_form=True), assert_fingerprint
- )
- elif (
- context.verify_mode != ssl.CERT_NONE
- and not context.check_hostname
- and assert_hostname is not False
- ):
- cert: _TYPE_PEER_CERT_RET_DICT = ssl_sock.getpeercert() # type: ignore[assignment]
-
- # Need to signal to our match_hostname whether to use 'commonName' or not.
- # If we're using our own constructed SSLContext we explicitly set 'False'
- # because PyPy hard-codes 'True' from SSLContext.hostname_checks_common_name.
- if default_ssl_context:
- hostname_checks_common_name = False
- else:
- hostname_checks_common_name = (
- getattr(context, "hostname_checks_common_name", False) or False
- )
-
- _match_hostname(
- cert,
- assert_hostname or server_hostname, # type: ignore[arg-type]
- hostname_checks_common_name,
- )
-
- return _WrappedAndVerifiedSocket(
- socket=ssl_sock,
- is_verified=context.verify_mode == ssl.CERT_REQUIRED
- or bool(assert_fingerprint),
- )
- except BaseException:
- ssl_sock.close()
- raise
-
-
-def _match_hostname(
- cert: _TYPE_PEER_CERT_RET_DICT | None,
- asserted_hostname: str,
- hostname_checks_common_name: bool = False,
-) -> None:
- # Our upstream implementation of ssl.match_hostname()
- # only applies this normalization to IP addresses so it doesn't
- # match DNS SANs so we do the same thing!
- stripped_hostname = asserted_hostname.strip("[]")
- if is_ipaddress(stripped_hostname):
- asserted_hostname = stripped_hostname
-
- try:
- match_hostname(cert, asserted_hostname, hostname_checks_common_name)
- except CertificateError as e:
- log.warning(
- "Certificate did not match expected hostname: %s. Certificate: %s",
- asserted_hostname,
- cert,
- )
- # Add cert to exception and reraise so client code can inspect
- # the cert when catching the exception, if they want to
- e._peer_cert = cert # type: ignore[attr-defined]
- raise
-
-
-def _wrap_proxy_error(err: Exception, proxy_scheme: str | None) -> ProxyError:
- # Look for the phrase 'wrong version number', if found
- # then we should warn the user that we're very sure that
- # this proxy is HTTP-only and they have a configuration issue.
- error_normalized = " ".join(re.split("[^a-z]", str(err).lower()))
- is_likely_http_proxy = (
- "wrong version number" in error_normalized
- or "unknown protocol" in error_normalized
- or "record layer failure" in error_normalized
- )
- http_proxy_warning = (
- ". Your proxy appears to only use HTTP and not HTTPS, "
- "try changing your proxy URL to be HTTP. See: "
- "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
- "#https-proxy-error-http-proxy"
- )
- new_err = ProxyError(
- f"Unable to connect to proxy"
- f"{http_proxy_warning if is_likely_http_proxy and proxy_scheme == 'https' else ''}",
- err,
- )
- new_err.__cause__ = err
- return new_err
-
-
-def _get_default_user_agent() -> str:
- return f"python-urllib3/{__version__}"
-
-
-class DummyConnection:
- """Used to detect a failed ConnectionCls import."""
-
-
-if not ssl:
- HTTPSConnection = DummyConnection # type: ignore[misc, assignment] # noqa: F811
-
-
-VerifiedHTTPSConnection = HTTPSConnection
-
-
-def _url_from_connection(
- conn: HTTPConnection | HTTPSConnection, path: str | None = None
-) -> str:
- """Returns the URL from a given connection. This is mainly used for testing and logging."""
-
- scheme = "https" if isinstance(conn, HTTPSConnection) else "http"
-
- return Url(scheme=scheme, host=conn.host, port=conn.port, path=path).url
diff --git a/.venv/lib/python3.12/site-packages/urllib3/connectionpool.py b/.venv/lib/python3.12/site-packages/urllib3/connectionpool.py
deleted file mode 100644
index a2c3cf6..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/connectionpool.py
+++ /dev/null
@@ -1,1182 +0,0 @@
-from __future__ import annotations
-
-import errno
-import logging
-import queue
-import sys
-import typing
-import warnings
-import weakref
-from socket import timeout as SocketTimeout
-from types import TracebackType
-
-from ._base_connection import _TYPE_BODY
-from ._collections import HTTPHeaderDict
-from ._request_methods import RequestMethods
-from .connection import (
- BaseSSLError,
- BrokenPipeError,
- DummyConnection,
- HTTPConnection,
- HTTPException,
- HTTPSConnection,
- ProxyConfig,
- _wrap_proxy_error,
-)
-from .connection import port_by_scheme as port_by_scheme
-from .exceptions import (
- ClosedPoolError,
- EmptyPoolError,
- FullPoolError,
- HostChangedError,
- InsecureRequestWarning,
- LocationValueError,
- MaxRetryError,
- NewConnectionError,
- ProtocolError,
- ProxyError,
- ReadTimeoutError,
- SSLError,
- TimeoutError,
-)
-from .response import BaseHTTPResponse
-from .util.connection import is_connection_dropped
-from .util.proxy import connection_requires_http_tunnel
-from .util.request import _TYPE_BODY_POSITION, set_file_position
-from .util.retry import Retry
-from .util.ssl_match_hostname import CertificateError
-from .util.timeout import _DEFAULT_TIMEOUT, _TYPE_DEFAULT, Timeout
-from .util.url import Url, _encode_target
-from .util.url import _normalize_host as normalize_host
-from .util.url import parse_url
-from .util.util import to_str
-
-if typing.TYPE_CHECKING:
- import ssl
-
- from typing_extensions import Self
-
- from ._base_connection import BaseHTTPConnection, BaseHTTPSConnection
-
-log = logging.getLogger(__name__)
-
-_TYPE_TIMEOUT = typing.Union[Timeout, float, _TYPE_DEFAULT, None]
-
-
-# Pool objects
-class ConnectionPool:
- """
- Base class for all connection pools, such as
- :class:`.HTTPConnectionPool` and :class:`.HTTPSConnectionPool`.
-
- .. note::
- ConnectionPool.urlopen() does not normalize or percent-encode target URIs
- which is useful if your target server doesn't support percent-encoded
- target URIs.
- """
-
- scheme: str | None = None
- QueueCls = queue.LifoQueue
-
- def __init__(self, host: str, port: int | None = None) -> None:
- if not host:
- raise LocationValueError("No host specified.")
-
- self.host = _normalize_host(host, scheme=self.scheme)
- self.port = port
-
- # This property uses 'normalize_host()' (not '_normalize_host()')
- # to avoid removing square braces around IPv6 addresses.
- # This value is sent to `HTTPConnection.set_tunnel()` if called
- # because square braces are required for HTTP CONNECT tunneling.
- self._tunnel_host = normalize_host(host, scheme=self.scheme).lower()
-
- def __str__(self) -> str:
- return f"{type(self).__name__}(host={self.host!r}, port={self.port!r})"
-
- def __enter__(self) -> Self:
- return self
-
- def __exit__(
- self,
- exc_type: type[BaseException] | None,
- exc_val: BaseException | None,
- exc_tb: TracebackType | None,
- ) -> typing.Literal[False]:
- self.close()
- # Return False to re-raise any potential exceptions
- return False
-
- def close(self) -> None:
- """
- Close all pooled connections and disable the pool.
- """
-
-
-# This is taken from http://hg.python.org/cpython/file/7aaba721ebc0/Lib/socket.py#l252
-_blocking_errnos = {errno.EAGAIN, errno.EWOULDBLOCK}
-
-
-class HTTPConnectionPool(ConnectionPool, RequestMethods):
- """
- Thread-safe connection pool for one host.
-
- :param host:
- Host used for this HTTP Connection (e.g. "localhost"), passed into
- :class:`http.client.HTTPConnection`.
-
- :param port:
- Port used for this HTTP Connection (None is equivalent to 80), passed
- into :class:`http.client.HTTPConnection`.
-
- :param timeout:
- Socket timeout in seconds for each individual connection. This can
- be a float or integer, which sets the timeout for the HTTP request,
- or an instance of :class:`urllib3.util.Timeout` which gives you more
- fine-grained control over request timeouts. After the constructor has
- been parsed, this is always a `urllib3.util.Timeout` object.
-
- :param maxsize:
- Number of connections to save that can be reused. More than 1 is useful
- in multithreaded situations. If ``block`` is set to False, more
- connections will be created but they will not be saved once they've
- been used.
-
- :param block:
- If set to True, no more than ``maxsize`` connections will be used at
- a time. When no free connections are available, the call will block
- until a connection has been released. This is a useful side effect for
- particular multithreaded situations where one does not want to use more
- than maxsize connections per host to prevent flooding.
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
-
- :param retries:
- Retry configuration to use by default with requests in this pool.
-
- :param _proxy:
- Parsed proxy URL, should not be used directly, instead, see
- :class:`urllib3.ProxyManager`
-
- :param _proxy_headers:
- A dictionary with proxy headers, should not be used directly,
- instead, see :class:`urllib3.ProxyManager`
-
- :param \\**conn_kw:
- Additional parameters are used to create fresh :class:`urllib3.connection.HTTPConnection`,
- :class:`urllib3.connection.HTTPSConnection` instances.
- """
-
- scheme = "http"
- ConnectionCls: (
- type[BaseHTTPConnection] | type[BaseHTTPSConnection]
- ) = HTTPConnection
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- timeout: _TYPE_TIMEOUT | None = _DEFAULT_TIMEOUT,
- maxsize: int = 1,
- block: bool = False,
- headers: typing.Mapping[str, str] | None = None,
- retries: Retry | bool | int | None = None,
- _proxy: Url | None = None,
- _proxy_headers: typing.Mapping[str, str] | None = None,
- _proxy_config: ProxyConfig | None = None,
- **conn_kw: typing.Any,
- ):
- ConnectionPool.__init__(self, host, port)
- RequestMethods.__init__(self, headers)
-
- if not isinstance(timeout, Timeout):
- timeout = Timeout.from_float(timeout)
-
- if retries is None:
- retries = Retry.DEFAULT
-
- self.timeout = timeout
- self.retries = retries
-
- self.pool: queue.LifoQueue[typing.Any] | None = self.QueueCls(maxsize)
- self.block = block
-
- self.proxy = _proxy
- self.proxy_headers = _proxy_headers or {}
- self.proxy_config = _proxy_config
-
- # Fill the queue up so that doing get() on it will block properly
- for _ in range(maxsize):
- self.pool.put(None)
-
- # These are mostly for testing and debugging purposes.
- self.num_connections = 0
- self.num_requests = 0
- self.conn_kw = conn_kw
-
- if self.proxy:
- # Enable Nagle's algorithm for proxies, to avoid packet fragmentation.
- # We cannot know if the user has added default socket options, so we cannot replace the
- # list.
- self.conn_kw.setdefault("socket_options", [])
-
- self.conn_kw["proxy"] = self.proxy
- self.conn_kw["proxy_config"] = self.proxy_config
-
- # Do not pass 'self' as callback to 'finalize'.
- # Then the 'finalize' would keep an endless living (leak) to self.
- # By just passing a reference to the pool allows the garbage collector
- # to free self if nobody else has a reference to it.
- pool = self.pool
-
- # Close all the HTTPConnections in the pool before the
- # HTTPConnectionPool object is garbage collected.
- weakref.finalize(self, _close_pool_connections, pool)
-
- def _new_conn(self) -> BaseHTTPConnection:
- """
- Return a fresh :class:`HTTPConnection`.
- """
- self.num_connections += 1
- log.debug(
- "Starting new HTTP connection (%d): %s:%s",
- self.num_connections,
- self.host,
- self.port or "80",
- )
-
- conn = self.ConnectionCls(
- host=self.host,
- port=self.port,
- timeout=self.timeout.connect_timeout,
- **self.conn_kw,
- )
- return conn
-
- def _get_conn(self, timeout: float | None = None) -> BaseHTTPConnection:
- """
- Get a connection. Will return a pooled connection if one is available.
-
- If no connections are available and :prop:`.block` is ``False``, then a
- fresh connection is returned.
-
- :param timeout:
- Seconds to wait before giving up and raising
- :class:`urllib3.exceptions.EmptyPoolError` if the pool is empty and
- :prop:`.block` is ``True``.
- """
- conn = None
-
- if self.pool is None:
- raise ClosedPoolError(self, "Pool is closed.")
-
- try:
- conn = self.pool.get(block=self.block, timeout=timeout)
-
- except AttributeError: # self.pool is None
- raise ClosedPoolError(self, "Pool is closed.") from None # Defensive:
-
- except queue.Empty:
- if self.block:
- raise EmptyPoolError(
- self,
- "Pool is empty and a new connection can't be opened due to blocking mode.",
- ) from None
- pass # Oh well, we'll create a new connection then
-
- # If this is a persistent connection, check if it got disconnected
- if conn and is_connection_dropped(conn):
- log.debug("Resetting dropped connection: %s", self.host)
- conn.close()
-
- return conn or self._new_conn()
-
- def _put_conn(self, conn: BaseHTTPConnection | None) -> None:
- """
- Put a connection back into the pool.
-
- :param conn:
- Connection object for the current host and port as returned by
- :meth:`._new_conn` or :meth:`._get_conn`.
-
- If the pool is already full, the connection is closed and discarded
- because we exceeded maxsize. If connections are discarded frequently,
- then maxsize should be increased.
-
- If the pool is closed, then the connection will be closed and discarded.
- """
- if self.pool is not None:
- try:
- self.pool.put(conn, block=False)
- return # Everything is dandy, done.
- except AttributeError:
- # self.pool is None.
- pass
- except queue.Full:
- # Connection never got put back into the pool, close it.
- if conn:
- conn.close()
-
- if self.block:
- # This should never happen if you got the conn from self._get_conn
- raise FullPoolError(
- self,
- "Pool reached maximum size and no more connections are allowed.",
- ) from None
-
- log.warning(
- "Connection pool is full, discarding connection: %s. Connection pool size: %s",
- self.host,
- self.pool.qsize(),
- )
-
- # Connection never got put back into the pool, close it.
- if conn:
- conn.close()
-
- def _validate_conn(self, conn: BaseHTTPConnection) -> None:
- """
- Called right before a request is made, after the socket is created.
- """
-
- def _prepare_proxy(self, conn: BaseHTTPConnection) -> None:
- # Nothing to do for HTTP connections.
- pass
-
- def _get_timeout(self, timeout: _TYPE_TIMEOUT) -> Timeout:
- """Helper that always returns a :class:`urllib3.util.Timeout`"""
- if timeout is _DEFAULT_TIMEOUT:
- return self.timeout.clone()
-
- if isinstance(timeout, Timeout):
- return timeout.clone()
- else:
- # User passed us an int/float. This is for backwards compatibility,
- # can be removed later
- return Timeout.from_float(timeout)
-
- def _raise_timeout(
- self,
- err: BaseSSLError | OSError | SocketTimeout,
- url: str,
- timeout_value: _TYPE_TIMEOUT | None,
- ) -> None:
- """Is the error actually a timeout? Will raise a ReadTimeout or pass"""
-
- if isinstance(err, SocketTimeout):
- raise ReadTimeoutError(
- self, url, f"Read timed out. (read timeout={timeout_value})"
- ) from err
-
- # See the above comment about EAGAIN in Python 3.
- if hasattr(err, "errno") and err.errno in _blocking_errnos:
- raise ReadTimeoutError(
- self, url, f"Read timed out. (read timeout={timeout_value})"
- ) from err
-
- def _make_request(
- self,
- conn: BaseHTTPConnection,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- retries: Retry | None = None,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- chunked: bool = False,
- response_conn: BaseHTTPConnection | None = None,
- preload_content: bool = True,
- decode_content: bool = True,
- enforce_content_length: bool = True,
- ) -> BaseHTTPResponse:
- """
- Perform a request on a given urllib connection object taken from our
- pool.
-
- :param conn:
- a connection from one of our connection pools
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param body:
- Data to send in the request body, either :class:`str`, :class:`bytes`,
- an iterable of :class:`str`/:class:`bytes`, or a file-like object.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
-
- :param retries:
- Configure the number of retries to allow before raising a
- :class:`~urllib3.exceptions.MaxRetryError` exception.
-
- Pass ``None`` to retry until you receive a response. Pass a
- :class:`~urllib3.util.retry.Retry` object for fine-grained control
- over different types of retries.
- Pass an integer number to retry connection errors that many times,
- but no other types of errors. Pass zero to never retry.
-
- If ``False``, then retries are disabled and any exception is raised
- immediately. Also, instead of raising a MaxRetryError on redirects,
- the redirect response will be returned.
-
- :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
-
- :param timeout:
- If specified, overrides the default timeout for this one
- request. It may be a float (in seconds) or an instance of
- :class:`urllib3.util.Timeout`.
-
- :param chunked:
- If True, urllib3 will send the body using chunked transfer
- encoding. Otherwise, urllib3 will send the body using the standard
- content-length form. Defaults to False.
-
- :param response_conn:
- Set this to ``None`` if you will handle releasing the connection or
- set the connection to have the response release it.
-
- :param preload_content:
- If True, the response's body will be preloaded during construction.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param enforce_content_length:
- Enforce content length checking. Body returned by server must match
- value of Content-Length header, if present. Otherwise, raise error.
- """
- self.num_requests += 1
-
- timeout_obj = self._get_timeout(timeout)
- timeout_obj.start_connect()
- conn.timeout = Timeout.resolve_default_timeout(timeout_obj.connect_timeout)
-
- try:
- # Trigger any extra validation we need to do.
- try:
- self._validate_conn(conn)
- except (SocketTimeout, BaseSSLError) as e:
- self._raise_timeout(err=e, url=url, timeout_value=conn.timeout)
- raise
-
- # _validate_conn() starts the connection to an HTTPS proxy
- # so we need to wrap errors with 'ProxyError' here too.
- except (
- OSError,
- NewConnectionError,
- TimeoutError,
- BaseSSLError,
- CertificateError,
- SSLError,
- ) as e:
- new_e: Exception = e
- if isinstance(e, (BaseSSLError, CertificateError)):
- new_e = SSLError(e)
- # If the connection didn't successfully connect to it's proxy
- # then there
- if isinstance(
- new_e, (OSError, NewConnectionError, TimeoutError, SSLError)
- ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
- new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
- raise new_e
-
- # conn.request() calls http.client.*.request, not the method in
- # urllib3.request. It also calls makefile (recv) on the socket.
- try:
- conn.request(
- method,
- url,
- body=body,
- headers=headers,
- chunked=chunked,
- preload_content=preload_content,
- decode_content=decode_content,
- enforce_content_length=enforce_content_length,
- )
-
- # We are swallowing BrokenPipeError (errno.EPIPE) since the server is
- # legitimately able to close the connection after sending a valid response.
- # With this behaviour, the received response is still readable.
- except BrokenPipeError:
- pass
- except OSError as e:
- # MacOS/Linux
- # EPROTOTYPE and ECONNRESET are needed on macOS
- # https://erickt.github.io/blog/2014/11/19/adventures-in-debugging-a-potential-osx-kernel-bug/
- # Condition changed later to emit ECONNRESET instead of only EPROTOTYPE.
- if e.errno != errno.EPROTOTYPE and e.errno != errno.ECONNRESET:
- raise
-
- # Reset the timeout for the recv() on the socket
- read_timeout = timeout_obj.read_timeout
-
- if not conn.is_closed:
- # In Python 3 socket.py will catch EAGAIN and return None when you
- # try and read into the file pointer created by http.client, which
- # instead raises a BadStatusLine exception. Instead of catching
- # the exception and assuming all BadStatusLine exceptions are read
- # timeouts, check for a zero timeout before making the request.
- if read_timeout == 0:
- raise ReadTimeoutError(
- self, url, f"Read timed out. (read timeout={read_timeout})"
- )
- conn.timeout = read_timeout
-
- # Receive the response from the server
- try:
- response = conn.getresponse()
- except (BaseSSLError, OSError) as e:
- self._raise_timeout(err=e, url=url, timeout_value=read_timeout)
- raise
-
- # Set properties that are used by the pooling layer.
- response.retries = retries
- response._connection = response_conn # type: ignore[attr-defined]
- response._pool = self # type: ignore[attr-defined]
-
- log.debug(
- '%s://%s:%s "%s %s HTTP/%s" %s %s',
- self.scheme,
- self.host,
- self.port,
- method,
- url,
- response.version,
- response.status,
- response.length_remaining,
- )
-
- return response
-
- def close(self) -> None:
- """
- Close all pooled connections and disable the pool.
- """
- if self.pool is None:
- return
- # Disable access to the pool
- old_pool, self.pool = self.pool, None
-
- # Close all the HTTPConnections in the pool.
- _close_pool_connections(old_pool)
-
- def is_same_host(self, url: str) -> bool:
- """
- Check if the given ``url`` is a member of the same host as this
- connection pool.
- """
- if url.startswith("/"):
- return True
-
- # TODO: Add optional support for socket.gethostbyname checking.
- scheme, _, host, port, *_ = parse_url(url)
- scheme = scheme or "http"
- if host is not None:
- host = _normalize_host(host, scheme=scheme)
-
- # Use explicit default port for comparison when none is given
- if self.port and not port:
- port = port_by_scheme.get(scheme)
- elif not self.port and port == port_by_scheme.get(scheme):
- port = None
-
- return (scheme, host, port) == (self.scheme, self.host, self.port)
-
- def urlopen( # type: ignore[override]
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- retries: Retry | bool | int | None = None,
- redirect: bool = True,
- assert_same_host: bool = True,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- pool_timeout: int | None = None,
- release_conn: bool | None = None,
- chunked: bool = False,
- body_pos: _TYPE_BODY_POSITION | None = None,
- preload_content: bool = True,
- decode_content: bool = True,
- **response_kw: typing.Any,
- ) -> BaseHTTPResponse:
- """
- Get a connection from the pool and perform an HTTP request. This is the
- lowest level call for making a request, so you'll need to specify all
- the raw details.
-
- .. note::
-
- More commonly, it's appropriate to use a convenience method
- such as :meth:`request`.
-
- .. note::
-
- `release_conn` will only behave as expected if
- `preload_content=False` because we want to make
- `preload_content=False` the default behaviour someday soon without
- breaking backwards compatibility.
-
- :param method:
- HTTP request method (such as GET, POST, PUT, etc.)
-
- :param url:
- The URL to perform the request on.
-
- :param body:
- Data to send in the request body, either :class:`str`, :class:`bytes`,
- an iterable of :class:`str`/:class:`bytes`, or a file-like object.
-
- :param headers:
- Dictionary of custom headers to send, such as User-Agent,
- If-None-Match, etc. If None, pool headers are used. If provided,
- these headers completely replace any pool-specific headers.
-
- :param retries:
- Configure the number of retries to allow before raising a
- :class:`~urllib3.exceptions.MaxRetryError` exception.
-
- If ``None`` (default) will retry 3 times, see ``Retry.DEFAULT``. Pass a
- :class:`~urllib3.util.retry.Retry` object for fine-grained control
- over different types of retries.
- Pass an integer number to retry connection errors that many times,
- but no other types of errors. Pass zero to never retry.
-
- If ``False``, then retries are disabled and any exception is raised
- immediately. Also, instead of raising a MaxRetryError on redirects,
- the redirect response will be returned.
-
- :type retries: :class:`~urllib3.util.retry.Retry`, False, or an int.
-
- :param redirect:
- If True, automatically handle redirects (status codes 301, 302,
- 303, 307, 308). Each redirect counts as a retry. Disabling retries
- will disable redirect, too.
-
- :param assert_same_host:
- If ``True``, will make sure that the host of the pool requests is
- consistent else will raise HostChangedError. When ``False``, you can
- use the pool on an HTTP proxy and request foreign hosts.
-
- :param timeout:
- If specified, overrides the default timeout for this one
- request. It may be a float (in seconds) or an instance of
- :class:`urllib3.util.Timeout`.
-
- :param pool_timeout:
- If set and the pool is set to block=True, then this method will
- block for ``pool_timeout`` seconds and raise EmptyPoolError if no
- connection is available within the time period.
-
- :param bool preload_content:
- If True, the response's body will be preloaded into memory.
-
- :param bool decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param release_conn:
- If False, then the urlopen call will not release the connection
- back into the pool once a response is received (but will release if
- you read the entire contents of the response such as when
- `preload_content=True`). This is useful if you're not preloading
- the response's content immediately. You will need to call
- ``r.release_conn()`` on the response ``r`` to return the connection
- back into the pool. If None, it takes the value of ``preload_content``
- which defaults to ``True``.
-
- :param bool chunked:
- If True, urllib3 will send the body using chunked transfer
- encoding. Otherwise, urllib3 will send the body using the standard
- content-length form. Defaults to False.
-
- :param int body_pos:
- Position to seek to in file-like body in the event of a retry or
- redirect. Typically this won't need to be set because urllib3 will
- auto-populate the value when needed.
- """
- parsed_url = parse_url(url)
- destination_scheme = parsed_url.scheme
-
- if headers is None:
- headers = self.headers
-
- if not isinstance(retries, Retry):
- retries = Retry.from_int(retries, redirect=redirect, default=self.retries)
-
- if release_conn is None:
- release_conn = preload_content
-
- # Check host
- if assert_same_host and not self.is_same_host(url):
- raise HostChangedError(self, url, retries)
-
- # Ensure that the URL we're connecting to is properly encoded
- if url.startswith("/"):
- url = to_str(_encode_target(url))
- else:
- url = to_str(parsed_url.url)
-
- conn = None
-
- # Track whether `conn` needs to be released before
- # returning/raising/recursing. Update this variable if necessary, and
- # leave `release_conn` constant throughout the function. That way, if
- # the function recurses, the original value of `release_conn` will be
- # passed down into the recursive call, and its value will be respected.
- #
- # See issue #651 [1] for details.
- #
- # [1]
- release_this_conn = release_conn
-
- http_tunnel_required = connection_requires_http_tunnel(
- self.proxy, self.proxy_config, destination_scheme
- )
-
- # Merge the proxy headers. Only done when not using HTTP CONNECT. We
- # have to copy the headers dict so we can safely change it without those
- # changes being reflected in anyone else's copy.
- if not http_tunnel_required:
- headers = headers.copy() # type: ignore[attr-defined]
- headers.update(self.proxy_headers) # type: ignore[union-attr]
-
- # Must keep the exception bound to a separate variable or else Python 3
- # complains about UnboundLocalError.
- err = None
-
- # Keep track of whether we cleanly exited the except block. This
- # ensures we do proper cleanup in finally.
- clean_exit = False
-
- # Rewind body position, if needed. Record current position
- # for future rewinds in the event of a redirect/retry.
- body_pos = set_file_position(body, body_pos)
-
- try:
- # Request a connection from the queue.
- timeout_obj = self._get_timeout(timeout)
- conn = self._get_conn(timeout=pool_timeout)
-
- conn.timeout = timeout_obj.connect_timeout # type: ignore[assignment]
-
- # Is this a closed/new connection that requires CONNECT tunnelling?
- if self.proxy is not None and http_tunnel_required and conn.is_closed:
- try:
- self._prepare_proxy(conn)
- except (BaseSSLError, OSError, SocketTimeout) as e:
- self._raise_timeout(
- err=e, url=self.proxy.url, timeout_value=conn.timeout
- )
- raise
-
- # If we're going to release the connection in ``finally:``, then
- # the response doesn't need to know about the connection. Otherwise
- # it will also try to release it and we'll have a double-release
- # mess.
- response_conn = conn if not release_conn else None
-
- # Make the request on the HTTPConnection object
- response = self._make_request(
- conn,
- method,
- url,
- timeout=timeout_obj,
- body=body,
- headers=headers,
- chunked=chunked,
- retries=retries,
- response_conn=response_conn,
- preload_content=preload_content,
- decode_content=decode_content,
- **response_kw,
- )
-
- # Everything went great!
- clean_exit = True
-
- except EmptyPoolError:
- # Didn't get a connection from the pool, no need to clean up
- clean_exit = True
- release_this_conn = False
- raise
-
- except (
- TimeoutError,
- HTTPException,
- OSError,
- ProtocolError,
- BaseSSLError,
- SSLError,
- CertificateError,
- ProxyError,
- ) as e:
- # Discard the connection for these exceptions. It will be
- # replaced during the next _get_conn() call.
- clean_exit = False
- new_e: Exception = e
- if isinstance(e, (BaseSSLError, CertificateError)):
- new_e = SSLError(e)
- if isinstance(
- new_e,
- (
- OSError,
- NewConnectionError,
- TimeoutError,
- SSLError,
- HTTPException,
- ),
- ) and (conn and conn.proxy and not conn.has_connected_to_proxy):
- new_e = _wrap_proxy_error(new_e, conn.proxy.scheme)
- elif isinstance(new_e, (OSError, HTTPException)):
- new_e = ProtocolError("Connection aborted.", new_e)
-
- retries = retries.increment(
- method, url, error=new_e, _pool=self, _stacktrace=sys.exc_info()[2]
- )
- retries.sleep()
-
- # Keep track of the error for the retry warning.
- err = e
-
- finally:
- if not clean_exit:
- # We hit some kind of exception, handled or otherwise. We need
- # to throw the connection away unless explicitly told not to.
- # Close the connection, set the variable to None, and make sure
- # we put the None back in the pool to avoid leaking it.
- if conn:
- conn.close()
- conn = None
- release_this_conn = True
-
- if release_this_conn:
- # Put the connection back to be reused. If the connection is
- # expired then it will be None, which will get replaced with a
- # fresh connection during _get_conn.
- self._put_conn(conn)
-
- if not conn:
- # Try again
- log.warning(
- "Retrying (%r) after connection broken by '%r': %s", retries, err, url
- )
- return self.urlopen(
- method,
- url,
- body,
- headers,
- retries,
- redirect,
- assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- preload_content=preload_content,
- decode_content=decode_content,
- **response_kw,
- )
-
- # Handle redirect?
- redirect_location = redirect and response.get_redirect_location()
- if redirect_location:
- if response.status == 303:
- # Change the method according to RFC 9110, Section 15.4.4.
- method = "GET"
- # And lose the body not to transfer anything sensitive.
- body = None
- headers = HTTPHeaderDict(headers)._prepare_for_method_change()
-
- try:
- retries = retries.increment(method, url, response=response, _pool=self)
- except MaxRetryError:
- if retries.raise_on_redirect:
- response.drain_conn()
- raise
- return response
-
- response.drain_conn()
- retries.sleep_for_retry(response)
- log.debug("Redirecting %s -> %s", url, redirect_location)
- return self.urlopen(
- method,
- redirect_location,
- body,
- headers,
- retries=retries,
- redirect=redirect,
- assert_same_host=assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- preload_content=preload_content,
- decode_content=decode_content,
- **response_kw,
- )
-
- # Check if we should retry the HTTP response.
- has_retry_after = bool(response.headers.get("Retry-After"))
- if retries.is_retry(method, response.status, has_retry_after):
- try:
- retries = retries.increment(method, url, response=response, _pool=self)
- except MaxRetryError:
- if retries.raise_on_status:
- response.drain_conn()
- raise
- return response
-
- response.drain_conn()
- retries.sleep(response)
- log.debug("Retry: %s", url)
- return self.urlopen(
- method,
- url,
- body,
- headers,
- retries=retries,
- redirect=redirect,
- assert_same_host=assert_same_host,
- timeout=timeout,
- pool_timeout=pool_timeout,
- release_conn=release_conn,
- chunked=chunked,
- body_pos=body_pos,
- preload_content=preload_content,
- decode_content=decode_content,
- **response_kw,
- )
-
- return response
-
-
-class HTTPSConnectionPool(HTTPConnectionPool):
- """
- Same as :class:`.HTTPConnectionPool`, but HTTPS.
-
- :class:`.HTTPSConnection` uses one of ``assert_fingerprint``,
- ``assert_hostname`` and ``host`` in this order to verify connections.
- If ``assert_hostname`` is False, no verification is done.
-
- The ``key_file``, ``cert_file``, ``cert_reqs``, ``ca_certs``,
- ``ca_cert_dir``, ``ssl_version``, ``key_password`` are only used if :mod:`ssl`
- is available and are fed into :meth:`urllib3.util.ssl_wrap_socket` to upgrade
- the connection socket into an SSL socket.
- """
-
- scheme = "https"
- ConnectionCls: type[BaseHTTPSConnection] = HTTPSConnection
-
- def __init__(
- self,
- host: str,
- port: int | None = None,
- timeout: _TYPE_TIMEOUT | None = _DEFAULT_TIMEOUT,
- maxsize: int = 1,
- block: bool = False,
- headers: typing.Mapping[str, str] | None = None,
- retries: Retry | bool | int | None = None,
- _proxy: Url | None = None,
- _proxy_headers: typing.Mapping[str, str] | None = None,
- key_file: str | None = None,
- cert_file: str | None = None,
- cert_reqs: int | str | None = None,
- key_password: str | None = None,
- ca_certs: str | None = None,
- ssl_version: int | str | None = None,
- ssl_minimum_version: ssl.TLSVersion | None = None,
- ssl_maximum_version: ssl.TLSVersion | None = None,
- assert_hostname: str | typing.Literal[False] | None = None,
- assert_fingerprint: str | None = None,
- ca_cert_dir: str | None = None,
- **conn_kw: typing.Any,
- ) -> None:
- super().__init__(
- host,
- port,
- timeout,
- maxsize,
- block,
- headers,
- retries,
- _proxy,
- _proxy_headers,
- **conn_kw,
- )
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.cert_reqs = cert_reqs
- self.key_password = key_password
- self.ca_certs = ca_certs
- self.ca_cert_dir = ca_cert_dir
- self.ssl_version = ssl_version
- self.ssl_minimum_version = ssl_minimum_version
- self.ssl_maximum_version = ssl_maximum_version
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
-
- def _prepare_proxy(self, conn: HTTPSConnection) -> None: # type: ignore[override]
- """Establishes a tunnel connection through HTTP CONNECT."""
- if self.proxy and self.proxy.scheme == "https":
- tunnel_scheme = "https"
- else:
- tunnel_scheme = "http"
-
- conn.set_tunnel(
- scheme=tunnel_scheme,
- host=self._tunnel_host,
- port=self.port,
- headers=self.proxy_headers,
- )
- conn.connect()
-
- def _new_conn(self) -> BaseHTTPSConnection:
- """
- Return a fresh :class:`urllib3.connection.HTTPConnection`.
- """
- self.num_connections += 1
- log.debug(
- "Starting new HTTPS connection (%d): %s:%s",
- self.num_connections,
- self.host,
- self.port or "443",
- )
-
- if not self.ConnectionCls or self.ConnectionCls is DummyConnection: # type: ignore[comparison-overlap]
- raise ImportError(
- "Can't connect to HTTPS URL because the SSL module is not available."
- )
-
- actual_host: str = self.host
- actual_port = self.port
- if self.proxy is not None and self.proxy.host is not None:
- actual_host = self.proxy.host
- actual_port = self.proxy.port
-
- return self.ConnectionCls(
- host=actual_host,
- port=actual_port,
- timeout=self.timeout.connect_timeout,
- cert_file=self.cert_file,
- key_file=self.key_file,
- key_password=self.key_password,
- cert_reqs=self.cert_reqs,
- ca_certs=self.ca_certs,
- ca_cert_dir=self.ca_cert_dir,
- assert_hostname=self.assert_hostname,
- assert_fingerprint=self.assert_fingerprint,
- ssl_version=self.ssl_version,
- ssl_minimum_version=self.ssl_minimum_version,
- ssl_maximum_version=self.ssl_maximum_version,
- **self.conn_kw,
- )
-
- def _validate_conn(self, conn: BaseHTTPConnection) -> None:
- """
- Called right before a request is made, after the socket is created.
- """
- super()._validate_conn(conn)
-
- # Force connect early to allow us to validate the connection.
- if conn.is_closed:
- conn.connect()
-
- # TODO revise this, see https://github.com/urllib3/urllib3/issues/2791
- if not conn.is_verified and not conn.proxy_is_verified:
- warnings.warn(
- (
- f"Unverified HTTPS request is being made to host '{conn.host}'. "
- "Adding certificate verification is strongly advised. See: "
- "https://urllib3.readthedocs.io/en/latest/advanced-usage.html"
- "#tls-warnings"
- ),
- InsecureRequestWarning,
- )
-
-
-def connection_from_url(url: str, **kw: typing.Any) -> HTTPConnectionPool:
- """
- Given a url, return an :class:`.ConnectionPool` instance of its host.
-
- This is a shortcut for not having to parse out the scheme, host, and port
- of the url before creating an :class:`.ConnectionPool` instance.
-
- :param url:
- Absolute URL string that must include the scheme. Port is optional.
-
- :param \\**kw:
- Passes additional parameters to the constructor of the appropriate
- :class:`.ConnectionPool`. Useful for specifying things like
- timeout, maxsize, headers, etc.
-
- Example::
-
- >>> conn = connection_from_url('http://google.com/')
- >>> r = conn.request('GET', '/')
- """
- scheme, _, host, port, *_ = parse_url(url)
- scheme = scheme or "http"
- port = port or port_by_scheme.get(scheme, 80)
- if scheme == "https":
- return HTTPSConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
- else:
- return HTTPConnectionPool(host, port=port, **kw) # type: ignore[arg-type]
-
-
-@typing.overload
-def _normalize_host(host: None, scheme: str | None) -> None:
- ...
-
-
-@typing.overload
-def _normalize_host(host: str, scheme: str | None) -> str:
- ...
-
-
-def _normalize_host(host: str | None, scheme: str | None) -> str | None:
- """
- Normalize hosts for comparisons and use with sockets.
- """
-
- host = normalize_host(host, scheme)
-
- # httplib doesn't like it when we include brackets in IPv6 addresses
- # Specifically, if we include brackets but also pass the port then
- # httplib crazily doubles up the square brackets on the Host header.
- # Instead, we need to make sure we never pass ``None`` as the port.
- # However, for backward compatibility reasons we can't actually
- # *assert* that. See http://bugs.python.org/issue28539
- if host and host.startswith("[") and host.endswith("]"):
- host = host[1:-1]
- return host
-
-
-def _url_from_pool(
- pool: HTTPConnectionPool | HTTPSConnectionPool, path: str | None = None
-) -> str:
- """Returns the URL from a given connection pool. This is mainly used for testing and logging."""
- return Url(scheme=pool.scheme, host=pool.host, port=pool.port, path=path).url
-
-
-def _close_pool_connections(pool: queue.LifoQueue[typing.Any]) -> None:
- """Drains a queue of connections and closes each one."""
- try:
- while True:
- conn = pool.get(block=False)
- if conn:
- conn.close()
- except queue.Empty:
- pass # Done.
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/__init__.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 3ba5e1c..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc
deleted file mode 100644
index ef50dd8..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/pyopenssl.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc
deleted file mode 100644
index e512f7f..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/__pycache__/socks.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__init__.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__init__.py
deleted file mode 100644
index 8a3c5be..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-from __future__ import annotations
-
-import urllib3.connection
-
-from ...connectionpool import HTTPConnectionPool, HTTPSConnectionPool
-from .connection import EmscriptenHTTPConnection, EmscriptenHTTPSConnection
-
-
-def inject_into_urllib3() -> None:
- # override connection classes to use emscripten specific classes
- # n.b. mypy complains about the overriding of classes below
- # if it isn't ignored
- HTTPConnectionPool.ConnectionCls = EmscriptenHTTPConnection
- HTTPSConnectionPool.ConnectionCls = EmscriptenHTTPSConnection
- urllib3.connection.HTTPConnection = EmscriptenHTTPConnection # type: ignore[misc,assignment]
- urllib3.connection.HTTPSConnection = EmscriptenHTTPSConnection # type: ignore[misc,assignment]
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index c0a9611..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc
deleted file mode 100644
index ec64a21..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/connection.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc
deleted file mode 100644
index 25c112f..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/fetch.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc
deleted file mode 100644
index 1860a9d..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/request.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc
deleted file mode 100644
index de64c88..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/__pycache__/response.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/connection.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/connection.py
deleted file mode 100644
index 2ceb457..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/connection.py
+++ /dev/null
@@ -1,254 +0,0 @@
-from __future__ import annotations
-
-import os
-import typing
-
-# use http.client.HTTPException for consistency with non-emscripten
-from http.client import HTTPException as HTTPException # noqa: F401
-from http.client import ResponseNotReady
-
-from ..._base_connection import _TYPE_BODY
-from ...connection import HTTPConnection, ProxyConfig, port_by_scheme
-from ...exceptions import TimeoutError
-from ...response import BaseHTTPResponse
-from ...util.connection import _TYPE_SOCKET_OPTIONS
-from ...util.timeout import _DEFAULT_TIMEOUT, _TYPE_TIMEOUT
-from ...util.url import Url
-from .fetch import _RequestError, _TimeoutError, send_request, send_streaming_request
-from .request import EmscriptenRequest
-from .response import EmscriptenHttpResponseWrapper, EmscriptenResponse
-
-if typing.TYPE_CHECKING:
- from ..._base_connection import BaseHTTPConnection, BaseHTTPSConnection
-
-
-class EmscriptenHTTPConnection:
- default_port: typing.ClassVar[int] = port_by_scheme["http"]
- default_socket_options: typing.ClassVar[_TYPE_SOCKET_OPTIONS]
-
- timeout: None | (float)
-
- host: str
- port: int
- blocksize: int
- source_address: tuple[str, int] | None
- socket_options: _TYPE_SOCKET_OPTIONS | None
-
- proxy: Url | None
- proxy_config: ProxyConfig | None
-
- is_verified: bool = False
- proxy_is_verified: bool | None = None
-
- _response: EmscriptenResponse | None
-
- def __init__(
- self,
- host: str,
- port: int = 0,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 8192,
- socket_options: _TYPE_SOCKET_OPTIONS | None = None,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- ) -> None:
- self.host = host
- self.port = port
- self.timeout = timeout if isinstance(timeout, float) else 0.0
- self.scheme = "http"
- self._closed = True
- self._response = None
- # ignore these things because we don't
- # have control over that stuff
- self.proxy = None
- self.proxy_config = None
- self.blocksize = blocksize
- self.source_address = None
- self.socket_options = None
- self.is_verified = False
-
- def set_tunnel(
- self,
- host: str,
- port: int | None = 0,
- headers: typing.Mapping[str, str] | None = None,
- scheme: str = "http",
- ) -> None:
- pass
-
- def connect(self) -> None:
- pass
-
- def request(
- self,
- method: str,
- url: str,
- body: _TYPE_BODY | None = None,
- headers: typing.Mapping[str, str] | None = None,
- # We know *at least* botocore is depending on the order of the
- # first 3 parameters so to be safe we only mark the later ones
- # as keyword-only to ensure we have space to extend.
- *,
- chunked: bool = False,
- preload_content: bool = True,
- decode_content: bool = True,
- enforce_content_length: bool = True,
- ) -> None:
- self._closed = False
- if url.startswith("/"):
- # no scheme / host / port included, make a full url
- url = f"{self.scheme}://{self.host}:{self.port}" + url
- request = EmscriptenRequest(
- url=url,
- method=method,
- timeout=self.timeout if self.timeout else 0,
- decode_content=decode_content,
- )
- request.set_body(body)
- if headers:
- for k, v in headers.items():
- request.set_header(k, v)
- self._response = None
- try:
- if not preload_content:
- self._response = send_streaming_request(request)
- if self._response is None:
- self._response = send_request(request)
- except _TimeoutError as e:
- raise TimeoutError(e.message) from e
- except _RequestError as e:
- raise HTTPException(e.message) from e
-
- def getresponse(self) -> BaseHTTPResponse:
- if self._response is not None:
- return EmscriptenHttpResponseWrapper(
- internal_response=self._response,
- url=self._response.request.url,
- connection=self,
- )
- else:
- raise ResponseNotReady()
-
- def close(self) -> None:
- self._closed = True
- self._response = None
-
- @property
- def is_closed(self) -> bool:
- """Whether the connection either is brand new or has been previously closed.
- If this property is True then both ``is_connected`` and ``has_connected_to_proxy``
- properties must be False.
- """
- return self._closed
-
- @property
- def is_connected(self) -> bool:
- """Whether the connection is actively connected to any origin (proxy or target)"""
- return True
-
- @property
- def has_connected_to_proxy(self) -> bool:
- """Whether the connection has successfully connected to its proxy.
- This returns False if no proxy is in use. Used to determine whether
- errors are coming from the proxy layer or from tunnelling to the target origin.
- """
- return False
-
-
-class EmscriptenHTTPSConnection(EmscriptenHTTPConnection):
- default_port = port_by_scheme["https"]
- # all this is basically ignored, as browser handles https
- cert_reqs: int | str | None = None
- ca_certs: str | None = None
- ca_cert_dir: str | None = None
- ca_cert_data: None | str | bytes = None
- cert_file: str | None
- key_file: str | None
- key_password: str | None
- ssl_context: typing.Any | None
- ssl_version: int | str | None = None
- ssl_minimum_version: int | None = None
- ssl_maximum_version: int | None = None
- assert_hostname: None | str | typing.Literal[False]
- assert_fingerprint: str | None = None
-
- def __init__(
- self,
- host: str,
- port: int = 0,
- *,
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- blocksize: int = 16384,
- socket_options: None
- | _TYPE_SOCKET_OPTIONS = HTTPConnection.default_socket_options,
- proxy: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- cert_reqs: int | str | None = None,
- assert_hostname: None | str | typing.Literal[False] = None,
- assert_fingerprint: str | None = None,
- server_hostname: str | None = None,
- ssl_context: typing.Any | None = None,
- ca_certs: str | None = None,
- ca_cert_dir: str | None = None,
- ca_cert_data: None | str | bytes = None,
- ssl_minimum_version: int | None = None,
- ssl_maximum_version: int | None = None,
- ssl_version: int | str | None = None, # Deprecated
- cert_file: str | None = None,
- key_file: str | None = None,
- key_password: str | None = None,
- ) -> None:
- super().__init__(
- host,
- port=port,
- timeout=timeout,
- source_address=source_address,
- blocksize=blocksize,
- socket_options=socket_options,
- proxy=proxy,
- proxy_config=proxy_config,
- )
- self.scheme = "https"
-
- self.key_file = key_file
- self.cert_file = cert_file
- self.key_password = key_password
- self.ssl_context = ssl_context
- self.server_hostname = server_hostname
- self.assert_hostname = assert_hostname
- self.assert_fingerprint = assert_fingerprint
- self.ssl_version = ssl_version
- self.ssl_minimum_version = ssl_minimum_version
- self.ssl_maximum_version = ssl_maximum_version
- self.ca_certs = ca_certs and os.path.expanduser(ca_certs)
- self.ca_cert_dir = ca_cert_dir and os.path.expanduser(ca_cert_dir)
- self.ca_cert_data = ca_cert_data
-
- self.cert_reqs = None
-
- # The browser will automatically verify all requests.
- # We have no control over that setting.
- self.is_verified = True
-
- def set_cert(
- self,
- key_file: str | None = None,
- cert_file: str | None = None,
- cert_reqs: int | str | None = None,
- key_password: str | None = None,
- ca_certs: str | None = None,
- assert_hostname: None | str | typing.Literal[False] = None,
- assert_fingerprint: str | None = None,
- ca_cert_dir: str | None = None,
- ca_cert_data: None | str | bytes = None,
- ) -> None:
- pass
-
-
-# verify that this class implements BaseHTTP(s) connection correctly
-if typing.TYPE_CHECKING:
- _supports_http_protocol: BaseHTTPConnection = EmscriptenHTTPConnection("", 0)
- _supports_https_protocol: BaseHTTPSConnection = EmscriptenHTTPSConnection("", 0)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js
deleted file mode 100644
index 243b862..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/emscripten_fetch_worker.js
+++ /dev/null
@@ -1,110 +0,0 @@
-let Status = {
- SUCCESS_HEADER: -1,
- SUCCESS_EOF: -2,
- ERROR_TIMEOUT: -3,
- ERROR_EXCEPTION: -4,
-};
-
-let connections = {};
-let nextConnectionID = 1;
-const encoder = new TextEncoder();
-
-self.addEventListener("message", async function (event) {
- if (event.data.close) {
- let connectionID = event.data.close;
- delete connections[connectionID];
- return;
- } else if (event.data.getMore) {
- let connectionID = event.data.getMore;
- let { curOffset, value, reader, intBuffer, byteBuffer } =
- connections[connectionID];
- // if we still have some in buffer, then just send it back straight away
- if (!value || curOffset >= value.length) {
- // read another buffer if required
- try {
- let readResponse = await reader.read();
-
- if (readResponse.done) {
- // read everything - clear connection and return
- delete connections[connectionID];
- Atomics.store(intBuffer, 0, Status.SUCCESS_EOF);
- Atomics.notify(intBuffer, 0);
- // finished reading successfully
- // return from event handler
- return;
- }
- curOffset = 0;
- connections[connectionID].value = readResponse.value;
- value = readResponse.value;
- } catch (error) {
- console.log("Request exception:", error);
- let errorBytes = encoder.encode(error.message);
- let written = errorBytes.length;
- byteBuffer.set(errorBytes);
- intBuffer[1] = written;
- Atomics.store(intBuffer, 0, Status.ERROR_EXCEPTION);
- Atomics.notify(intBuffer, 0);
- }
- }
-
- // send as much buffer as we can
- let curLen = value.length - curOffset;
- if (curLen > byteBuffer.length) {
- curLen = byteBuffer.length;
- }
- byteBuffer.set(value.subarray(curOffset, curOffset + curLen), 0);
-
- Atomics.store(intBuffer, 0, curLen); // store current length in bytes
- Atomics.notify(intBuffer, 0);
- curOffset += curLen;
- connections[connectionID].curOffset = curOffset;
-
- return;
- } else {
- // start fetch
- let connectionID = nextConnectionID;
- nextConnectionID += 1;
- const intBuffer = new Int32Array(event.data.buffer);
- const byteBuffer = new Uint8Array(event.data.buffer, 8);
- try {
- const response = await fetch(event.data.url, event.data.fetchParams);
- // return the headers first via textencoder
- var headers = [];
- for (const pair of response.headers.entries()) {
- headers.push([pair[0], pair[1]]);
- }
- let headerObj = {
- headers: headers,
- status: response.status,
- connectionID,
- };
- const headerText = JSON.stringify(headerObj);
- let headerBytes = encoder.encode(headerText);
- let written = headerBytes.length;
- byteBuffer.set(headerBytes);
- intBuffer[1] = written;
- // make a connection
- connections[connectionID] = {
- reader: response.body.getReader(),
- intBuffer: intBuffer,
- byteBuffer: byteBuffer,
- value: undefined,
- curOffset: 0,
- };
- // set header ready
- Atomics.store(intBuffer, 0, Status.SUCCESS_HEADER);
- Atomics.notify(intBuffer, 0);
- // all fetching after this goes through a new postmessage call with getMore
- // this allows for parallel requests
- } catch (error) {
- console.log("Request exception:", error);
- let errorBytes = encoder.encode(error.message);
- let written = errorBytes.length;
- byteBuffer.set(errorBytes);
- intBuffer[1] = written;
- Atomics.store(intBuffer, 0, Status.ERROR_EXCEPTION);
- Atomics.notify(intBuffer, 0);
- }
- }
-});
-self.postMessage({ inited: true });
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/fetch.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/fetch.py
deleted file mode 100644
index 8d197ea..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/fetch.py
+++ /dev/null
@@ -1,418 +0,0 @@
-"""
-Support for streaming http requests in emscripten.
-
-A few caveats -
-
-Firstly, you can't do streaming http in the main UI thread, because atomics.wait isn't allowed.
-Streaming only works if you're running pyodide in a web worker.
-
-Secondly, this uses an extra web worker and SharedArrayBuffer to do the asynchronous fetch
-operation, so it requires that you have crossOriginIsolation enabled, by serving over https
-(or from localhost) with the two headers below set:
-
- Cross-Origin-Opener-Policy: same-origin
- Cross-Origin-Embedder-Policy: require-corp
-
-You can tell if cross origin isolation is successfully enabled by looking at the global crossOriginIsolated variable in
-javascript console. If it isn't, streaming requests will fallback to XMLHttpRequest, i.e. getting the whole
-request into a buffer and then returning it. it shows a warning in the javascript console in this case.
-
-Finally, the webworker which does the streaming fetch is created on initial import, but will only be started once
-control is returned to javascript. Call `await wait_for_streaming_ready()` to wait for streaming fetch.
-
-NB: in this code, there are a lot of javascript objects. They are named js_*
-to make it clear what type of object they are.
-"""
-from __future__ import annotations
-
-import io
-import json
-from email.parser import Parser
-from importlib.resources import files
-from typing import TYPE_CHECKING, Any
-
-import js # type: ignore[import-not-found]
-from pyodide.ffi import ( # type: ignore[import-not-found]
- JsArray,
- JsException,
- JsProxy,
- to_js,
-)
-
-if TYPE_CHECKING:
- from typing_extensions import Buffer
-
-from .request import EmscriptenRequest
-from .response import EmscriptenResponse
-
-"""
-There are some headers that trigger unintended CORS preflight requests.
-See also https://github.com/koenvo/pyodide-http/issues/22
-"""
-HEADERS_TO_IGNORE = ("user-agent",)
-
-SUCCESS_HEADER = -1
-SUCCESS_EOF = -2
-ERROR_TIMEOUT = -3
-ERROR_EXCEPTION = -4
-
-_STREAMING_WORKER_CODE = (
- files(__package__)
- .joinpath("emscripten_fetch_worker.js")
- .read_text(encoding="utf-8")
-)
-
-
-class _RequestError(Exception):
- def __init__(
- self,
- message: str | None = None,
- *,
- request: EmscriptenRequest | None = None,
- response: EmscriptenResponse | None = None,
- ):
- self.request = request
- self.response = response
- self.message = message
- super().__init__(self.message)
-
-
-class _StreamingError(_RequestError):
- pass
-
-
-class _TimeoutError(_RequestError):
- pass
-
-
-def _obj_from_dict(dict_val: dict[str, Any]) -> JsProxy:
- return to_js(dict_val, dict_converter=js.Object.fromEntries)
-
-
-class _ReadStream(io.RawIOBase):
- def __init__(
- self,
- int_buffer: JsArray,
- byte_buffer: JsArray,
- timeout: float,
- worker: JsProxy,
- connection_id: int,
- request: EmscriptenRequest,
- ):
- self.int_buffer = int_buffer
- self.byte_buffer = byte_buffer
- self.read_pos = 0
- self.read_len = 0
- self.connection_id = connection_id
- self.worker = worker
- self.timeout = int(1000 * timeout) if timeout > 0 else None
- self.is_live = True
- self._is_closed = False
- self.request: EmscriptenRequest | None = request
-
- def __del__(self) -> None:
- self.close()
-
- # this is compatible with _base_connection
- def is_closed(self) -> bool:
- return self._is_closed
-
- # for compatibility with RawIOBase
- @property
- def closed(self) -> bool:
- return self.is_closed()
-
- def close(self) -> None:
- if not self.is_closed():
- self.read_len = 0
- self.read_pos = 0
- self.int_buffer = None
- self.byte_buffer = None
- self._is_closed = True
- self.request = None
- if self.is_live:
- self.worker.postMessage(_obj_from_dict({"close": self.connection_id}))
- self.is_live = False
- super().close()
-
- def readable(self) -> bool:
- return True
-
- def writable(self) -> bool:
- return False
-
- def seekable(self) -> bool:
- return False
-
- def readinto(self, byte_obj: Buffer) -> int:
- if not self.int_buffer:
- raise _StreamingError(
- "No buffer for stream in _ReadStream.readinto",
- request=self.request,
- response=None,
- )
- if self.read_len == 0:
- # wait for the worker to send something
- js.Atomics.store(self.int_buffer, 0, ERROR_TIMEOUT)
- self.worker.postMessage(_obj_from_dict({"getMore": self.connection_id}))
- if (
- js.Atomics.wait(self.int_buffer, 0, ERROR_TIMEOUT, self.timeout)
- == "timed-out"
- ):
- raise _TimeoutError
- data_len = self.int_buffer[0]
- if data_len > 0:
- self.read_len = data_len
- self.read_pos = 0
- elif data_len == ERROR_EXCEPTION:
- string_len = self.int_buffer[1]
- # decode the error string
- js_decoder = js.TextDecoder.new()
- json_str = js_decoder.decode(self.byte_buffer.slice(0, string_len))
- raise _StreamingError(
- f"Exception thrown in fetch: {json_str}",
- request=self.request,
- response=None,
- )
- else:
- # EOF, free the buffers and return zero
- # and free the request
- self.is_live = False
- self.close()
- return 0
- # copy from int32array to python bytes
- ret_length = min(self.read_len, len(memoryview(byte_obj)))
- subarray = self.byte_buffer.subarray(
- self.read_pos, self.read_pos + ret_length
- ).to_py()
- memoryview(byte_obj)[0:ret_length] = subarray
- self.read_len -= ret_length
- self.read_pos += ret_length
- return ret_length
-
-
-class _StreamingFetcher:
- def __init__(self) -> None:
- # make web-worker and data buffer on startup
- self.streaming_ready = False
-
- js_data_blob = js.Blob.new(
- [_STREAMING_WORKER_CODE], _obj_from_dict({"type": "application/javascript"})
- )
-
- def promise_resolver(js_resolve_fn: JsProxy, js_reject_fn: JsProxy) -> None:
- def onMsg(e: JsProxy) -> None:
- self.streaming_ready = True
- js_resolve_fn(e)
-
- def onErr(e: JsProxy) -> None:
- js_reject_fn(e) # Defensive: never happens in ci
-
- self.js_worker.onmessage = onMsg
- self.js_worker.onerror = onErr
-
- js_data_url = js.URL.createObjectURL(js_data_blob)
- self.js_worker = js.globalThis.Worker.new(js_data_url)
- self.js_worker_ready_promise = js.globalThis.Promise.new(promise_resolver)
-
- def send(self, request: EmscriptenRequest) -> EmscriptenResponse:
- headers = {
- k: v for k, v in request.headers.items() if k not in HEADERS_TO_IGNORE
- }
-
- body = request.body
- fetch_data = {"headers": headers, "body": to_js(body), "method": request.method}
- # start the request off in the worker
- timeout = int(1000 * request.timeout) if request.timeout > 0 else None
- js_shared_buffer = js.SharedArrayBuffer.new(1048576)
- js_int_buffer = js.Int32Array.new(js_shared_buffer)
- js_byte_buffer = js.Uint8Array.new(js_shared_buffer, 8)
-
- js.Atomics.store(js_int_buffer, 0, ERROR_TIMEOUT)
- js.Atomics.notify(js_int_buffer, 0)
- js_absolute_url = js.URL.new(request.url, js.location).href
- self.js_worker.postMessage(
- _obj_from_dict(
- {
- "buffer": js_shared_buffer,
- "url": js_absolute_url,
- "fetchParams": fetch_data,
- }
- )
- )
- # wait for the worker to send something
- js.Atomics.wait(js_int_buffer, 0, ERROR_TIMEOUT, timeout)
- if js_int_buffer[0] == ERROR_TIMEOUT:
- raise _TimeoutError(
- "Timeout connecting to streaming request",
- request=request,
- response=None,
- )
- elif js_int_buffer[0] == SUCCESS_HEADER:
- # got response
- # header length is in second int of intBuffer
- string_len = js_int_buffer[1]
- # decode the rest to a JSON string
- js_decoder = js.TextDecoder.new()
- # this does a copy (the slice) because decode can't work on shared array
- # for some silly reason
- json_str = js_decoder.decode(js_byte_buffer.slice(0, string_len))
- # get it as an object
- response_obj = json.loads(json_str)
- return EmscriptenResponse(
- request=request,
- status_code=response_obj["status"],
- headers=response_obj["headers"],
- body=_ReadStream(
- js_int_buffer,
- js_byte_buffer,
- request.timeout,
- self.js_worker,
- response_obj["connectionID"],
- request,
- ),
- )
- elif js_int_buffer[0] == ERROR_EXCEPTION:
- string_len = js_int_buffer[1]
- # decode the error string
- js_decoder = js.TextDecoder.new()
- json_str = js_decoder.decode(js_byte_buffer.slice(0, string_len))
- raise _StreamingError(
- f"Exception thrown in fetch: {json_str}", request=request, response=None
- )
- else:
- raise _StreamingError(
- f"Unknown status from worker in fetch: {js_int_buffer[0]}",
- request=request,
- response=None,
- )
-
-
-# check if we are in a worker or not
-def is_in_browser_main_thread() -> bool:
- return hasattr(js, "window") and hasattr(js, "self") and js.self == js.window
-
-
-def is_cross_origin_isolated() -> bool:
- return hasattr(js, "crossOriginIsolated") and js.crossOriginIsolated
-
-
-def is_in_node() -> bool:
- return (
- hasattr(js, "process")
- and hasattr(js.process, "release")
- and hasattr(js.process.release, "name")
- and js.process.release.name == "node"
- )
-
-
-def is_worker_available() -> bool:
- return hasattr(js, "Worker") and hasattr(js, "Blob")
-
-
-_fetcher: _StreamingFetcher | None = None
-
-if is_worker_available() and (
- (is_cross_origin_isolated() and not is_in_browser_main_thread())
- and (not is_in_node())
-):
- _fetcher = _StreamingFetcher()
-else:
- _fetcher = None
-
-
-def send_streaming_request(request: EmscriptenRequest) -> EmscriptenResponse | None:
- if _fetcher and streaming_ready():
- return _fetcher.send(request)
- else:
- _show_streaming_warning()
- return None
-
-
-_SHOWN_TIMEOUT_WARNING = False
-
-
-def _show_timeout_warning() -> None:
- global _SHOWN_TIMEOUT_WARNING
- if not _SHOWN_TIMEOUT_WARNING:
- _SHOWN_TIMEOUT_WARNING = True
- message = "Warning: Timeout is not available on main browser thread"
- js.console.warn(message)
-
-
-_SHOWN_STREAMING_WARNING = False
-
-
-def _show_streaming_warning() -> None:
- global _SHOWN_STREAMING_WARNING
- if not _SHOWN_STREAMING_WARNING:
- _SHOWN_STREAMING_WARNING = True
- message = "Can't stream HTTP requests because: \n"
- if not is_cross_origin_isolated():
- message += " Page is not cross-origin isolated\n"
- if is_in_browser_main_thread():
- message += " Python is running in main browser thread\n"
- if not is_worker_available():
- message += " Worker or Blob classes are not available in this environment." # Defensive: this is always False in browsers that we test in
- if streaming_ready() is False:
- message += """ Streaming fetch worker isn't ready. If you want to be sure that streaming fetch
-is working, you need to call: 'await urllib3.contrib.emscripten.fetch.wait_for_streaming_ready()`"""
- from js import console
-
- console.warn(message)
-
-
-def send_request(request: EmscriptenRequest) -> EmscriptenResponse:
- try:
- js_xhr = js.XMLHttpRequest.new()
-
- if not is_in_browser_main_thread():
- js_xhr.responseType = "arraybuffer"
- if request.timeout:
- js_xhr.timeout = int(request.timeout * 1000)
- else:
- js_xhr.overrideMimeType("text/plain; charset=ISO-8859-15")
- if request.timeout:
- # timeout isn't available on the main thread - show a warning in console
- # if it is set
- _show_timeout_warning()
-
- js_xhr.open(request.method, request.url, False)
- for name, value in request.headers.items():
- if name.lower() not in HEADERS_TO_IGNORE:
- js_xhr.setRequestHeader(name, value)
-
- js_xhr.send(to_js(request.body))
-
- headers = dict(Parser().parsestr(js_xhr.getAllResponseHeaders()))
-
- if not is_in_browser_main_thread():
- body = js_xhr.response.to_py().tobytes()
- else:
- body = js_xhr.response.encode("ISO-8859-15")
- return EmscriptenResponse(
- status_code=js_xhr.status, headers=headers, body=body, request=request
- )
- except JsException as err:
- if err.name == "TimeoutError":
- raise _TimeoutError(err.message, request=request)
- elif err.name == "NetworkError":
- raise _RequestError(err.message, request=request)
- else:
- # general http error
- raise _RequestError(err.message, request=request)
-
-
-def streaming_ready() -> bool | None:
- if _fetcher:
- return _fetcher.streaming_ready
- else:
- return None # no fetcher, return None to signify that
-
-
-async def wait_for_streaming_ready() -> bool:
- if _fetcher:
- await _fetcher.js_worker_ready_promise
- return True
- else:
- return False
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/request.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/request.py
deleted file mode 100644
index e692e69..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/request.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from __future__ import annotations
-
-from dataclasses import dataclass, field
-
-from ..._base_connection import _TYPE_BODY
-
-
-@dataclass
-class EmscriptenRequest:
- method: str
- url: str
- params: dict[str, str] | None = None
- body: _TYPE_BODY | None = None
- headers: dict[str, str] = field(default_factory=dict)
- timeout: float = 0
- decode_content: bool = True
-
- def set_header(self, name: str, value: str) -> None:
- self.headers[name.capitalize()] = value
-
- def set_body(self, body: _TYPE_BODY | None) -> None:
- self.body = body
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/response.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/response.py
deleted file mode 100644
index cd3d80e..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/emscripten/response.py
+++ /dev/null
@@ -1,285 +0,0 @@
-from __future__ import annotations
-
-import json as _json
-import logging
-import typing
-from contextlib import contextmanager
-from dataclasses import dataclass
-from http.client import HTTPException as HTTPException
-from io import BytesIO, IOBase
-
-from ...exceptions import InvalidHeader, TimeoutError
-from ...response import BaseHTTPResponse
-from ...util.retry import Retry
-from .request import EmscriptenRequest
-
-if typing.TYPE_CHECKING:
- from ..._base_connection import BaseHTTPConnection, BaseHTTPSConnection
-
-log = logging.getLogger(__name__)
-
-
-@dataclass
-class EmscriptenResponse:
- status_code: int
- headers: dict[str, str]
- body: IOBase | bytes
- request: EmscriptenRequest
-
-
-class EmscriptenHttpResponseWrapper(BaseHTTPResponse):
- def __init__(
- self,
- internal_response: EmscriptenResponse,
- url: str | None = None,
- connection: BaseHTTPConnection | BaseHTTPSConnection | None = None,
- ):
- self._pool = None # set by pool class
- self._body = None
- self._response = internal_response
- self._url = url
- self._connection = connection
- self._closed = False
- super().__init__(
- headers=internal_response.headers,
- status=internal_response.status_code,
- request_url=url,
- version=0,
- version_string="HTTP/?",
- reason="",
- decode_content=True,
- )
- self.length_remaining = self._init_length(self._response.request.method)
- self.length_is_certain = False
-
- @property
- def url(self) -> str | None:
- return self._url
-
- @url.setter
- def url(self, url: str | None) -> None:
- self._url = url
-
- @property
- def connection(self) -> BaseHTTPConnection | BaseHTTPSConnection | None:
- return self._connection
-
- @property
- def retries(self) -> Retry | None:
- return self._retries
-
- @retries.setter
- def retries(self, retries: Retry | None) -> None:
- # Override the request_url if retries has a redirect location.
- self._retries = retries
-
- def stream(
- self, amt: int | None = 2**16, decode_content: bool | None = None
- ) -> typing.Generator[bytes, None, None]:
- """
- A generator wrapper for the read() method. A call will block until
- ``amt`` bytes have been read from the connection or until the
- connection is closed.
-
- :param amt:
- How much of the content to read. The generator will return up to
- much data per iteration, but may return less. This is particularly
- likely when using compressed data. However, the empty string will
- never be returned.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- while True:
- data = self.read(amt=amt, decode_content=decode_content)
-
- if data:
- yield data
- else:
- break
-
- def _init_length(self, request_method: str | None) -> int | None:
- length: int | None
- content_length: str | None = self.headers.get("content-length")
-
- if content_length is not None:
- try:
- # RFC 7230 section 3.3.2 specifies multiple content lengths can
- # be sent in a single Content-Length header
- # (e.g. Content-Length: 42, 42). This line ensures the values
- # are all valid ints and that as long as the `set` length is 1,
- # all values are the same. Otherwise, the header is invalid.
- lengths = {int(val) for val in content_length.split(",")}
- if len(lengths) > 1:
- raise InvalidHeader(
- "Content-Length contained multiple "
- "unmatching values (%s)" % content_length
- )
- length = lengths.pop()
- except ValueError:
- length = None
- else:
- if length < 0:
- length = None
-
- else: # if content_length is None
- length = None
-
- # Check for responses that shouldn't include a body
- if (
- self.status in (204, 304)
- or 100 <= self.status < 200
- or request_method == "HEAD"
- ):
- length = 0
-
- return length
-
- def read(
- self,
- amt: int | None = None,
- decode_content: bool | None = None, # ignored because browser decodes always
- cache_content: bool = False,
- ) -> bytes:
- if (
- self._closed
- or self._response is None
- or (isinstance(self._response.body, IOBase) and self._response.body.closed)
- ):
- return b""
-
- with self._error_catcher():
- # body has been preloaded as a string by XmlHttpRequest
- if not isinstance(self._response.body, IOBase):
- self.length_remaining = len(self._response.body)
- self.length_is_certain = True
- # wrap body in IOStream
- self._response.body = BytesIO(self._response.body)
- if amt is not None and amt >= 0:
- # don't cache partial content
- cache_content = False
- data = self._response.body.read(amt)
- if self.length_remaining is not None:
- self.length_remaining = max(self.length_remaining - len(data), 0)
- if (self.length_is_certain and self.length_remaining == 0) or len(
- data
- ) < amt:
- # definitely finished reading, close response stream
- self._response.body.close()
- return typing.cast(bytes, data)
- else: # read all we can (and cache it)
- data = self._response.body.read()
- if cache_content:
- self._body = data
- if self.length_remaining is not None:
- self.length_remaining = max(self.length_remaining - len(data), 0)
- if len(data) == 0 or (
- self.length_is_certain and self.length_remaining == 0
- ):
- # definitely finished reading, close response stream
- self._response.body.close()
- return typing.cast(bytes, data)
-
- def read_chunked(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- ) -> typing.Generator[bytes, None, None]:
- # chunked is handled by browser
- while True:
- bytes = self.read(amt, decode_content)
- if not bytes:
- break
- yield bytes
-
- def release_conn(self) -> None:
- if not self._pool or not self._connection:
- return None
-
- self._pool._put_conn(self._connection)
- self._connection = None
-
- def drain_conn(self) -> None:
- self.close()
-
- @property
- def data(self) -> bytes:
- if self._body:
- return self._body
- else:
- return self.read(cache_content=True)
-
- def json(self) -> typing.Any:
- """
- Deserializes the body of the HTTP response as a Python object.
-
- The body of the HTTP response must be encoded using UTF-8, as per
- `RFC 8529 Section 8.1 `_.
-
- To use a custom JSON decoder pass the result of :attr:`HTTPResponse.data` to
- your custom decoder instead.
-
- If the body of the HTTP response is not decodable to UTF-8, a
- `UnicodeDecodeError` will be raised. If the body of the HTTP response is not a
- valid JSON document, a `json.JSONDecodeError` will be raised.
-
- Read more :ref:`here `.
-
- :returns: The body of the HTTP response as a Python object.
- """
- data = self.data.decode("utf-8")
- return _json.loads(data)
-
- def close(self) -> None:
- if not self._closed:
- if isinstance(self._response.body, IOBase):
- self._response.body.close()
- if self._connection:
- self._connection.close()
- self._connection = None
- self._closed = True
-
- @contextmanager
- def _error_catcher(self) -> typing.Generator[None, None, None]:
- """
- Catch Emscripten specific exceptions thrown by fetch.py,
- instead re-raising urllib3 variants, so that low-level exceptions
- are not leaked in the high-level api.
-
- On exit, release the connection back to the pool.
- """
- from .fetch import _RequestError, _TimeoutError # avoid circular import
-
- clean_exit = False
-
- try:
- yield
- # If no exception is thrown, we should avoid cleaning up
- # unnecessarily.
- clean_exit = True
- except _TimeoutError as e:
- raise TimeoutError(str(e))
- except _RequestError as e:
- raise HTTPException(str(e))
- finally:
- # If we didn't terminate cleanly, we need to throw away our
- # connection.
- if not clean_exit:
- # The response may not be closed but we're not going to use it
- # anymore so close it now
- if (
- isinstance(self._response.body, IOBase)
- and not self._response.body.closed
- ):
- self._response.body.close()
- # release the connection back to the pool
- self.release_conn()
- else:
- # If we have read everything from the response stream,
- # return the connection back to the pool.
- if (
- isinstance(self._response.body, IOBase)
- and self._response.body.closed
- ):
- self.release_conn()
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/pyopenssl.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/pyopenssl.py
deleted file mode 100644
index b89a6da..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/pyopenssl.py
+++ /dev/null
@@ -1,548 +0,0 @@
-"""
-Module for using pyOpenSSL as a TLS backend. This module was relevant before
-the standard library ``ssl`` module supported SNI, but now that we've dropped
-support for Python 2.7 all relevant Python versions support SNI so
-**this module is no longer recommended**.
-
-This needs the following packages installed:
-
-* `pyOpenSSL`_ (tested with 16.0.0)
-* `cryptography`_ (minimum 1.3.4, from pyopenssl)
-* `idna`_ (minimum 2.0)
-
-However, pyOpenSSL depends on cryptography, so while we use all three directly here we
-end up having relatively few packages required.
-
-You can install them with the following command:
-
-.. code-block:: bash
-
- $ python -m pip install pyopenssl cryptography idna
-
-To activate certificate checking, call
-:func:`~urllib3.contrib.pyopenssl.inject_into_urllib3` from your Python code
-before you begin making HTTP requests. This can be done in a ``sitecustomize``
-module, or at any other time before your application begins using ``urllib3``,
-like this:
-
-.. code-block:: python
-
- try:
- import urllib3.contrib.pyopenssl
- urllib3.contrib.pyopenssl.inject_into_urllib3()
- except ImportError:
- pass
-
-.. _pyopenssl: https://www.pyopenssl.org
-.. _cryptography: https://cryptography.io
-.. _idna: https://github.com/kjd/idna
-"""
-
-from __future__ import annotations
-
-import OpenSSL.SSL # type: ignore[import-untyped]
-from cryptography import x509
-
-try:
- from cryptography.x509 import UnsupportedExtension # type: ignore[attr-defined]
-except ImportError:
- # UnsupportedExtension is gone in cryptography >= 2.1.0
- class UnsupportedExtension(Exception): # type: ignore[no-redef]
- pass
-
-
-import logging
-import ssl
-import typing
-from io import BytesIO
-from socket import socket as socket_cls
-from socket import timeout
-
-from .. import util
-
-if typing.TYPE_CHECKING:
- from OpenSSL.crypto import X509 # type: ignore[import-untyped]
-
-
-__all__ = ["inject_into_urllib3", "extract_from_urllib3"]
-
-# Map from urllib3 to PyOpenSSL compatible parameter-values.
-_openssl_versions: dict[int, int] = {
- util.ssl_.PROTOCOL_TLS: OpenSSL.SSL.SSLv23_METHOD, # type: ignore[attr-defined]
- util.ssl_.PROTOCOL_TLS_CLIENT: OpenSSL.SSL.SSLv23_METHOD, # type: ignore[attr-defined]
- ssl.PROTOCOL_TLSv1: OpenSSL.SSL.TLSv1_METHOD,
-}
-
-if hasattr(ssl, "PROTOCOL_TLSv1_1") and hasattr(OpenSSL.SSL, "TLSv1_1_METHOD"):
- _openssl_versions[ssl.PROTOCOL_TLSv1_1] = OpenSSL.SSL.TLSv1_1_METHOD
-
-if hasattr(ssl, "PROTOCOL_TLSv1_2") and hasattr(OpenSSL.SSL, "TLSv1_2_METHOD"):
- _openssl_versions[ssl.PROTOCOL_TLSv1_2] = OpenSSL.SSL.TLSv1_2_METHOD
-
-
-_stdlib_to_openssl_verify = {
- ssl.CERT_NONE: OpenSSL.SSL.VERIFY_NONE,
- ssl.CERT_OPTIONAL: OpenSSL.SSL.VERIFY_PEER,
- ssl.CERT_REQUIRED: OpenSSL.SSL.VERIFY_PEER
- + OpenSSL.SSL.VERIFY_FAIL_IF_NO_PEER_CERT,
-}
-_openssl_to_stdlib_verify = {v: k for k, v in _stdlib_to_openssl_verify.items()}
-
-# The SSLvX values are the most likely to be missing in the future
-# but we check them all just to be sure.
-_OP_NO_SSLv2_OR_SSLv3: int = getattr(OpenSSL.SSL, "OP_NO_SSLv2", 0) | getattr(
- OpenSSL.SSL, "OP_NO_SSLv3", 0
-)
-_OP_NO_TLSv1: int = getattr(OpenSSL.SSL, "OP_NO_TLSv1", 0)
-_OP_NO_TLSv1_1: int = getattr(OpenSSL.SSL, "OP_NO_TLSv1_1", 0)
-_OP_NO_TLSv1_2: int = getattr(OpenSSL.SSL, "OP_NO_TLSv1_2", 0)
-_OP_NO_TLSv1_3: int = getattr(OpenSSL.SSL, "OP_NO_TLSv1_3", 0)
-
-_openssl_to_ssl_minimum_version: dict[int, int] = {
- ssl.TLSVersion.MINIMUM_SUPPORTED: _OP_NO_SSLv2_OR_SSLv3,
- ssl.TLSVersion.TLSv1: _OP_NO_SSLv2_OR_SSLv3,
- ssl.TLSVersion.TLSv1_1: _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1,
- ssl.TLSVersion.TLSv1_2: _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1 | _OP_NO_TLSv1_1,
- ssl.TLSVersion.TLSv1_3: (
- _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1 | _OP_NO_TLSv1_1 | _OP_NO_TLSv1_2
- ),
- ssl.TLSVersion.MAXIMUM_SUPPORTED: (
- _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1 | _OP_NO_TLSv1_1 | _OP_NO_TLSv1_2
- ),
-}
-_openssl_to_ssl_maximum_version: dict[int, int] = {
- ssl.TLSVersion.MINIMUM_SUPPORTED: (
- _OP_NO_SSLv2_OR_SSLv3
- | _OP_NO_TLSv1
- | _OP_NO_TLSv1_1
- | _OP_NO_TLSv1_2
- | _OP_NO_TLSv1_3
- ),
- ssl.TLSVersion.TLSv1: (
- _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1_1 | _OP_NO_TLSv1_2 | _OP_NO_TLSv1_3
- ),
- ssl.TLSVersion.TLSv1_1: _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1_2 | _OP_NO_TLSv1_3,
- ssl.TLSVersion.TLSv1_2: _OP_NO_SSLv2_OR_SSLv3 | _OP_NO_TLSv1_3,
- ssl.TLSVersion.TLSv1_3: _OP_NO_SSLv2_OR_SSLv3,
- ssl.TLSVersion.MAXIMUM_SUPPORTED: _OP_NO_SSLv2_OR_SSLv3,
-}
-
-# OpenSSL will only write 16K at a time
-SSL_WRITE_BLOCKSIZE = 16384
-
-orig_util_SSLContext = util.ssl_.SSLContext
-
-
-log = logging.getLogger(__name__)
-
-
-def inject_into_urllib3() -> None:
- "Monkey-patch urllib3 with PyOpenSSL-backed SSL-support."
-
- _validate_dependencies_met()
-
- util.SSLContext = PyOpenSSLContext # type: ignore[assignment]
- util.ssl_.SSLContext = PyOpenSSLContext # type: ignore[assignment]
- util.IS_PYOPENSSL = True
- util.ssl_.IS_PYOPENSSL = True
-
-
-def extract_from_urllib3() -> None:
- "Undo monkey-patching by :func:`inject_into_urllib3`."
-
- util.SSLContext = orig_util_SSLContext
- util.ssl_.SSLContext = orig_util_SSLContext
- util.IS_PYOPENSSL = False
- util.ssl_.IS_PYOPENSSL = False
-
-
-def _validate_dependencies_met() -> None:
- """
- Verifies that PyOpenSSL's package-level dependencies have been met.
- Throws `ImportError` if they are not met.
- """
- # Method added in `cryptography==1.1`; not available in older versions
- from cryptography.x509.extensions import Extensions
-
- if getattr(Extensions, "get_extension_for_class", None) is None:
- raise ImportError(
- "'cryptography' module missing required functionality. "
- "Try upgrading to v1.3.4 or newer."
- )
-
- # pyOpenSSL 0.14 and above use cryptography for OpenSSL bindings. The _x509
- # attribute is only present on those versions.
- from OpenSSL.crypto import X509
-
- x509 = X509()
- if getattr(x509, "_x509", None) is None:
- raise ImportError(
- "'pyOpenSSL' module missing required functionality. "
- "Try upgrading to v0.14 or newer."
- )
-
-
-def _dnsname_to_stdlib(name: str) -> str | None:
- """
- Converts a dNSName SubjectAlternativeName field to the form used by the
- standard library on the given Python version.
-
- Cryptography produces a dNSName as a unicode string that was idna-decoded
- from ASCII bytes. We need to idna-encode that string to get it back, and
- then on Python 3 we also need to convert to unicode via UTF-8 (the stdlib
- uses PyUnicode_FromStringAndSize on it, which decodes via UTF-8).
-
- If the name cannot be idna-encoded then we return None signalling that
- the name given should be skipped.
- """
-
- def idna_encode(name: str) -> bytes | None:
- """
- Borrowed wholesale from the Python Cryptography Project. It turns out
- that we can't just safely call `idna.encode`: it can explode for
- wildcard names. This avoids that problem.
- """
- import idna
-
- try:
- for prefix in ["*.", "."]:
- if name.startswith(prefix):
- name = name[len(prefix) :]
- return prefix.encode("ascii") + idna.encode(name)
- return idna.encode(name)
- except idna.core.IDNAError:
- return None
-
- # Don't send IPv6 addresses through the IDNA encoder.
- if ":" in name:
- return name
-
- encoded_name = idna_encode(name)
- if encoded_name is None:
- return None
- return encoded_name.decode("utf-8")
-
-
-def get_subj_alt_name(peer_cert: X509) -> list[tuple[str, str]]:
- """
- Given an PyOpenSSL certificate, provides all the subject alternative names.
- """
- cert = peer_cert.to_cryptography()
-
- # We want to find the SAN extension. Ask Cryptography to locate it (it's
- # faster than looping in Python)
- try:
- ext = cert.extensions.get_extension_for_class(x509.SubjectAlternativeName).value
- except x509.ExtensionNotFound:
- # No such extension, return the empty list.
- return []
- except (
- x509.DuplicateExtension,
- UnsupportedExtension,
- x509.UnsupportedGeneralNameType,
- UnicodeError,
- ) as e:
- # A problem has been found with the quality of the certificate. Assume
- # no SAN field is present.
- log.warning(
- "A problem was encountered with the certificate that prevented "
- "urllib3 from finding the SubjectAlternativeName field. This can "
- "affect certificate validation. The error was %s",
- e,
- )
- return []
-
- # We want to return dNSName and iPAddress fields. We need to cast the IPs
- # back to strings because the match_hostname function wants them as
- # strings.
- # Sadly the DNS names need to be idna encoded and then, on Python 3, UTF-8
- # decoded. This is pretty frustrating, but that's what the standard library
- # does with certificates, and so we need to attempt to do the same.
- # We also want to skip over names which cannot be idna encoded.
- names = [
- ("DNS", name)
- for name in map(_dnsname_to_stdlib, ext.get_values_for_type(x509.DNSName))
- if name is not None
- ]
- names.extend(
- ("IP Address", str(name)) for name in ext.get_values_for_type(x509.IPAddress)
- )
-
- return names
-
-
-class WrappedSocket:
- """API-compatibility wrapper for Python OpenSSL's Connection-class."""
-
- def __init__(
- self,
- connection: OpenSSL.SSL.Connection,
- socket: socket_cls,
- suppress_ragged_eofs: bool = True,
- ) -> None:
- self.connection = connection
- self.socket = socket
- self.suppress_ragged_eofs = suppress_ragged_eofs
- self._io_refs = 0
- self._closed = False
-
- def fileno(self) -> int:
- return self.socket.fileno()
-
- # Copy-pasted from Python 3.5 source code
- def _decref_socketios(self) -> None:
- if self._io_refs > 0:
- self._io_refs -= 1
- if self._closed:
- self.close()
-
- def recv(self, *args: typing.Any, **kwargs: typing.Any) -> bytes:
- try:
- data = self.connection.recv(*args, **kwargs)
- except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
- return b""
- else:
- raise OSError(e.args[0], str(e)) from e
- except OpenSSL.SSL.ZeroReturnError:
- if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
- return b""
- else:
- raise
- except OpenSSL.SSL.WantReadError as e:
- if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout("The read operation timed out") from e
- else:
- return self.recv(*args, **kwargs)
-
- # TLS 1.3 post-handshake authentication
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError(f"read error: {e!r}") from e
- else:
- return data # type: ignore[no-any-return]
-
- def recv_into(self, *args: typing.Any, **kwargs: typing.Any) -> int:
- try:
- return self.connection.recv_into(*args, **kwargs) # type: ignore[no-any-return]
- except OpenSSL.SSL.SysCallError as e:
- if self.suppress_ragged_eofs and e.args == (-1, "Unexpected EOF"):
- return 0
- else:
- raise OSError(e.args[0], str(e)) from e
- except OpenSSL.SSL.ZeroReturnError:
- if self.connection.get_shutdown() == OpenSSL.SSL.RECEIVED_SHUTDOWN:
- return 0
- else:
- raise
- except OpenSSL.SSL.WantReadError as e:
- if not util.wait_for_read(self.socket, self.socket.gettimeout()):
- raise timeout("The read operation timed out") from e
- else:
- return self.recv_into(*args, **kwargs)
-
- # TLS 1.3 post-handshake authentication
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError(f"read error: {e!r}") from e
-
- def settimeout(self, timeout: float) -> None:
- return self.socket.settimeout(timeout)
-
- def _send_until_done(self, data: bytes) -> int:
- while True:
- try:
- return self.connection.send(data) # type: ignore[no-any-return]
- except OpenSSL.SSL.WantWriteError as e:
- if not util.wait_for_write(self.socket, self.socket.gettimeout()):
- raise timeout() from e
- continue
- except OpenSSL.SSL.SysCallError as e:
- raise OSError(e.args[0], str(e)) from e
-
- def sendall(self, data: bytes) -> None:
- total_sent = 0
- while total_sent < len(data):
- sent = self._send_until_done(
- data[total_sent : total_sent + SSL_WRITE_BLOCKSIZE]
- )
- total_sent += sent
-
- def shutdown(self) -> None:
- # FIXME rethrow compatible exceptions should we ever use this
- self.connection.shutdown()
-
- def close(self) -> None:
- self._closed = True
- if self._io_refs <= 0:
- self._real_close()
-
- def _real_close(self) -> None:
- try:
- return self.connection.close() # type: ignore[no-any-return]
- except OpenSSL.SSL.Error:
- return
-
- def getpeercert(
- self, binary_form: bool = False
- ) -> dict[str, list[typing.Any]] | None:
- x509 = self.connection.get_peer_certificate()
-
- if not x509:
- return x509 # type: ignore[no-any-return]
-
- if binary_form:
- return OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_ASN1, x509) # type: ignore[no-any-return]
-
- return {
- "subject": ((("commonName", x509.get_subject().CN),),), # type: ignore[dict-item]
- "subjectAltName": get_subj_alt_name(x509),
- }
-
- def version(self) -> str:
- return self.connection.get_protocol_version_name() # type: ignore[no-any-return]
-
-
-WrappedSocket.makefile = socket_cls.makefile # type: ignore[attr-defined]
-
-
-class PyOpenSSLContext:
- """
- I am a wrapper class for the PyOpenSSL ``Context`` object. I am responsible
- for translating the interface of the standard library ``SSLContext`` object
- to calls into PyOpenSSL.
- """
-
- def __init__(self, protocol: int) -> None:
- self.protocol = _openssl_versions[protocol]
- self._ctx = OpenSSL.SSL.Context(self.protocol)
- self._options = 0
- self.check_hostname = False
- self._minimum_version: int = ssl.TLSVersion.MINIMUM_SUPPORTED
- self._maximum_version: int = ssl.TLSVersion.MAXIMUM_SUPPORTED
-
- @property
- def options(self) -> int:
- return self._options
-
- @options.setter
- def options(self, value: int) -> None:
- self._options = value
- self._set_ctx_options()
-
- @property
- def verify_mode(self) -> int:
- return _openssl_to_stdlib_verify[self._ctx.get_verify_mode()]
-
- @verify_mode.setter
- def verify_mode(self, value: ssl.VerifyMode) -> None:
- self._ctx.set_verify(_stdlib_to_openssl_verify[value], _verify_callback)
-
- def set_default_verify_paths(self) -> None:
- self._ctx.set_default_verify_paths()
-
- def set_ciphers(self, ciphers: bytes | str) -> None:
- if isinstance(ciphers, str):
- ciphers = ciphers.encode("utf-8")
- self._ctx.set_cipher_list(ciphers)
-
- def load_verify_locations(
- self,
- cafile: str | None = None,
- capath: str | None = None,
- cadata: bytes | None = None,
- ) -> None:
- if cafile is not None:
- cafile = cafile.encode("utf-8") # type: ignore[assignment]
- if capath is not None:
- capath = capath.encode("utf-8") # type: ignore[assignment]
- try:
- self._ctx.load_verify_locations(cafile, capath)
- if cadata is not None:
- self._ctx.load_verify_locations(BytesIO(cadata))
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError(f"unable to load trusted certificates: {e!r}") from e
-
- def load_cert_chain(
- self,
- certfile: str,
- keyfile: str | None = None,
- password: str | None = None,
- ) -> None:
- try:
- self._ctx.use_certificate_chain_file(certfile)
- if password is not None:
- if not isinstance(password, bytes):
- password = password.encode("utf-8") # type: ignore[assignment]
- self._ctx.set_passwd_cb(lambda *_: password)
- self._ctx.use_privatekey_file(keyfile or certfile)
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError(f"Unable to load certificate chain: {e!r}") from e
-
- def set_alpn_protocols(self, protocols: list[bytes | str]) -> None:
- protocols = [util.util.to_bytes(p, "ascii") for p in protocols]
- return self._ctx.set_alpn_protos(protocols) # type: ignore[no-any-return]
-
- def wrap_socket(
- self,
- sock: socket_cls,
- server_side: bool = False,
- do_handshake_on_connect: bool = True,
- suppress_ragged_eofs: bool = True,
- server_hostname: bytes | str | None = None,
- ) -> WrappedSocket:
- cnx = OpenSSL.SSL.Connection(self._ctx, sock)
-
- # If server_hostname is an IP, don't use it for SNI, per RFC6066 Section 3
- if server_hostname and not util.ssl_.is_ipaddress(server_hostname):
- if isinstance(server_hostname, str):
- server_hostname = server_hostname.encode("utf-8")
- cnx.set_tlsext_host_name(server_hostname)
-
- cnx.set_connect_state()
-
- while True:
- try:
- cnx.do_handshake()
- except OpenSSL.SSL.WantReadError as e:
- if not util.wait_for_read(sock, sock.gettimeout()):
- raise timeout("select timed out") from e
- continue
- except OpenSSL.SSL.Error as e:
- raise ssl.SSLError(f"bad handshake: {e!r}") from e
- break
-
- return WrappedSocket(cnx, sock)
-
- def _set_ctx_options(self) -> None:
- self._ctx.set_options(
- self._options
- | _openssl_to_ssl_minimum_version[self._minimum_version]
- | _openssl_to_ssl_maximum_version[self._maximum_version]
- )
-
- @property
- def minimum_version(self) -> int:
- return self._minimum_version
-
- @minimum_version.setter
- def minimum_version(self, minimum_version: int) -> None:
- self._minimum_version = minimum_version
- self._set_ctx_options()
-
- @property
- def maximum_version(self) -> int:
- return self._maximum_version
-
- @maximum_version.setter
- def maximum_version(self, maximum_version: int) -> None:
- self._maximum_version = maximum_version
- self._set_ctx_options()
-
-
-def _verify_callback(
- cnx: OpenSSL.SSL.Connection,
- x509: X509,
- err_no: int,
- err_depth: int,
- return_code: int,
-) -> bool:
- return err_no == 0
diff --git a/.venv/lib/python3.12/site-packages/urllib3/contrib/socks.py b/.venv/lib/python3.12/site-packages/urllib3/contrib/socks.py
deleted file mode 100644
index c62b5e0..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/contrib/socks.py
+++ /dev/null
@@ -1,228 +0,0 @@
-"""
-This module contains provisional support for SOCKS proxies from within
-urllib3. This module supports SOCKS4, SOCKS4A (an extension of SOCKS4), and
-SOCKS5. To enable its functionality, either install PySocks or install this
-module with the ``socks`` extra.
-
-The SOCKS implementation supports the full range of urllib3 features. It also
-supports the following SOCKS features:
-
-- SOCKS4A (``proxy_url='socks4a://...``)
-- SOCKS4 (``proxy_url='socks4://...``)
-- SOCKS5 with remote DNS (``proxy_url='socks5h://...``)
-- SOCKS5 with local DNS (``proxy_url='socks5://...``)
-- Usernames and passwords for the SOCKS proxy
-
-.. note::
- It is recommended to use ``socks5h://`` or ``socks4a://`` schemes in
- your ``proxy_url`` to ensure that DNS resolution is done from the remote
- server instead of client-side when connecting to a domain name.
-
-SOCKS4 supports IPv4 and domain names with the SOCKS4A extension. SOCKS5
-supports IPv4, IPv6, and domain names.
-
-When connecting to a SOCKS4 proxy the ``username`` portion of the ``proxy_url``
-will be sent as the ``userid`` section of the SOCKS request:
-
-.. code-block:: python
-
- proxy_url="socks4a://@proxy-host"
-
-When connecting to a SOCKS5 proxy the ``username`` and ``password`` portion
-of the ``proxy_url`` will be sent as the username/password to authenticate
-with the proxy:
-
-.. code-block:: python
-
- proxy_url="socks5h://:@proxy-host"
-
-"""
-
-from __future__ import annotations
-
-try:
- import socks # type: ignore[import-not-found]
-except ImportError:
- import warnings
-
- from ..exceptions import DependencyWarning
-
- warnings.warn(
- (
- "SOCKS support in urllib3 requires the installation of optional "
- "dependencies: specifically, PySocks. For more information, see "
- "https://urllib3.readthedocs.io/en/latest/advanced-usage.html#socks-proxies"
- ),
- DependencyWarning,
- )
- raise
-
-import typing
-from socket import timeout as SocketTimeout
-
-from ..connection import HTTPConnection, HTTPSConnection
-from ..connectionpool import HTTPConnectionPool, HTTPSConnectionPool
-from ..exceptions import ConnectTimeoutError, NewConnectionError
-from ..poolmanager import PoolManager
-from ..util.url import parse_url
-
-try:
- import ssl
-except ImportError:
- ssl = None # type: ignore[assignment]
-
-
-class _TYPE_SOCKS_OPTIONS(typing.TypedDict):
- socks_version: int
- proxy_host: str | None
- proxy_port: str | None
- username: str | None
- password: str | None
- rdns: bool
-
-
-class SOCKSConnection(HTTPConnection):
- """
- A plain-text HTTP connection that connects via a SOCKS proxy.
- """
-
- def __init__(
- self,
- _socks_options: _TYPE_SOCKS_OPTIONS,
- *args: typing.Any,
- **kwargs: typing.Any,
- ) -> None:
- self._socks_options = _socks_options
- super().__init__(*args, **kwargs)
-
- def _new_conn(self) -> socks.socksocket:
- """
- Establish a new connection via the SOCKS proxy.
- """
- extra_kw: dict[str, typing.Any] = {}
- if self.source_address:
- extra_kw["source_address"] = self.source_address
-
- if self.socket_options:
- extra_kw["socket_options"] = self.socket_options
-
- try:
- conn = socks.create_connection(
- (self.host, self.port),
- proxy_type=self._socks_options["socks_version"],
- proxy_addr=self._socks_options["proxy_host"],
- proxy_port=self._socks_options["proxy_port"],
- proxy_username=self._socks_options["username"],
- proxy_password=self._socks_options["password"],
- proxy_rdns=self._socks_options["rdns"],
- timeout=self.timeout,
- **extra_kw,
- )
-
- except SocketTimeout as e:
- raise ConnectTimeoutError(
- self,
- f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
- ) from e
-
- except socks.ProxyError as e:
- # This is fragile as hell, but it seems to be the only way to raise
- # useful errors here.
- if e.socket_err:
- error = e.socket_err
- if isinstance(error, SocketTimeout):
- raise ConnectTimeoutError(
- self,
- f"Connection to {self.host} timed out. (connect timeout={self.timeout})",
- ) from e
- else:
- # Adding `from e` messes with coverage somehow, so it's omitted.
- # See #2386.
- raise NewConnectionError(
- self, f"Failed to establish a new connection: {error}"
- )
- else:
- raise NewConnectionError(
- self, f"Failed to establish a new connection: {e}"
- ) from e
-
- except OSError as e: # Defensive: PySocks should catch all these.
- raise NewConnectionError(
- self, f"Failed to establish a new connection: {e}"
- ) from e
-
- return conn
-
-
-# We don't need to duplicate the Verified/Unverified distinction from
-# urllib3/connection.py here because the HTTPSConnection will already have been
-# correctly set to either the Verified or Unverified form by that module. This
-# means the SOCKSHTTPSConnection will automatically be the correct type.
-class SOCKSHTTPSConnection(SOCKSConnection, HTTPSConnection):
- pass
-
-
-class SOCKSHTTPConnectionPool(HTTPConnectionPool):
- ConnectionCls = SOCKSConnection
-
-
-class SOCKSHTTPSConnectionPool(HTTPSConnectionPool):
- ConnectionCls = SOCKSHTTPSConnection
-
-
-class SOCKSProxyManager(PoolManager):
- """
- A version of the urllib3 ProxyManager that routes connections via the
- defined SOCKS proxy.
- """
-
- pool_classes_by_scheme = {
- "http": SOCKSHTTPConnectionPool,
- "https": SOCKSHTTPSConnectionPool,
- }
-
- def __init__(
- self,
- proxy_url: str,
- username: str | None = None,
- password: str | None = None,
- num_pools: int = 10,
- headers: typing.Mapping[str, str] | None = None,
- **connection_pool_kw: typing.Any,
- ):
- parsed = parse_url(proxy_url)
-
- if username is None and password is None and parsed.auth is not None:
- split = parsed.auth.split(":")
- if len(split) == 2:
- username, password = split
- if parsed.scheme == "socks5":
- socks_version = socks.PROXY_TYPE_SOCKS5
- rdns = False
- elif parsed.scheme == "socks5h":
- socks_version = socks.PROXY_TYPE_SOCKS5
- rdns = True
- elif parsed.scheme == "socks4":
- socks_version = socks.PROXY_TYPE_SOCKS4
- rdns = False
- elif parsed.scheme == "socks4a":
- socks_version = socks.PROXY_TYPE_SOCKS4
- rdns = True
- else:
- raise ValueError(f"Unable to determine SOCKS version from {proxy_url}")
-
- self.proxy_url = proxy_url
-
- socks_options = {
- "socks_version": socks_version,
- "proxy_host": parsed.host,
- "proxy_port": parsed.port,
- "username": username,
- "password": password,
- "rdns": rdns,
- }
- connection_pool_kw["_socks_options"] = socks_options
-
- super().__init__(num_pools, headers, **connection_pool_kw)
-
- self.pool_classes_by_scheme = SOCKSProxyManager.pool_classes_by_scheme
diff --git a/.venv/lib/python3.12/site-packages/urllib3/exceptions.py b/.venv/lib/python3.12/site-packages/urllib3/exceptions.py
deleted file mode 100644
index b0792f0..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/exceptions.py
+++ /dev/null
@@ -1,321 +0,0 @@
-from __future__ import annotations
-
-import socket
-import typing
-import warnings
-from email.errors import MessageDefect
-from http.client import IncompleteRead as httplib_IncompleteRead
-
-if typing.TYPE_CHECKING:
- from .connection import HTTPConnection
- from .connectionpool import ConnectionPool
- from .response import HTTPResponse
- from .util.retry import Retry
-
-# Base Exceptions
-
-
-class HTTPError(Exception):
- """Base exception used by this module."""
-
-
-class HTTPWarning(Warning):
- """Base warning used by this module."""
-
-
-_TYPE_REDUCE_RESULT = typing.Tuple[
- typing.Callable[..., object], typing.Tuple[object, ...]
-]
-
-
-class PoolError(HTTPError):
- """Base exception for errors caused within a pool."""
-
- def __init__(self, pool: ConnectionPool, message: str) -> None:
- self.pool = pool
- super().__init__(f"{pool}: {message}")
-
- def __reduce__(self) -> _TYPE_REDUCE_RESULT:
- # For pickling purposes.
- return self.__class__, (None, None)
-
-
-class RequestError(PoolError):
- """Base exception for PoolErrors that have associated URLs."""
-
- def __init__(self, pool: ConnectionPool, url: str, message: str) -> None:
- self.url = url
- super().__init__(pool, message)
-
- def __reduce__(self) -> _TYPE_REDUCE_RESULT:
- # For pickling purposes.
- return self.__class__, (None, self.url, None)
-
-
-class SSLError(HTTPError):
- """Raised when SSL certificate fails in an HTTPS connection."""
-
-
-class ProxyError(HTTPError):
- """Raised when the connection to a proxy fails."""
-
- # The original error is also available as __cause__.
- original_error: Exception
-
- def __init__(self, message: str, error: Exception) -> None:
- super().__init__(message, error)
- self.original_error = error
-
-
-class DecodeError(HTTPError):
- """Raised when automatic decoding based on Content-Type fails."""
-
-
-class ProtocolError(HTTPError):
- """Raised when something unexpected happens mid-request/response."""
-
-
-#: Renamed to ProtocolError but aliased for backwards compatibility.
-ConnectionError = ProtocolError
-
-
-# Leaf Exceptions
-
-
-class MaxRetryError(RequestError):
- """Raised when the maximum number of retries is exceeded.
-
- :param pool: The connection pool
- :type pool: :class:`~urllib3.connectionpool.HTTPConnectionPool`
- :param str url: The requested Url
- :param reason: The underlying error
- :type reason: :class:`Exception`
-
- """
-
- def __init__(
- self, pool: ConnectionPool, url: str, reason: Exception | None = None
- ) -> None:
- self.reason = reason
-
- message = f"Max retries exceeded with url: {url} (Caused by {reason!r})"
-
- super().__init__(pool, url, message)
-
-
-class HostChangedError(RequestError):
- """Raised when an existing pool gets a request for a foreign host."""
-
- def __init__(
- self, pool: ConnectionPool, url: str, retries: Retry | int = 3
- ) -> None:
- message = f"Tried to open a foreign host with url: {url}"
- super().__init__(pool, url, message)
- self.retries = retries
-
-
-class TimeoutStateError(HTTPError):
- """Raised when passing an invalid state to a timeout"""
-
-
-class TimeoutError(HTTPError):
- """Raised when a socket timeout error occurs.
-
- Catching this error will catch both :exc:`ReadTimeoutErrors
- ` and :exc:`ConnectTimeoutErrors `.
- """
-
-
-class ReadTimeoutError(TimeoutError, RequestError):
- """Raised when a socket timeout occurs while receiving data from a server"""
-
-
-# This timeout error does not have a URL attached and needs to inherit from the
-# base HTTPError
-class ConnectTimeoutError(TimeoutError):
- """Raised when a socket timeout occurs while connecting to a server"""
-
-
-class NewConnectionError(ConnectTimeoutError, HTTPError):
- """Raised when we fail to establish a new connection. Usually ECONNREFUSED."""
-
- def __init__(self, conn: HTTPConnection, message: str) -> None:
- self.conn = conn
- super().__init__(f"{conn}: {message}")
-
- @property
- def pool(self) -> HTTPConnection:
- warnings.warn(
- "The 'pool' property is deprecated and will be removed "
- "in urllib3 v2.1.0. Use 'conn' instead.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- return self.conn
-
-
-class NameResolutionError(NewConnectionError):
- """Raised when host name resolution fails."""
-
- def __init__(self, host: str, conn: HTTPConnection, reason: socket.gaierror):
- message = f"Failed to resolve '{host}' ({reason})"
- super().__init__(conn, message)
-
-
-class EmptyPoolError(PoolError):
- """Raised when a pool runs out of connections and no more are allowed."""
-
-
-class FullPoolError(PoolError):
- """Raised when we try to add a connection to a full pool in blocking mode."""
-
-
-class ClosedPoolError(PoolError):
- """Raised when a request enters a pool after the pool has been closed."""
-
-
-class LocationValueError(ValueError, HTTPError):
- """Raised when there is something wrong with a given URL input."""
-
-
-class LocationParseError(LocationValueError):
- """Raised when get_host or similar fails to parse the URL input."""
-
- def __init__(self, location: str) -> None:
- message = f"Failed to parse: {location}"
- super().__init__(message)
-
- self.location = location
-
-
-class URLSchemeUnknown(LocationValueError):
- """Raised when a URL input has an unsupported scheme."""
-
- def __init__(self, scheme: str):
- message = f"Not supported URL scheme {scheme}"
- super().__init__(message)
-
- self.scheme = scheme
-
-
-class ResponseError(HTTPError):
- """Used as a container for an error reason supplied in a MaxRetryError."""
-
- GENERIC_ERROR = "too many error responses"
- SPECIFIC_ERROR = "too many {status_code} error responses"
-
-
-class SecurityWarning(HTTPWarning):
- """Warned when performing security reducing actions"""
-
-
-class InsecureRequestWarning(SecurityWarning):
- """Warned when making an unverified HTTPS request."""
-
-
-class NotOpenSSLWarning(SecurityWarning):
- """Warned when using unsupported SSL library"""
-
-
-class SystemTimeWarning(SecurityWarning):
- """Warned when system time is suspected to be wrong"""
-
-
-class InsecurePlatformWarning(SecurityWarning):
- """Warned when certain TLS/SSL configuration is not available on a platform."""
-
-
-class DependencyWarning(HTTPWarning):
- """
- Warned when an attempt is made to import a module with missing optional
- dependencies.
- """
-
-
-class ResponseNotChunked(ProtocolError, ValueError):
- """Response needs to be chunked in order to read it as chunks."""
-
-
-class BodyNotHttplibCompatible(HTTPError):
- """
- Body should be :class:`http.client.HTTPResponse` like
- (have an fp attribute which returns raw chunks) for read_chunked().
- """
-
-
-class IncompleteRead(HTTPError, httplib_IncompleteRead):
- """
- Response length doesn't match expected Content-Length
-
- Subclass of :class:`http.client.IncompleteRead` to allow int value
- for ``partial`` to avoid creating large objects on streamed reads.
- """
-
- partial: int # type: ignore[assignment]
- expected: int
-
- def __init__(self, partial: int, expected: int) -> None:
- self.partial = partial
- self.expected = expected
-
- def __repr__(self) -> str:
- return "IncompleteRead(%i bytes read, %i more expected)" % (
- self.partial,
- self.expected,
- )
-
-
-class InvalidChunkLength(HTTPError, httplib_IncompleteRead):
- """Invalid chunk length in a chunked response."""
-
- def __init__(self, response: HTTPResponse, length: bytes) -> None:
- self.partial: int = response.tell() # type: ignore[assignment]
- self.expected: int | None = response.length_remaining
- self.response = response
- self.length = length
-
- def __repr__(self) -> str:
- return "InvalidChunkLength(got length %r, %i bytes read)" % (
- self.length,
- self.partial,
- )
-
-
-class InvalidHeader(HTTPError):
- """The header provided was somehow invalid."""
-
-
-class ProxySchemeUnknown(AssertionError, URLSchemeUnknown):
- """ProxyManager does not support the supplied scheme"""
-
- # TODO(t-8ch): Stop inheriting from AssertionError in v2.0.
-
- def __init__(self, scheme: str | None) -> None:
- # 'localhost' is here because our URL parser parses
- # localhost:8080 -> scheme=localhost, remove if we fix this.
- if scheme == "localhost":
- scheme = None
- if scheme is None:
- message = "Proxy URL had no scheme, should start with http:// or https://"
- else:
- message = f"Proxy URL had unsupported scheme {scheme}, should use http:// or https://"
- super().__init__(message)
-
-
-class ProxySchemeUnsupported(ValueError):
- """Fetching HTTPS resources through HTTPS proxies is unsupported"""
-
-
-class HeaderParsingError(HTTPError):
- """Raised by assert_header_parsing, but we convert it to a log.warning statement."""
-
- def __init__(
- self, defects: list[MessageDefect], unparsed_data: bytes | str | None
- ) -> None:
- message = f"{defects or 'Unknown'}, unparsed data: {unparsed_data!r}"
- super().__init__(message)
-
-
-class UnrewindableBodyError(HTTPError):
- """urllib3 encountered an error when trying to rewind a body"""
diff --git a/.venv/lib/python3.12/site-packages/urllib3/fields.py b/.venv/lib/python3.12/site-packages/urllib3/fields.py
deleted file mode 100644
index 3e258a5..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/fields.py
+++ /dev/null
@@ -1,341 +0,0 @@
-from __future__ import annotations
-
-import email.utils
-import mimetypes
-import typing
-
-_TYPE_FIELD_VALUE = typing.Union[str, bytes]
-_TYPE_FIELD_VALUE_TUPLE = typing.Union[
- _TYPE_FIELD_VALUE,
- typing.Tuple[str, _TYPE_FIELD_VALUE],
- typing.Tuple[str, _TYPE_FIELD_VALUE, str],
-]
-
-
-def guess_content_type(
- filename: str | None, default: str = "application/octet-stream"
-) -> str:
- """
- Guess the "Content-Type" of a file.
-
- :param filename:
- The filename to guess the "Content-Type" of using :mod:`mimetypes`.
- :param default:
- If no "Content-Type" can be guessed, default to `default`.
- """
- if filename:
- return mimetypes.guess_type(filename)[0] or default
- return default
-
-
-def format_header_param_rfc2231(name: str, value: _TYPE_FIELD_VALUE) -> str:
- """
- Helper function to format and quote a single header parameter using the
- strategy defined in RFC 2231.
-
- Particularly useful for header parameters which might contain
- non-ASCII values, like file names. This follows
- `RFC 2388 Section 4.4 `_.
-
- :param name:
- The name of the parameter, a string expected to be ASCII only.
- :param value:
- The value of the parameter, provided as ``bytes`` or `str``.
- :returns:
- An RFC-2231-formatted unicode string.
-
- .. deprecated:: 2.0.0
- Will be removed in urllib3 v2.1.0. This is not valid for
- ``multipart/form-data`` header parameters.
- """
- import warnings
-
- warnings.warn(
- "'format_header_param_rfc2231' is deprecated and will be "
- "removed in urllib3 v2.1.0. This is not valid for "
- "multipart/form-data header parameters.",
- DeprecationWarning,
- stacklevel=2,
- )
-
- if isinstance(value, bytes):
- value = value.decode("utf-8")
-
- if not any(ch in value for ch in '"\\\r\n'):
- result = f'{name}="{value}"'
- try:
- result.encode("ascii")
- except (UnicodeEncodeError, UnicodeDecodeError):
- pass
- else:
- return result
-
- value = email.utils.encode_rfc2231(value, "utf-8")
- value = f"{name}*={value}"
-
- return value
-
-
-def format_multipart_header_param(name: str, value: _TYPE_FIELD_VALUE) -> str:
- """
- Format and quote a single multipart header parameter.
-
- This follows the `WHATWG HTML Standard`_ as of 2021/06/10, matching
- the behavior of current browser and curl versions. Values are
- assumed to be UTF-8. The ``\\n``, ``\\r``, and ``"`` characters are
- percent encoded.
-
- .. _WHATWG HTML Standard:
- https://html.spec.whatwg.org/multipage/
- form-control-infrastructure.html#multipart-form-data
-
- :param name:
- The name of the parameter, an ASCII-only ``str``.
- :param value:
- The value of the parameter, a ``str`` or UTF-8 encoded
- ``bytes``.
- :returns:
- A string ``name="value"`` with the escaped value.
-
- .. versionchanged:: 2.0.0
- Matches the WHATWG HTML Standard as of 2021/06/10. Control
- characters are no longer percent encoded.
-
- .. versionchanged:: 2.0.0
- Renamed from ``format_header_param_html5`` and
- ``format_header_param``. The old names will be removed in
- urllib3 v2.1.0.
- """
- if isinstance(value, bytes):
- value = value.decode("utf-8")
-
- # percent encode \n \r "
- value = value.translate({10: "%0A", 13: "%0D", 34: "%22"})
- return f'{name}="{value}"'
-
-
-def format_header_param_html5(name: str, value: _TYPE_FIELD_VALUE) -> str:
- """
- .. deprecated:: 2.0.0
- Renamed to :func:`format_multipart_header_param`. Will be
- removed in urllib3 v2.1.0.
- """
- import warnings
-
- warnings.warn(
- "'format_header_param_html5' has been renamed to "
- "'format_multipart_header_param'. The old name will be "
- "removed in urllib3 v2.1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
- return format_multipart_header_param(name, value)
-
-
-def format_header_param(name: str, value: _TYPE_FIELD_VALUE) -> str:
- """
- .. deprecated:: 2.0.0
- Renamed to :func:`format_multipart_header_param`. Will be
- removed in urllib3 v2.1.0.
- """
- import warnings
-
- warnings.warn(
- "'format_header_param' has been renamed to "
- "'format_multipart_header_param'. The old name will be "
- "removed in urllib3 v2.1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
- return format_multipart_header_param(name, value)
-
-
-class RequestField:
- """
- A data container for request body parameters.
-
- :param name:
- The name of this request field. Must be unicode.
- :param data:
- The data/value body.
- :param filename:
- An optional filename of the request field. Must be unicode.
- :param headers:
- An optional dict-like object of headers to initially use for the field.
-
- .. versionchanged:: 2.0.0
- The ``header_formatter`` parameter is deprecated and will
- be removed in urllib3 v2.1.0.
- """
-
- def __init__(
- self,
- name: str,
- data: _TYPE_FIELD_VALUE,
- filename: str | None = None,
- headers: typing.Mapping[str, str] | None = None,
- header_formatter: typing.Callable[[str, _TYPE_FIELD_VALUE], str] | None = None,
- ):
- self._name = name
- self._filename = filename
- self.data = data
- self.headers: dict[str, str | None] = {}
- if headers:
- self.headers = dict(headers)
-
- if header_formatter is not None:
- import warnings
-
- warnings.warn(
- "The 'header_formatter' parameter is deprecated and "
- "will be removed in urllib3 v2.1.0.",
- DeprecationWarning,
- stacklevel=2,
- )
- self.header_formatter = header_formatter
- else:
- self.header_formatter = format_multipart_header_param
-
- @classmethod
- def from_tuples(
- cls,
- fieldname: str,
- value: _TYPE_FIELD_VALUE_TUPLE,
- header_formatter: typing.Callable[[str, _TYPE_FIELD_VALUE], str] | None = None,
- ) -> RequestField:
- """
- A :class:`~urllib3.fields.RequestField` factory from old-style tuple parameters.
-
- Supports constructing :class:`~urllib3.fields.RequestField` from
- parameter of key/value strings AND key/filetuple. A filetuple is a
- (filename, data, MIME type) tuple where the MIME type is optional.
- For example::
-
- 'foo': 'bar',
- 'fakefile': ('foofile.txt', 'contents of foofile'),
- 'realfile': ('barfile.txt', open('realfile').read()),
- 'typedfile': ('bazfile.bin', open('bazfile').read(), 'image/jpeg'),
- 'nonamefile': 'contents of nonamefile field',
-
- Field names and filenames must be unicode.
- """
- filename: str | None
- content_type: str | None
- data: _TYPE_FIELD_VALUE
-
- if isinstance(value, tuple):
- if len(value) == 3:
- filename, data, content_type = value
- else:
- filename, data = value
- content_type = guess_content_type(filename)
- else:
- filename = None
- content_type = None
- data = value
-
- request_param = cls(
- fieldname, data, filename=filename, header_formatter=header_formatter
- )
- request_param.make_multipart(content_type=content_type)
-
- return request_param
-
- def _render_part(self, name: str, value: _TYPE_FIELD_VALUE) -> str:
- """
- Override this method to change how each multipart header
- parameter is formatted. By default, this calls
- :func:`format_multipart_header_param`.
-
- :param name:
- The name of the parameter, an ASCII-only ``str``.
- :param value:
- The value of the parameter, a ``str`` or UTF-8 encoded
- ``bytes``.
-
- :meta public:
- """
- return self.header_formatter(name, value)
-
- def _render_parts(
- self,
- header_parts: (
- dict[str, _TYPE_FIELD_VALUE | None]
- | typing.Sequence[tuple[str, _TYPE_FIELD_VALUE | None]]
- ),
- ) -> str:
- """
- Helper function to format and quote a single header.
-
- Useful for single headers that are composed of multiple items. E.g.,
- 'Content-Disposition' fields.
-
- :param header_parts:
- A sequence of (k, v) tuples or a :class:`dict` of (k, v) to format
- as `k1="v1"; k2="v2"; ...`.
- """
- iterable: typing.Iterable[tuple[str, _TYPE_FIELD_VALUE | None]]
-
- parts = []
- if isinstance(header_parts, dict):
- iterable = header_parts.items()
- else:
- iterable = header_parts
-
- for name, value in iterable:
- if value is not None:
- parts.append(self._render_part(name, value))
-
- return "; ".join(parts)
-
- def render_headers(self) -> str:
- """
- Renders the headers for this request field.
- """
- lines = []
-
- sort_keys = ["Content-Disposition", "Content-Type", "Content-Location"]
- for sort_key in sort_keys:
- if self.headers.get(sort_key, False):
- lines.append(f"{sort_key}: {self.headers[sort_key]}")
-
- for header_name, header_value in self.headers.items():
- if header_name not in sort_keys:
- if header_value:
- lines.append(f"{header_name}: {header_value}")
-
- lines.append("\r\n")
- return "\r\n".join(lines)
-
- def make_multipart(
- self,
- content_disposition: str | None = None,
- content_type: str | None = None,
- content_location: str | None = None,
- ) -> None:
- """
- Makes this request field into a multipart request field.
-
- This method overrides "Content-Disposition", "Content-Type" and
- "Content-Location" headers to the request parameter.
-
- :param content_disposition:
- The 'Content-Disposition' of the request body. Defaults to 'form-data'
- :param content_type:
- The 'Content-Type' of the request body.
- :param content_location:
- The 'Content-Location' of the request body.
-
- """
- content_disposition = (content_disposition or "form-data") + "; ".join(
- [
- "",
- self._render_parts(
- (("name", self._name), ("filename", self._filename))
- ),
- ]
- )
-
- self.headers["Content-Disposition"] = content_disposition
- self.headers["Content-Type"] = content_type
- self.headers["Content-Location"] = content_location
diff --git a/.venv/lib/python3.12/site-packages/urllib3/filepost.py b/.venv/lib/python3.12/site-packages/urllib3/filepost.py
deleted file mode 100644
index 1c90a21..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/filepost.py
+++ /dev/null
@@ -1,89 +0,0 @@
-from __future__ import annotations
-
-import binascii
-import codecs
-import os
-import typing
-from io import BytesIO
-
-from .fields import _TYPE_FIELD_VALUE_TUPLE, RequestField
-
-writer = codecs.lookup("utf-8")[3]
-
-_TYPE_FIELDS_SEQUENCE = typing.Sequence[
- typing.Union[typing.Tuple[str, _TYPE_FIELD_VALUE_TUPLE], RequestField]
-]
-_TYPE_FIELDS = typing.Union[
- _TYPE_FIELDS_SEQUENCE,
- typing.Mapping[str, _TYPE_FIELD_VALUE_TUPLE],
-]
-
-
-def choose_boundary() -> str:
- """
- Our embarrassingly-simple replacement for mimetools.choose_boundary.
- """
- return binascii.hexlify(os.urandom(16)).decode()
-
-
-def iter_field_objects(fields: _TYPE_FIELDS) -> typing.Iterable[RequestField]:
- """
- Iterate over fields.
-
- Supports list of (k, v) tuples and dicts, and lists of
- :class:`~urllib3.fields.RequestField`.
-
- """
- iterable: typing.Iterable[RequestField | tuple[str, _TYPE_FIELD_VALUE_TUPLE]]
-
- if isinstance(fields, typing.Mapping):
- iterable = fields.items()
- else:
- iterable = fields
-
- for field in iterable:
- if isinstance(field, RequestField):
- yield field
- else:
- yield RequestField.from_tuples(*field)
-
-
-def encode_multipart_formdata(
- fields: _TYPE_FIELDS, boundary: str | None = None
-) -> tuple[bytes, str]:
- """
- Encode a dictionary of ``fields`` using the multipart/form-data MIME format.
-
- :param fields:
- Dictionary of fields or list of (key, :class:`~urllib3.fields.RequestField`).
- Values are processed by :func:`urllib3.fields.RequestField.from_tuples`.
-
- :param boundary:
- If not specified, then a random boundary will be generated using
- :func:`urllib3.filepost.choose_boundary`.
- """
- body = BytesIO()
- if boundary is None:
- boundary = choose_boundary()
-
- for field in iter_field_objects(fields):
- body.write(f"--{boundary}\r\n".encode("latin-1"))
-
- writer(body).write(field.render_headers())
- data = field.data
-
- if isinstance(data, int):
- data = str(data) # Backwards compatibility
-
- if isinstance(data, str):
- writer(body).write(data)
- else:
- body.write(data)
-
- body.write(b"\r\n")
-
- body.write(f"--{boundary}--\r\n".encode("latin-1"))
-
- content_type = f"multipart/form-data; boundary={boundary}"
-
- return body.getvalue(), content_type
diff --git a/.venv/lib/python3.12/site-packages/urllib3/http2.py b/.venv/lib/python3.12/site-packages/urllib3/http2.py
deleted file mode 100644
index ceb4060..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/http2.py
+++ /dev/null
@@ -1,230 +0,0 @@
-from __future__ import annotations
-
-import threading
-import types
-import typing
-
-import h2.config # type: ignore[import-untyped]
-import h2.connection # type: ignore[import-untyped]
-import h2.events # type: ignore[import-untyped]
-
-import urllib3.connection
-import urllib3.util.ssl_
-from urllib3.response import BaseHTTPResponse
-
-from ._collections import HTTPHeaderDict
-from .connection import HTTPSConnection
-from .connectionpool import HTTPSConnectionPool
-
-orig_HTTPSConnection = HTTPSConnection
-
-T = typing.TypeVar("T")
-
-
-class _LockedObject(typing.Generic[T]):
- """
- A wrapper class that hides a specific object behind a lock.
-
- The goal here is to provide a simple way to protect access to an object
- that cannot safely be simultaneously accessed from multiple threads. The
- intended use of this class is simple: take hold of it with a context
- manager, which returns the protected object.
- """
-
- def __init__(self, obj: T):
- self.lock = threading.RLock()
- self._obj = obj
-
- def __enter__(self) -> T:
- self.lock.acquire()
- return self._obj
-
- def __exit__(
- self,
- exc_type: type[BaseException] | None,
- exc_val: BaseException | None,
- exc_tb: types.TracebackType | None,
- ) -> None:
- self.lock.release()
-
-
-class HTTP2Connection(HTTPSConnection):
- def __init__(
- self, host: str, port: int | None = None, **kwargs: typing.Any
- ) -> None:
- self._h2_conn = self._new_h2_conn()
- self._h2_stream: int | None = None
- self._h2_headers: list[tuple[bytes, bytes]] = []
-
- if "proxy" in kwargs or "proxy_config" in kwargs: # Defensive:
- raise NotImplementedError("Proxies aren't supported with HTTP/2")
-
- super().__init__(host, port, **kwargs)
-
- def _new_h2_conn(self) -> _LockedObject[h2.connection.H2Connection]:
- config = h2.config.H2Configuration(client_side=True)
- return _LockedObject(h2.connection.H2Connection(config=config))
-
- def connect(self) -> None:
- super().connect()
-
- with self._h2_conn as h2_conn:
- h2_conn.initiate_connection()
- self.sock.sendall(h2_conn.data_to_send())
-
- def putrequest(
- self,
- method: str,
- url: str,
- skip_host: bool = False,
- skip_accept_encoding: bool = False,
- ) -> None:
- with self._h2_conn as h2_conn:
- self._request_url = url
- self._h2_stream = h2_conn.get_next_available_stream_id()
-
- if ":" in self.host:
- authority = f"[{self.host}]:{self.port or 443}"
- else:
- authority = f"{self.host}:{self.port or 443}"
-
- self._h2_headers.extend(
- (
- (b":scheme", b"https"),
- (b":method", method.encode()),
- (b":authority", authority.encode()),
- (b":path", url.encode()),
- )
- )
-
- def putheader(self, header: str, *values: str) -> None: # type: ignore[override]
- for value in values:
- self._h2_headers.append(
- (header.encode("utf-8").lower(), value.encode("utf-8"))
- )
-
- def endheaders(self) -> None: # type: ignore[override]
- with self._h2_conn as h2_conn:
- h2_conn.send_headers(
- stream_id=self._h2_stream,
- headers=self._h2_headers,
- end_stream=True,
- )
- if data_to_send := h2_conn.data_to_send():
- self.sock.sendall(data_to_send)
-
- def send(self, data: bytes) -> None: # type: ignore[override] # Defensive:
- if not data:
- return
- raise NotImplementedError("Sending data isn't supported yet")
-
- def getresponse( # type: ignore[override]
- self,
- ) -> HTTP2Response:
- status = None
- data = bytearray()
- with self._h2_conn as h2_conn:
- end_stream = False
- while not end_stream:
- # TODO: Arbitrary read value.
- if received_data := self.sock.recv(65535):
- events = h2_conn.receive_data(received_data)
- for event in events:
- if isinstance(event, h2.events.ResponseReceived):
- headers = HTTPHeaderDict()
- for header, value in event.headers:
- if header == b":status":
- status = int(value.decode())
- else:
- headers.add(
- header.decode("ascii"), value.decode("ascii")
- )
-
- elif isinstance(event, h2.events.DataReceived):
- data += event.data
- h2_conn.acknowledge_received_data(
- event.flow_controlled_length, event.stream_id
- )
-
- elif isinstance(event, h2.events.StreamEnded):
- end_stream = True
-
- if data_to_send := h2_conn.data_to_send():
- self.sock.sendall(data_to_send)
-
- # We always close to not have to handle connection management.
- self.close()
-
- assert status is not None
- return HTTP2Response(
- status=status,
- headers=headers,
- request_url=self._request_url,
- data=bytes(data),
- )
-
- def close(self) -> None:
- with self._h2_conn as h2_conn:
- try:
- h2_conn.close_connection()
- if data := h2_conn.data_to_send():
- self.sock.sendall(data)
- except Exception:
- pass
-
- # Reset all our HTTP/2 connection state.
- self._h2_conn = self._new_h2_conn()
- self._h2_stream = None
- self._h2_headers = []
-
- super().close()
-
-
-class HTTP2Response(BaseHTTPResponse):
- # TODO: This is a woefully incomplete response object, but works for non-streaming.
- def __init__(
- self,
- status: int,
- headers: HTTPHeaderDict,
- request_url: str,
- data: bytes,
- decode_content: bool = False, # TODO: support decoding
- ) -> None:
- super().__init__(
- status=status,
- headers=headers,
- # Following CPython, we map HTTP versions to major * 10 + minor integers
- version=20,
- version_string="HTTP/2",
- # No reason phrase in HTTP/2
- reason=None,
- decode_content=decode_content,
- request_url=request_url,
- )
- self._data = data
- self.length_remaining = 0
-
- @property
- def data(self) -> bytes:
- return self._data
-
- def get_redirect_location(self) -> None:
- return None
-
- def close(self) -> None:
- pass
-
-
-def inject_into_urllib3() -> None:
- HTTPSConnectionPool.ConnectionCls = HTTP2Connection
- urllib3.connection.HTTPSConnection = HTTP2Connection # type: ignore[misc]
-
- # TODO: Offer 'http/1.1' as well, but for testing purposes this is handy.
- urllib3.util.ssl_.ALPN_PROTOCOLS = ["h2"]
-
-
-def extract_from_urllib3() -> None:
- HTTPSConnectionPool.ConnectionCls = orig_HTTPSConnection
- urllib3.connection.HTTPSConnection = orig_HTTPSConnection # type: ignore[misc]
-
- urllib3.util.ssl_.ALPN_PROTOCOLS = ["http/1.1"]
diff --git a/.venv/lib/python3.12/site-packages/urllib3/poolmanager.py b/.venv/lib/python3.12/site-packages/urllib3/poolmanager.py
deleted file mode 100644
index 085d1db..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/poolmanager.py
+++ /dev/null
@@ -1,637 +0,0 @@
-from __future__ import annotations
-
-import functools
-import logging
-import typing
-import warnings
-from types import TracebackType
-from urllib.parse import urljoin
-
-from ._collections import HTTPHeaderDict, RecentlyUsedContainer
-from ._request_methods import RequestMethods
-from .connection import ProxyConfig
-from .connectionpool import HTTPConnectionPool, HTTPSConnectionPool, port_by_scheme
-from .exceptions import (
- LocationValueError,
- MaxRetryError,
- ProxySchemeUnknown,
- URLSchemeUnknown,
-)
-from .response import BaseHTTPResponse
-from .util.connection import _TYPE_SOCKET_OPTIONS
-from .util.proxy import connection_requires_http_tunnel
-from .util.retry import Retry
-from .util.timeout import Timeout
-from .util.url import Url, parse_url
-
-if typing.TYPE_CHECKING:
- import ssl
-
- from typing_extensions import Self
-
-__all__ = ["PoolManager", "ProxyManager", "proxy_from_url"]
-
-
-log = logging.getLogger(__name__)
-
-SSL_KEYWORDS = (
- "key_file",
- "cert_file",
- "cert_reqs",
- "ca_certs",
- "ca_cert_data",
- "ssl_version",
- "ssl_minimum_version",
- "ssl_maximum_version",
- "ca_cert_dir",
- "ssl_context",
- "key_password",
- "server_hostname",
-)
-# Default value for `blocksize` - a new parameter introduced to
-# http.client.HTTPConnection & http.client.HTTPSConnection in Python 3.7
-_DEFAULT_BLOCKSIZE = 16384
-
-
-class PoolKey(typing.NamedTuple):
- """
- All known keyword arguments that could be provided to the pool manager, its
- pools, or the underlying connections.
-
- All custom key schemes should include the fields in this key at a minimum.
- """
-
- key_scheme: str
- key_host: str
- key_port: int | None
- key_timeout: Timeout | float | int | None
- key_retries: Retry | bool | int | None
- key_block: bool | None
- key_source_address: tuple[str, int] | None
- key_key_file: str | None
- key_key_password: str | None
- key_cert_file: str | None
- key_cert_reqs: str | None
- key_ca_certs: str | None
- key_ca_cert_data: str | bytes | None
- key_ssl_version: int | str | None
- key_ssl_minimum_version: ssl.TLSVersion | None
- key_ssl_maximum_version: ssl.TLSVersion | None
- key_ca_cert_dir: str | None
- key_ssl_context: ssl.SSLContext | None
- key_maxsize: int | None
- key_headers: frozenset[tuple[str, str]] | None
- key__proxy: Url | None
- key__proxy_headers: frozenset[tuple[str, str]] | None
- key__proxy_config: ProxyConfig | None
- key_socket_options: _TYPE_SOCKET_OPTIONS | None
- key__socks_options: frozenset[tuple[str, str]] | None
- key_assert_hostname: bool | str | None
- key_assert_fingerprint: str | None
- key_server_hostname: str | None
- key_blocksize: int | None
-
-
-def _default_key_normalizer(
- key_class: type[PoolKey], request_context: dict[str, typing.Any]
-) -> PoolKey:
- """
- Create a pool key out of a request context dictionary.
-
- According to RFC 3986, both the scheme and host are case-insensitive.
- Therefore, this function normalizes both before constructing the pool
- key for an HTTPS request. If you wish to change this behaviour, provide
- alternate callables to ``key_fn_by_scheme``.
-
- :param key_class:
- The class to use when constructing the key. This should be a namedtuple
- with the ``scheme`` and ``host`` keys at a minimum.
- :type key_class: namedtuple
- :param request_context:
- A dictionary-like object that contain the context for a request.
- :type request_context: dict
-
- :return: A namedtuple that can be used as a connection pool key.
- :rtype: PoolKey
- """
- # Since we mutate the dictionary, make a copy first
- context = request_context.copy()
- context["scheme"] = context["scheme"].lower()
- context["host"] = context["host"].lower()
-
- # These are both dictionaries and need to be transformed into frozensets
- for key in ("headers", "_proxy_headers", "_socks_options"):
- if key in context and context[key] is not None:
- context[key] = frozenset(context[key].items())
-
- # The socket_options key may be a list and needs to be transformed into a
- # tuple.
- socket_opts = context.get("socket_options")
- if socket_opts is not None:
- context["socket_options"] = tuple(socket_opts)
-
- # Map the kwargs to the names in the namedtuple - this is necessary since
- # namedtuples can't have fields starting with '_'.
- for key in list(context.keys()):
- context["key_" + key] = context.pop(key)
-
- # Default to ``None`` for keys missing from the context
- for field in key_class._fields:
- if field not in context:
- context[field] = None
-
- # Default key_blocksize to _DEFAULT_BLOCKSIZE if missing from the context
- if context.get("key_blocksize") is None:
- context["key_blocksize"] = _DEFAULT_BLOCKSIZE
-
- return key_class(**context)
-
-
-#: A dictionary that maps a scheme to a callable that creates a pool key.
-#: This can be used to alter the way pool keys are constructed, if desired.
-#: Each PoolManager makes a copy of this dictionary so they can be configured
-#: globally here, or individually on the instance.
-key_fn_by_scheme = {
- "http": functools.partial(_default_key_normalizer, PoolKey),
- "https": functools.partial(_default_key_normalizer, PoolKey),
-}
-
-pool_classes_by_scheme = {"http": HTTPConnectionPool, "https": HTTPSConnectionPool}
-
-
-class PoolManager(RequestMethods):
- """
- Allows for arbitrary requests while transparently keeping track of
- necessary connection pools for you.
-
- :param num_pools:
- Number of connection pools to cache before discarding the least
- recently used pool.
-
- :param headers:
- Headers to include with all requests, unless other headers are given
- explicitly.
-
- :param \\**connection_pool_kw:
- Additional parameters are used to create fresh
- :class:`urllib3.connectionpool.ConnectionPool` instances.
-
- Example:
-
- .. code-block:: python
-
- import urllib3
-
- http = urllib3.PoolManager(num_pools=2)
-
- resp1 = http.request("GET", "https://google.com/")
- resp2 = http.request("GET", "https://google.com/mail")
- resp3 = http.request("GET", "https://yahoo.com/")
-
- print(len(http.pools))
- # 2
-
- """
-
- proxy: Url | None = None
- proxy_config: ProxyConfig | None = None
-
- def __init__(
- self,
- num_pools: int = 10,
- headers: typing.Mapping[str, str] | None = None,
- **connection_pool_kw: typing.Any,
- ) -> None:
- super().__init__(headers)
- self.connection_pool_kw = connection_pool_kw
-
- self.pools: RecentlyUsedContainer[PoolKey, HTTPConnectionPool]
- self.pools = RecentlyUsedContainer(num_pools)
-
- # Locally set the pool classes and keys so other PoolManagers can
- # override them.
- self.pool_classes_by_scheme = pool_classes_by_scheme
- self.key_fn_by_scheme = key_fn_by_scheme.copy()
-
- def __enter__(self) -> Self:
- return self
-
- def __exit__(
- self,
- exc_type: type[BaseException] | None,
- exc_val: BaseException | None,
- exc_tb: TracebackType | None,
- ) -> typing.Literal[False]:
- self.clear()
- # Return False to re-raise any potential exceptions
- return False
-
- def _new_pool(
- self,
- scheme: str,
- host: str,
- port: int,
- request_context: dict[str, typing.Any] | None = None,
- ) -> HTTPConnectionPool:
- """
- Create a new :class:`urllib3.connectionpool.ConnectionPool` based on host, port, scheme, and
- any additional pool keyword arguments.
-
- If ``request_context`` is provided, it is provided as keyword arguments
- to the pool class used. This method is used to actually create the
- connection pools handed out by :meth:`connection_from_url` and
- companion methods. It is intended to be overridden for customization.
- """
- pool_cls: type[HTTPConnectionPool] = self.pool_classes_by_scheme[scheme]
- if request_context is None:
- request_context = self.connection_pool_kw.copy()
-
- # Default blocksize to _DEFAULT_BLOCKSIZE if missing or explicitly
- # set to 'None' in the request_context.
- if request_context.get("blocksize") is None:
- request_context["blocksize"] = _DEFAULT_BLOCKSIZE
-
- # Although the context has everything necessary to create the pool,
- # this function has historically only used the scheme, host, and port
- # in the positional args. When an API change is acceptable these can
- # be removed.
- for key in ("scheme", "host", "port"):
- request_context.pop(key, None)
-
- if scheme == "http":
- for kw in SSL_KEYWORDS:
- request_context.pop(kw, None)
-
- return pool_cls(host, port, **request_context)
-
- def clear(self) -> None:
- """
- Empty our store of pools and direct them all to close.
-
- This will not affect in-flight connections, but they will not be
- re-used after completion.
- """
- self.pools.clear()
-
- def connection_from_host(
- self,
- host: str | None,
- port: int | None = None,
- scheme: str | None = "http",
- pool_kwargs: dict[str, typing.Any] | None = None,
- ) -> HTTPConnectionPool:
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the host, port, and scheme.
-
- If ``port`` isn't given, it will be derived from the ``scheme`` using
- ``urllib3.connectionpool.port_by_scheme``. If ``pool_kwargs`` is
- provided, it is merged with the instance's ``connection_pool_kw``
- variable and used to create the new connection pool, if one is
- needed.
- """
-
- if not host:
- raise LocationValueError("No host specified.")
-
- request_context = self._merge_pool_kwargs(pool_kwargs)
- request_context["scheme"] = scheme or "http"
- if not port:
- port = port_by_scheme.get(request_context["scheme"].lower(), 80)
- request_context["port"] = port
- request_context["host"] = host
-
- return self.connection_from_context(request_context)
-
- def connection_from_context(
- self, request_context: dict[str, typing.Any]
- ) -> HTTPConnectionPool:
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the request context.
-
- ``request_context`` must at least contain the ``scheme`` key and its
- value must be a key in ``key_fn_by_scheme`` instance variable.
- """
- if "strict" in request_context:
- warnings.warn(
- "The 'strict' parameter is no longer needed on Python 3+. "
- "This will raise an error in urllib3 v2.1.0.",
- DeprecationWarning,
- )
- request_context.pop("strict")
-
- scheme = request_context["scheme"].lower()
- pool_key_constructor = self.key_fn_by_scheme.get(scheme)
- if not pool_key_constructor:
- raise URLSchemeUnknown(scheme)
- pool_key = pool_key_constructor(request_context)
-
- return self.connection_from_pool_key(pool_key, request_context=request_context)
-
- def connection_from_pool_key(
- self, pool_key: PoolKey, request_context: dict[str, typing.Any]
- ) -> HTTPConnectionPool:
- """
- Get a :class:`urllib3.connectionpool.ConnectionPool` based on the provided pool key.
-
- ``pool_key`` should be a namedtuple that only contains immutable
- objects. At a minimum it must have the ``scheme``, ``host``, and
- ``port`` fields.
- """
- with self.pools.lock:
- # If the scheme, host, or port doesn't match existing open
- # connections, open a new ConnectionPool.
- pool = self.pools.get(pool_key)
- if pool:
- return pool
-
- # Make a fresh ConnectionPool of the desired type
- scheme = request_context["scheme"]
- host = request_context["host"]
- port = request_context["port"]
- pool = self._new_pool(scheme, host, port, request_context=request_context)
- self.pools[pool_key] = pool
-
- return pool
-
- def connection_from_url(
- self, url: str, pool_kwargs: dict[str, typing.Any] | None = None
- ) -> HTTPConnectionPool:
- """
- Similar to :func:`urllib3.connectionpool.connection_from_url`.
-
- If ``pool_kwargs`` is not provided and a new pool needs to be
- constructed, ``self.connection_pool_kw`` is used to initialize
- the :class:`urllib3.connectionpool.ConnectionPool`. If ``pool_kwargs``
- is provided, it is used instead. Note that if a new pool does not
- need to be created for the request, the provided ``pool_kwargs`` are
- not used.
- """
- u = parse_url(url)
- return self.connection_from_host(
- u.host, port=u.port, scheme=u.scheme, pool_kwargs=pool_kwargs
- )
-
- def _merge_pool_kwargs(
- self, override: dict[str, typing.Any] | None
- ) -> dict[str, typing.Any]:
- """
- Merge a dictionary of override values for self.connection_pool_kw.
-
- This does not modify self.connection_pool_kw and returns a new dict.
- Any keys in the override dictionary with a value of ``None`` are
- removed from the merged dictionary.
- """
- base_pool_kwargs = self.connection_pool_kw.copy()
- if override:
- for key, value in override.items():
- if value is None:
- try:
- del base_pool_kwargs[key]
- except KeyError:
- pass
- else:
- base_pool_kwargs[key] = value
- return base_pool_kwargs
-
- def _proxy_requires_url_absolute_form(self, parsed_url: Url) -> bool:
- """
- Indicates if the proxy requires the complete destination URL in the
- request. Normally this is only needed when not using an HTTP CONNECT
- tunnel.
- """
- if self.proxy is None:
- return False
-
- return not connection_requires_http_tunnel(
- self.proxy, self.proxy_config, parsed_url.scheme
- )
-
- def urlopen( # type: ignore[override]
- self, method: str, url: str, redirect: bool = True, **kw: typing.Any
- ) -> BaseHTTPResponse:
- """
- Same as :meth:`urllib3.HTTPConnectionPool.urlopen`
- with custom cross-host redirect logic and only sends the request-uri
- portion of the ``url``.
-
- The given ``url`` parameter must be absolute, such that an appropriate
- :class:`urllib3.connectionpool.ConnectionPool` can be chosen for it.
- """
- u = parse_url(url)
-
- if u.scheme is None:
- warnings.warn(
- "URLs without a scheme (ie 'https://') are deprecated and will raise an error "
- "in a future version of urllib3. To avoid this DeprecationWarning ensure all URLs "
- "start with 'https://' or 'http://'. Read more in this issue: "
- "https://github.com/urllib3/urllib3/issues/2920",
- category=DeprecationWarning,
- stacklevel=2,
- )
-
- conn = self.connection_from_host(u.host, port=u.port, scheme=u.scheme)
-
- kw["assert_same_host"] = False
- kw["redirect"] = False
-
- if "headers" not in kw:
- kw["headers"] = self.headers
-
- if self._proxy_requires_url_absolute_form(u):
- response = conn.urlopen(method, url, **kw)
- else:
- response = conn.urlopen(method, u.request_uri, **kw)
-
- redirect_location = redirect and response.get_redirect_location()
- if not redirect_location:
- return response
-
- # Support relative URLs for redirecting.
- redirect_location = urljoin(url, redirect_location)
-
- if response.status == 303:
- # Change the method according to RFC 9110, Section 15.4.4.
- method = "GET"
- # And lose the body not to transfer anything sensitive.
- kw["body"] = None
- kw["headers"] = HTTPHeaderDict(kw["headers"])._prepare_for_method_change()
-
- retries = kw.get("retries")
- if not isinstance(retries, Retry):
- retries = Retry.from_int(retries, redirect=redirect)
-
- # Strip headers marked as unsafe to forward to the redirected location.
- # Check remove_headers_on_redirect to avoid a potential network call within
- # conn.is_same_host() which may use socket.gethostbyname() in the future.
- if retries.remove_headers_on_redirect and not conn.is_same_host(
- redirect_location
- ):
- new_headers = kw["headers"].copy()
- for header in kw["headers"]:
- if header.lower() in retries.remove_headers_on_redirect:
- new_headers.pop(header, None)
- kw["headers"] = new_headers
-
- try:
- retries = retries.increment(method, url, response=response, _pool=conn)
- except MaxRetryError:
- if retries.raise_on_redirect:
- response.drain_conn()
- raise
- return response
-
- kw["retries"] = retries
- kw["redirect"] = redirect
-
- log.info("Redirecting %s -> %s", url, redirect_location)
-
- response.drain_conn()
- return self.urlopen(method, redirect_location, **kw)
-
-
-class ProxyManager(PoolManager):
- """
- Behaves just like :class:`PoolManager`, but sends all requests through
- the defined proxy, using the CONNECT method for HTTPS URLs.
-
- :param proxy_url:
- The URL of the proxy to be used.
-
- :param proxy_headers:
- A dictionary containing headers that will be sent to the proxy. In case
- of HTTP they are being sent with each request, while in the
- HTTPS/CONNECT case they are sent only once. Could be used for proxy
- authentication.
-
- :param proxy_ssl_context:
- The proxy SSL context is used to establish the TLS connection to the
- proxy when using HTTPS proxies.
-
- :param use_forwarding_for_https:
- (Defaults to False) If set to True will forward requests to the HTTPS
- proxy to be made on behalf of the client instead of creating a TLS
- tunnel via the CONNECT method. **Enabling this flag means that request
- and response headers and content will be visible from the HTTPS proxy**
- whereas tunneling keeps request and response headers and content
- private. IP address, target hostname, SNI, and port are always visible
- to an HTTPS proxy even when this flag is disabled.
-
- :param proxy_assert_hostname:
- The hostname of the certificate to verify against.
-
- :param proxy_assert_fingerprint:
- The fingerprint of the certificate to verify against.
-
- Example:
-
- .. code-block:: python
-
- import urllib3
-
- proxy = urllib3.ProxyManager("https://localhost:3128/")
-
- resp1 = proxy.request("GET", "https://google.com/")
- resp2 = proxy.request("GET", "https://httpbin.org/")
-
- print(len(proxy.pools))
- # 1
-
- resp3 = proxy.request("GET", "https://httpbin.org/")
- resp4 = proxy.request("GET", "https://twitter.com/")
-
- print(len(proxy.pools))
- # 3
-
- """
-
- def __init__(
- self,
- proxy_url: str,
- num_pools: int = 10,
- headers: typing.Mapping[str, str] | None = None,
- proxy_headers: typing.Mapping[str, str] | None = None,
- proxy_ssl_context: ssl.SSLContext | None = None,
- use_forwarding_for_https: bool = False,
- proxy_assert_hostname: None | str | typing.Literal[False] = None,
- proxy_assert_fingerprint: str | None = None,
- **connection_pool_kw: typing.Any,
- ) -> None:
- if isinstance(proxy_url, HTTPConnectionPool):
- str_proxy_url = f"{proxy_url.scheme}://{proxy_url.host}:{proxy_url.port}"
- else:
- str_proxy_url = proxy_url
- proxy = parse_url(str_proxy_url)
-
- if proxy.scheme not in ("http", "https"):
- raise ProxySchemeUnknown(proxy.scheme)
-
- if not proxy.port:
- port = port_by_scheme.get(proxy.scheme, 80)
- proxy = proxy._replace(port=port)
-
- self.proxy = proxy
- self.proxy_headers = proxy_headers or {}
- self.proxy_ssl_context = proxy_ssl_context
- self.proxy_config = ProxyConfig(
- proxy_ssl_context,
- use_forwarding_for_https,
- proxy_assert_hostname,
- proxy_assert_fingerprint,
- )
-
- connection_pool_kw["_proxy"] = self.proxy
- connection_pool_kw["_proxy_headers"] = self.proxy_headers
- connection_pool_kw["_proxy_config"] = self.proxy_config
-
- super().__init__(num_pools, headers, **connection_pool_kw)
-
- def connection_from_host(
- self,
- host: str | None,
- port: int | None = None,
- scheme: str | None = "http",
- pool_kwargs: dict[str, typing.Any] | None = None,
- ) -> HTTPConnectionPool:
- if scheme == "https":
- return super().connection_from_host(
- host, port, scheme, pool_kwargs=pool_kwargs
- )
-
- return super().connection_from_host(
- self.proxy.host, self.proxy.port, self.proxy.scheme, pool_kwargs=pool_kwargs # type: ignore[union-attr]
- )
-
- def _set_proxy_headers(
- self, url: str, headers: typing.Mapping[str, str] | None = None
- ) -> typing.Mapping[str, str]:
- """
- Sets headers needed by proxies: specifically, the Accept and Host
- headers. Only sets headers not provided by the user.
- """
- headers_ = {"Accept": "*/*"}
-
- netloc = parse_url(url).netloc
- if netloc:
- headers_["Host"] = netloc
-
- if headers:
- headers_.update(headers)
- return headers_
-
- def urlopen( # type: ignore[override]
- self, method: str, url: str, redirect: bool = True, **kw: typing.Any
- ) -> BaseHTTPResponse:
- "Same as HTTP(S)ConnectionPool.urlopen, ``url`` must be absolute."
- u = parse_url(url)
- if not connection_requires_http_tunnel(self.proxy, self.proxy_config, u.scheme):
- # For connections using HTTP CONNECT, httplib sets the necessary
- # headers on the CONNECT to the proxy. If we're not using CONNECT,
- # we'll definitely need to set 'Host' at the very least.
- headers = kw.get("headers", self.headers)
- kw["headers"] = self._set_proxy_headers(url, headers)
-
- return super().urlopen(method, url, redirect=redirect, **kw)
-
-
-def proxy_from_url(url: str, **kw: typing.Any) -> ProxyManager:
- return ProxyManager(proxy_url=url, **kw)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/py.typed b/.venv/lib/python3.12/site-packages/urllib3/py.typed
deleted file mode 100644
index 5f3ea3d..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/py.typed
+++ /dev/null
@@ -1,2 +0,0 @@
-# Instruct type checkers to look for inline type annotations in this package.
-# See PEP 561.
diff --git a/.venv/lib/python3.12/site-packages/urllib3/response.py b/.venv/lib/python3.12/site-packages/urllib3/response.py
deleted file mode 100644
index a0273d6..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/response.py
+++ /dev/null
@@ -1,1265 +0,0 @@
-from __future__ import annotations
-
-import collections
-import io
-import json as _json
-import logging
-import re
-import sys
-import typing
-import warnings
-import zlib
-from contextlib import contextmanager
-from http.client import HTTPMessage as _HttplibHTTPMessage
-from http.client import HTTPResponse as _HttplibHTTPResponse
-from socket import timeout as SocketTimeout
-
-if typing.TYPE_CHECKING:
- from ._base_connection import BaseHTTPConnection
-
-try:
- try:
- import brotlicffi as brotli # type: ignore[import-not-found]
- except ImportError:
- import brotli # type: ignore[import-not-found]
-except ImportError:
- brotli = None
-
-try:
- import zstandard as zstd
-except (AttributeError, ImportError, ValueError): # Defensive:
- HAS_ZSTD = False
-else:
- # The package 'zstandard' added the 'eof' property starting
- # in v0.18.0 which we require to ensure a complete and
- # valid zstd stream was fed into the ZstdDecoder.
- # See: https://github.com/urllib3/urllib3/pull/2624
- _zstd_version = tuple(
- map(int, re.search(r"^([0-9]+)\.([0-9]+)", zstd.__version__).groups()) # type: ignore[union-attr]
- )
- if _zstd_version < (0, 18): # Defensive:
- HAS_ZSTD = False
- else:
- HAS_ZSTD = True
-
-from . import util
-from ._base_connection import _TYPE_BODY
-from ._collections import HTTPHeaderDict
-from .connection import BaseSSLError, HTTPConnection, HTTPException
-from .exceptions import (
- BodyNotHttplibCompatible,
- DecodeError,
- HTTPError,
- IncompleteRead,
- InvalidChunkLength,
- InvalidHeader,
- ProtocolError,
- ReadTimeoutError,
- ResponseNotChunked,
- SSLError,
-)
-from .util.response import is_fp_closed, is_response_to_head
-from .util.retry import Retry
-
-if typing.TYPE_CHECKING:
- from .connectionpool import HTTPConnectionPool
-
-log = logging.getLogger(__name__)
-
-
-class ContentDecoder:
- def decompress(self, data: bytes) -> bytes:
- raise NotImplementedError()
-
- def flush(self) -> bytes:
- raise NotImplementedError()
-
-
-class DeflateDecoder(ContentDecoder):
- def __init__(self) -> None:
- self._first_try = True
- self._data = b""
- self._obj = zlib.decompressobj()
-
- def decompress(self, data: bytes) -> bytes:
- if not data:
- return data
-
- if not self._first_try:
- return self._obj.decompress(data)
-
- self._data += data
- try:
- decompressed = self._obj.decompress(data)
- if decompressed:
- self._first_try = False
- self._data = None # type: ignore[assignment]
- return decompressed
- except zlib.error:
- self._first_try = False
- self._obj = zlib.decompressobj(-zlib.MAX_WBITS)
- try:
- return self.decompress(self._data)
- finally:
- self._data = None # type: ignore[assignment]
-
- def flush(self) -> bytes:
- return self._obj.flush()
-
-
-class GzipDecoderState:
- FIRST_MEMBER = 0
- OTHER_MEMBERS = 1
- SWALLOW_DATA = 2
-
-
-class GzipDecoder(ContentDecoder):
- def __init__(self) -> None:
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
- self._state = GzipDecoderState.FIRST_MEMBER
-
- def decompress(self, data: bytes) -> bytes:
- ret = bytearray()
- if self._state == GzipDecoderState.SWALLOW_DATA or not data:
- return bytes(ret)
- while True:
- try:
- ret += self._obj.decompress(data)
- except zlib.error:
- previous_state = self._state
- # Ignore data after the first error
- self._state = GzipDecoderState.SWALLOW_DATA
- if previous_state == GzipDecoderState.OTHER_MEMBERS:
- # Allow trailing garbage acceptable in other gzip clients
- return bytes(ret)
- raise
- data = self._obj.unused_data
- if not data:
- return bytes(ret)
- self._state = GzipDecoderState.OTHER_MEMBERS
- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS)
-
- def flush(self) -> bytes:
- return self._obj.flush()
-
-
-if brotli is not None:
-
- class BrotliDecoder(ContentDecoder):
- # Supports both 'brotlipy' and 'Brotli' packages
- # since they share an import name. The top branches
- # are for 'brotlipy' and bottom branches for 'Brotli'
- def __init__(self) -> None:
- self._obj = brotli.Decompressor()
- if hasattr(self._obj, "decompress"):
- setattr(self, "decompress", self._obj.decompress)
- else:
- setattr(self, "decompress", self._obj.process)
-
- def flush(self) -> bytes:
- if hasattr(self._obj, "flush"):
- return self._obj.flush() # type: ignore[no-any-return]
- return b""
-
-
-if HAS_ZSTD:
-
- class ZstdDecoder(ContentDecoder):
- def __init__(self) -> None:
- self._obj = zstd.ZstdDecompressor().decompressobj()
-
- def decompress(self, data: bytes) -> bytes:
- if not data:
- return b""
- data_parts = [self._obj.decompress(data)]
- while self._obj.eof and self._obj.unused_data:
- unused_data = self._obj.unused_data
- self._obj = zstd.ZstdDecompressor().decompressobj()
- data_parts.append(self._obj.decompress(unused_data))
- return b"".join(data_parts)
-
- def flush(self) -> bytes:
- ret = self._obj.flush() # note: this is a no-op
- if not self._obj.eof:
- raise DecodeError("Zstandard data is incomplete")
- return ret
-
-
-class MultiDecoder(ContentDecoder):
- """
- From RFC7231:
- If one or more encodings have been applied to a representation, the
- sender that applied the encodings MUST generate a Content-Encoding
- header field that lists the content codings in the order in which
- they were applied.
- """
-
- def __init__(self, modes: str) -> None:
- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")]
-
- def flush(self) -> bytes:
- return self._decoders[0].flush()
-
- def decompress(self, data: bytes) -> bytes:
- for d in reversed(self._decoders):
- data = d.decompress(data)
- return data
-
-
-def _get_decoder(mode: str) -> ContentDecoder:
- if "," in mode:
- return MultiDecoder(mode)
-
- # According to RFC 9110 section 8.4.1.3, recipients should
- # consider x-gzip equivalent to gzip
- if mode in ("gzip", "x-gzip"):
- return GzipDecoder()
-
- if brotli is not None and mode == "br":
- return BrotliDecoder()
-
- if HAS_ZSTD and mode == "zstd":
- return ZstdDecoder()
-
- return DeflateDecoder()
-
-
-class BytesQueueBuffer:
- """Memory-efficient bytes buffer
-
- To return decoded data in read() and still follow the BufferedIOBase API, we need a
- buffer to always return the correct amount of bytes.
-
- This buffer should be filled using calls to put()
-
- Our maximum memory usage is determined by the sum of the size of:
-
- * self.buffer, which contains the full data
- * the largest chunk that we will copy in get()
-
- The worst case scenario is a single chunk, in which case we'll make a full copy of
- the data inside get().
- """
-
- def __init__(self) -> None:
- self.buffer: typing.Deque[bytes] = collections.deque()
- self._size: int = 0
-
- def __len__(self) -> int:
- return self._size
-
- def put(self, data: bytes) -> None:
- self.buffer.append(data)
- self._size += len(data)
-
- def get(self, n: int) -> bytes:
- if n == 0:
- return b""
- elif not self.buffer:
- raise RuntimeError("buffer is empty")
- elif n < 0:
- raise ValueError("n should be > 0")
-
- fetched = 0
- ret = io.BytesIO()
- while fetched < n:
- remaining = n - fetched
- chunk = self.buffer.popleft()
- chunk_length = len(chunk)
- if remaining < chunk_length:
- left_chunk, right_chunk = chunk[:remaining], chunk[remaining:]
- ret.write(left_chunk)
- self.buffer.appendleft(right_chunk)
- self._size -= remaining
- break
- else:
- ret.write(chunk)
- self._size -= chunk_length
- fetched += chunk_length
-
- if not self.buffer:
- break
-
- return ret.getvalue()
-
- def get_all(self) -> bytes:
- buffer = self.buffer
- if not buffer:
- assert self._size == 0
- return b""
- if len(buffer) == 1:
- result = buffer.pop()
- else:
- ret = io.BytesIO()
- ret.writelines(buffer.popleft() for _ in range(len(buffer)))
- result = ret.getvalue()
- self._size = 0
- return result
-
-
-class BaseHTTPResponse(io.IOBase):
- CONTENT_DECODERS = ["gzip", "x-gzip", "deflate"]
- if brotli is not None:
- CONTENT_DECODERS += ["br"]
- if HAS_ZSTD:
- CONTENT_DECODERS += ["zstd"]
- REDIRECT_STATUSES = [301, 302, 303, 307, 308]
-
- DECODER_ERROR_CLASSES: tuple[type[Exception], ...] = (IOError, zlib.error)
- if brotli is not None:
- DECODER_ERROR_CLASSES += (brotli.error,)
-
- if HAS_ZSTD:
- DECODER_ERROR_CLASSES += (zstd.ZstdError,)
-
- def __init__(
- self,
- *,
- headers: typing.Mapping[str, str] | typing.Mapping[bytes, bytes] | None = None,
- status: int,
- version: int,
- version_string: str,
- reason: str | None,
- decode_content: bool,
- request_url: str | None,
- retries: Retry | None = None,
- ) -> None:
- if isinstance(headers, HTTPHeaderDict):
- self.headers = headers
- else:
- self.headers = HTTPHeaderDict(headers) # type: ignore[arg-type]
- self.status = status
- self.version = version
- self.version_string = version_string
- self.reason = reason
- self.decode_content = decode_content
- self._has_decoded_content = False
- self._request_url: str | None = request_url
- self.retries = retries
-
- self.chunked = False
- tr_enc = self.headers.get("transfer-encoding", "").lower()
- # Don't incur the penalty of creating a list and then discarding it
- encodings = (enc.strip() for enc in tr_enc.split(","))
- if "chunked" in encodings:
- self.chunked = True
-
- self._decoder: ContentDecoder | None = None
- self.length_remaining: int | None
-
- def get_redirect_location(self) -> str | None | typing.Literal[False]:
- """
- Should we redirect and where to?
-
- :returns: Truthy redirect location string if we got a redirect status
- code and valid location. ``None`` if redirect status and no
- location. ``False`` if not a redirect status code.
- """
- if self.status in self.REDIRECT_STATUSES:
- return self.headers.get("location")
- return False
-
- @property
- def data(self) -> bytes:
- raise NotImplementedError()
-
- def json(self) -> typing.Any:
- """
- Deserializes the body of the HTTP response as a Python object.
-
- The body of the HTTP response must be encoded using UTF-8, as per
- `RFC 8529 Section 8.1 `_.
-
- To use a custom JSON decoder pass the result of :attr:`HTTPResponse.data` to
- your custom decoder instead.
-
- If the body of the HTTP response is not decodable to UTF-8, a
- `UnicodeDecodeError` will be raised. If the body of the HTTP response is not a
- valid JSON document, a `json.JSONDecodeError` will be raised.
-
- Read more :ref:`here `.
-
- :returns: The body of the HTTP response as a Python object.
- """
- data = self.data.decode("utf-8")
- return _json.loads(data)
-
- @property
- def url(self) -> str | None:
- raise NotImplementedError()
-
- @url.setter
- def url(self, url: str | None) -> None:
- raise NotImplementedError()
-
- @property
- def connection(self) -> BaseHTTPConnection | None:
- raise NotImplementedError()
-
- @property
- def retries(self) -> Retry | None:
- return self._retries
-
- @retries.setter
- def retries(self, retries: Retry | None) -> None:
- # Override the request_url if retries has a redirect location.
- if retries is not None and retries.history:
- self.url = retries.history[-1].redirect_location
- self._retries = retries
-
- def stream(
- self, amt: int | None = 2**16, decode_content: bool | None = None
- ) -> typing.Iterator[bytes]:
- raise NotImplementedError()
-
- def read(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- cache_content: bool = False,
- ) -> bytes:
- raise NotImplementedError()
-
- def read1(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- ) -> bytes:
- raise NotImplementedError()
-
- def read_chunked(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- ) -> typing.Iterator[bytes]:
- raise NotImplementedError()
-
- def release_conn(self) -> None:
- raise NotImplementedError()
-
- def drain_conn(self) -> None:
- raise NotImplementedError()
-
- def close(self) -> None:
- raise NotImplementedError()
-
- def _init_decoder(self) -> None:
- """
- Set-up the _decoder attribute if necessary.
- """
- # Note: content-encoding value should be case-insensitive, per RFC 7230
- # Section 3.2
- content_encoding = self.headers.get("content-encoding", "").lower()
- if self._decoder is None:
- if content_encoding in self.CONTENT_DECODERS:
- self._decoder = _get_decoder(content_encoding)
- elif "," in content_encoding:
- encodings = [
- e.strip()
- for e in content_encoding.split(",")
- if e.strip() in self.CONTENT_DECODERS
- ]
- if encodings:
- self._decoder = _get_decoder(content_encoding)
-
- def _decode(
- self, data: bytes, decode_content: bool | None, flush_decoder: bool
- ) -> bytes:
- """
- Decode the data passed in and potentially flush the decoder.
- """
- if not decode_content:
- if self._has_decoded_content:
- raise RuntimeError(
- "Calling read(decode_content=False) is not supported after "
- "read(decode_content=True) was called."
- )
- return data
-
- try:
- if self._decoder:
- data = self._decoder.decompress(data)
- self._has_decoded_content = True
- except self.DECODER_ERROR_CLASSES as e:
- content_encoding = self.headers.get("content-encoding", "").lower()
- raise DecodeError(
- "Received response with content-encoding: %s, but "
- "failed to decode it." % content_encoding,
- e,
- ) from e
- if flush_decoder:
- data += self._flush_decoder()
-
- return data
-
- def _flush_decoder(self) -> bytes:
- """
- Flushes the decoder. Should only be called if the decoder is actually
- being used.
- """
- if self._decoder:
- return self._decoder.decompress(b"") + self._decoder.flush()
- return b""
-
- # Compatibility methods for `io` module
- def readinto(self, b: bytearray) -> int:
- temp = self.read(len(b))
- if len(temp) == 0:
- return 0
- else:
- b[: len(temp)] = temp
- return len(temp)
-
- # Compatibility methods for http.client.HTTPResponse
- def getheaders(self) -> HTTPHeaderDict:
- warnings.warn(
- "HTTPResponse.getheaders() is deprecated and will be removed "
- "in urllib3 v2.1.0. Instead access HTTPResponse.headers directly.",
- category=DeprecationWarning,
- stacklevel=2,
- )
- return self.headers
-
- def getheader(self, name: str, default: str | None = None) -> str | None:
- warnings.warn(
- "HTTPResponse.getheader() is deprecated and will be removed "
- "in urllib3 v2.1.0. Instead use HTTPResponse.headers.get(name, default).",
- category=DeprecationWarning,
- stacklevel=2,
- )
- return self.headers.get(name, default)
-
- # Compatibility method for http.cookiejar
- def info(self) -> HTTPHeaderDict:
- return self.headers
-
- def geturl(self) -> str | None:
- return self.url
-
-
-class HTTPResponse(BaseHTTPResponse):
- """
- HTTP Response container.
-
- Backwards-compatible with :class:`http.client.HTTPResponse` but the response ``body`` is
- loaded and decoded on-demand when the ``data`` property is accessed. This
- class is also compatible with the Python standard library's :mod:`io`
- module, and can hence be treated as a readable object in the context of that
- framework.
-
- Extra parameters for behaviour not present in :class:`http.client.HTTPResponse`:
-
- :param preload_content:
- If True, the response's body will be preloaded during construction.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param original_response:
- When this HTTPResponse wrapper is generated from an :class:`http.client.HTTPResponse`
- object, it's convenient to include the original for debug purposes. It's
- otherwise unused.
-
- :param retries:
- The retries contains the last :class:`~urllib3.util.retry.Retry` that
- was used during the request.
-
- :param enforce_content_length:
- Enforce content length checking. Body returned by server must match
- value of Content-Length header, if present. Otherwise, raise error.
- """
-
- def __init__(
- self,
- body: _TYPE_BODY = "",
- headers: typing.Mapping[str, str] | typing.Mapping[bytes, bytes] | None = None,
- status: int = 0,
- version: int = 0,
- version_string: str = "HTTP/?",
- reason: str | None = None,
- preload_content: bool = True,
- decode_content: bool = True,
- original_response: _HttplibHTTPResponse | None = None,
- pool: HTTPConnectionPool | None = None,
- connection: HTTPConnection | None = None,
- msg: _HttplibHTTPMessage | None = None,
- retries: Retry | None = None,
- enforce_content_length: bool = True,
- request_method: str | None = None,
- request_url: str | None = None,
- auto_close: bool = True,
- ) -> None:
- super().__init__(
- headers=headers,
- status=status,
- version=version,
- version_string=version_string,
- reason=reason,
- decode_content=decode_content,
- request_url=request_url,
- retries=retries,
- )
-
- self.enforce_content_length = enforce_content_length
- self.auto_close = auto_close
-
- self._body = None
- self._fp: _HttplibHTTPResponse | None = None
- self._original_response = original_response
- self._fp_bytes_read = 0
- self.msg = msg
-
- if body and isinstance(body, (str, bytes)):
- self._body = body
-
- self._pool = pool
- self._connection = connection
-
- if hasattr(body, "read"):
- self._fp = body # type: ignore[assignment]
-
- # Are we using the chunked-style of transfer encoding?
- self.chunk_left: int | None = None
-
- # Determine length of response
- self.length_remaining = self._init_length(request_method)
-
- # Used to return the correct amount of bytes for partial read()s
- self._decoded_buffer = BytesQueueBuffer()
-
- # If requested, preload the body.
- if preload_content and not self._body:
- self._body = self.read(decode_content=decode_content)
-
- def release_conn(self) -> None:
- if not self._pool or not self._connection:
- return None
-
- self._pool._put_conn(self._connection)
- self._connection = None
-
- def drain_conn(self) -> None:
- """
- Read and discard any remaining HTTP response data in the response connection.
-
- Unread data in the HTTPResponse connection blocks the connection from being released back to the pool.
- """
- try:
- self.read()
- except (HTTPError, OSError, BaseSSLError, HTTPException):
- pass
-
- @property
- def data(self) -> bytes:
- # For backwards-compat with earlier urllib3 0.4 and earlier.
- if self._body:
- return self._body # type: ignore[return-value]
-
- if self._fp:
- return self.read(cache_content=True)
-
- return None # type: ignore[return-value]
-
- @property
- def connection(self) -> HTTPConnection | None:
- return self._connection
-
- def isclosed(self) -> bool:
- return is_fp_closed(self._fp)
-
- def tell(self) -> int:
- """
- Obtain the number of bytes pulled over the wire so far. May differ from
- the amount of content returned by :meth:``urllib3.response.HTTPResponse.read``
- if bytes are encoded on the wire (e.g, compressed).
- """
- return self._fp_bytes_read
-
- def _init_length(self, request_method: str | None) -> int | None:
- """
- Set initial length value for Response content if available.
- """
- length: int | None
- content_length: str | None = self.headers.get("content-length")
-
- if content_length is not None:
- if self.chunked:
- # This Response will fail with an IncompleteRead if it can't be
- # received as chunked. This method falls back to attempt reading
- # the response before raising an exception.
- log.warning(
- "Received response with both Content-Length and "
- "Transfer-Encoding set. This is expressly forbidden "
- "by RFC 7230 sec 3.3.2. Ignoring Content-Length and "
- "attempting to process response as Transfer-Encoding: "
- "chunked."
- )
- return None
-
- try:
- # RFC 7230 section 3.3.2 specifies multiple content lengths can
- # be sent in a single Content-Length header
- # (e.g. Content-Length: 42, 42). This line ensures the values
- # are all valid ints and that as long as the `set` length is 1,
- # all values are the same. Otherwise, the header is invalid.
- lengths = {int(val) for val in content_length.split(",")}
- if len(lengths) > 1:
- raise InvalidHeader(
- "Content-Length contained multiple "
- "unmatching values (%s)" % content_length
- )
- length = lengths.pop()
- except ValueError:
- length = None
- else:
- if length < 0:
- length = None
-
- else: # if content_length is None
- length = None
-
- # Convert status to int for comparison
- # In some cases, httplib returns a status of "_UNKNOWN"
- try:
- status = int(self.status)
- except ValueError:
- status = 0
-
- # Check for responses that shouldn't include a body
- if status in (204, 304) or 100 <= status < 200 or request_method == "HEAD":
- length = 0
-
- return length
-
- @contextmanager
- def _error_catcher(self) -> typing.Generator[None, None, None]:
- """
- Catch low-level python exceptions, instead re-raising urllib3
- variants, so that low-level exceptions are not leaked in the
- high-level api.
-
- On exit, release the connection back to the pool.
- """
- clean_exit = False
-
- try:
- try:
- yield
-
- except SocketTimeout as e:
- # FIXME: Ideally we'd like to include the url in the ReadTimeoutError but
- # there is yet no clean way to get at it from this context.
- raise ReadTimeoutError(self._pool, None, "Read timed out.") from e # type: ignore[arg-type]
-
- except BaseSSLError as e:
- # FIXME: Is there a better way to differentiate between SSLErrors?
- if "read operation timed out" not in str(e):
- # SSL errors related to framing/MAC get wrapped and reraised here
- raise SSLError(e) from e
-
- raise ReadTimeoutError(self._pool, None, "Read timed out.") from e # type: ignore[arg-type]
-
- except IncompleteRead as e:
- if (
- e.expected is not None
- and e.partial is not None
- and e.expected == -e.partial
- ):
- arg = "Response may not contain content."
- else:
- arg = f"Connection broken: {e!r}"
- raise ProtocolError(arg, e) from e
-
- except (HTTPException, OSError) as e:
- raise ProtocolError(f"Connection broken: {e!r}", e) from e
-
- # If no exception is thrown, we should avoid cleaning up
- # unnecessarily.
- clean_exit = True
- finally:
- # If we didn't terminate cleanly, we need to throw away our
- # connection.
- if not clean_exit:
- # The response may not be closed but we're not going to use it
- # anymore so close it now to ensure that the connection is
- # released back to the pool.
- if self._original_response:
- self._original_response.close()
-
- # Closing the response may not actually be sufficient to close
- # everything, so if we have a hold of the connection close that
- # too.
- if self._connection:
- self._connection.close()
-
- # If we hold the original response but it's closed now, we should
- # return the connection back to the pool.
- if self._original_response and self._original_response.isclosed():
- self.release_conn()
-
- def _fp_read(
- self,
- amt: int | None = None,
- *,
- read1: bool = False,
- ) -> bytes:
- """
- Read a response with the thought that reading the number of bytes
- larger than can fit in a 32-bit int at a time via SSL in some
- known cases leads to an overflow error that has to be prevented
- if `amt` or `self.length_remaining` indicate that a problem may
- happen.
-
- The known cases:
- * 3.8 <= CPython < 3.9.7 because of a bug
- https://github.com/urllib3/urllib3/issues/2513#issuecomment-1152559900.
- * urllib3 injected with pyOpenSSL-backed SSL-support.
- * CPython < 3.10 only when `amt` does not fit 32-bit int.
- """
- assert self._fp
- c_int_max = 2**31 - 1
- if (
- (amt and amt > c_int_max)
- or (
- amt is None
- and self.length_remaining
- and self.length_remaining > c_int_max
- )
- ) and (util.IS_PYOPENSSL or sys.version_info < (3, 10)):
- if read1:
- return self._fp.read1(c_int_max)
- buffer = io.BytesIO()
- # Besides `max_chunk_amt` being a maximum chunk size, it
- # affects memory overhead of reading a response by this
- # method in CPython.
- # `c_int_max` equal to 2 GiB - 1 byte is the actual maximum
- # chunk size that does not lead to an overflow error, but
- # 256 MiB is a compromise.
- max_chunk_amt = 2**28
- while amt is None or amt != 0:
- if amt is not None:
- chunk_amt = min(amt, max_chunk_amt)
- amt -= chunk_amt
- else:
- chunk_amt = max_chunk_amt
- data = self._fp.read(chunk_amt)
- if not data:
- break
- buffer.write(data)
- del data # to reduce peak memory usage by `max_chunk_amt`.
- return buffer.getvalue()
- elif read1:
- return self._fp.read1(amt) if amt is not None else self._fp.read1()
- else:
- # StringIO doesn't like amt=None
- return self._fp.read(amt) if amt is not None else self._fp.read()
-
- def _raw_read(
- self,
- amt: int | None = None,
- *,
- read1: bool = False,
- ) -> bytes:
- """
- Reads `amt` of bytes from the socket.
- """
- if self._fp is None:
- return None # type: ignore[return-value]
-
- fp_closed = getattr(self._fp, "closed", False)
-
- with self._error_catcher():
- data = self._fp_read(amt, read1=read1) if not fp_closed else b""
- if amt is not None and amt != 0 and not data:
- # Platform-specific: Buggy versions of Python.
- # Close the connection when no data is returned
- #
- # This is redundant to what httplib/http.client _should_
- # already do. However, versions of python released before
- # December 15, 2012 (http://bugs.python.org/issue16298) do
- # not properly close the connection in all cases. There is
- # no harm in redundantly calling close.
- self._fp.close()
- if (
- self.enforce_content_length
- and self.length_remaining is not None
- and self.length_remaining != 0
- ):
- # This is an edge case that httplib failed to cover due
- # to concerns of backward compatibility. We're
- # addressing it here to make sure IncompleteRead is
- # raised during streaming, so all calls with incorrect
- # Content-Length are caught.
- raise IncompleteRead(self._fp_bytes_read, self.length_remaining)
- elif read1 and (
- (amt != 0 and not data) or self.length_remaining == len(data)
- ):
- # All data has been read, but `self._fp.read1` in
- # CPython 3.12 and older doesn't always close
- # `http.client.HTTPResponse`, so we close it here.
- # See https://github.com/python/cpython/issues/113199
- self._fp.close()
-
- if data:
- self._fp_bytes_read += len(data)
- if self.length_remaining is not None:
- self.length_remaining -= len(data)
- return data
-
- def read(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- cache_content: bool = False,
- ) -> bytes:
- """
- Similar to :meth:`http.client.HTTPResponse.read`, but with two additional
- parameters: ``decode_content`` and ``cache_content``.
-
- :param amt:
- How much of the content to read. If specified, caching is skipped
- because it doesn't make sense to cache partial content as the full
- response.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
-
- :param cache_content:
- If True, will save the returned data such that the same result is
- returned despite of the state of the underlying file object. This
- is useful if you want the ``.data`` property to continue working
- after having ``.read()`` the file object. (Overridden if ``amt`` is
- set.)
- """
- self._init_decoder()
- if decode_content is None:
- decode_content = self.decode_content
-
- if amt and amt < 0:
- # Negative numbers and `None` should be treated the same.
- amt = None
- elif amt is not None:
- cache_content = False
-
- if len(self._decoded_buffer) >= amt:
- return self._decoded_buffer.get(amt)
-
- data = self._raw_read(amt)
-
- flush_decoder = amt is None or (amt != 0 and not data)
-
- if not data and len(self._decoded_buffer) == 0:
- return data
-
- if amt is None:
- data = self._decode(data, decode_content, flush_decoder)
- if cache_content:
- self._body = data
- else:
- # do not waste memory on buffer when not decoding
- if not decode_content:
- if self._has_decoded_content:
- raise RuntimeError(
- "Calling read(decode_content=False) is not supported after "
- "read(decode_content=True) was called."
- )
- return data
-
- decoded_data = self._decode(data, decode_content, flush_decoder)
- self._decoded_buffer.put(decoded_data)
-
- while len(self._decoded_buffer) < amt and data:
- # TODO make sure to initially read enough data to get past the headers
- # For example, the GZ file header takes 10 bytes, we don't want to read
- # it one byte at a time
- data = self._raw_read(amt)
- decoded_data = self._decode(data, decode_content, flush_decoder)
- self._decoded_buffer.put(decoded_data)
- data = self._decoded_buffer.get(amt)
-
- return data
-
- def read1(
- self,
- amt: int | None = None,
- decode_content: bool | None = None,
- ) -> bytes:
- """
- Similar to ``http.client.HTTPResponse.read1`` and documented
- in :meth:`io.BufferedReader.read1`, but with an additional parameter:
- ``decode_content``.
-
- :param amt:
- How much of the content to read.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- if decode_content is None:
- decode_content = self.decode_content
- if amt and amt < 0:
- # Negative numbers and `None` should be treated the same.
- amt = None
- # try and respond without going to the network
- if self._has_decoded_content:
- if not decode_content:
- raise RuntimeError(
- "Calling read1(decode_content=False) is not supported after "
- "read1(decode_content=True) was called."
- )
- if len(self._decoded_buffer) > 0:
- if amt is None:
- return self._decoded_buffer.get_all()
- return self._decoded_buffer.get(amt)
- if amt == 0:
- return b""
-
- # FIXME, this method's type doesn't say returning None is possible
- data = self._raw_read(amt, read1=True)
- if not decode_content or data is None:
- return data
-
- self._init_decoder()
- while True:
- flush_decoder = not data
- decoded_data = self._decode(data, decode_content, flush_decoder)
- self._decoded_buffer.put(decoded_data)
- if decoded_data or flush_decoder:
- break
- data = self._raw_read(8192, read1=True)
-
- if amt is None:
- return self._decoded_buffer.get_all()
- return self._decoded_buffer.get(amt)
-
- def stream(
- self, amt: int | None = 2**16, decode_content: bool | None = None
- ) -> typing.Generator[bytes, None, None]:
- """
- A generator wrapper for the read() method. A call will block until
- ``amt`` bytes have been read from the connection or until the
- connection is closed.
-
- :param amt:
- How much of the content to read. The generator will return up to
- much data per iteration, but may return less. This is particularly
- likely when using compressed data. However, the empty string will
- never be returned.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- if self.chunked and self.supports_chunked_reads():
- yield from self.read_chunked(amt, decode_content=decode_content)
- else:
- while not is_fp_closed(self._fp) or len(self._decoded_buffer) > 0:
- data = self.read(amt=amt, decode_content=decode_content)
-
- if data:
- yield data
-
- # Overrides from io.IOBase
- def readable(self) -> bool:
- return True
-
- def close(self) -> None:
- if not self.closed and self._fp:
- self._fp.close()
-
- if self._connection:
- self._connection.close()
-
- if not self.auto_close:
- io.IOBase.close(self)
-
- @property
- def closed(self) -> bool:
- if not self.auto_close:
- return io.IOBase.closed.__get__(self) # type: ignore[no-any-return]
- elif self._fp is None:
- return True
- elif hasattr(self._fp, "isclosed"):
- return self._fp.isclosed()
- elif hasattr(self._fp, "closed"):
- return self._fp.closed
- else:
- return True
-
- def fileno(self) -> int:
- if self._fp is None:
- raise OSError("HTTPResponse has no file to get a fileno from")
- elif hasattr(self._fp, "fileno"):
- return self._fp.fileno()
- else:
- raise OSError(
- "The file-like object this HTTPResponse is wrapped "
- "around has no file descriptor"
- )
-
- def flush(self) -> None:
- if (
- self._fp is not None
- and hasattr(self._fp, "flush")
- and not getattr(self._fp, "closed", False)
- ):
- return self._fp.flush()
-
- def supports_chunked_reads(self) -> bool:
- """
- Checks if the underlying file-like object looks like a
- :class:`http.client.HTTPResponse` object. We do this by testing for
- the fp attribute. If it is present we assume it returns raw chunks as
- processed by read_chunked().
- """
- return hasattr(self._fp, "fp")
-
- def _update_chunk_length(self) -> None:
- # First, we'll figure out length of a chunk and then
- # we'll try to read it from socket.
- if self.chunk_left is not None:
- return None
- line = self._fp.fp.readline() # type: ignore[union-attr]
- line = line.split(b";", 1)[0]
- try:
- self.chunk_left = int(line, 16)
- except ValueError:
- self.close()
- if line:
- # Invalid chunked protocol response, abort.
- raise InvalidChunkLength(self, line) from None
- else:
- # Truncated at start of next chunk
- raise ProtocolError("Response ended prematurely") from None
-
- def _handle_chunk(self, amt: int | None) -> bytes:
- returned_chunk = None
- if amt is None:
- chunk = self._fp._safe_read(self.chunk_left) # type: ignore[union-attr]
- returned_chunk = chunk
- self._fp._safe_read(2) # type: ignore[union-attr] # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- elif self.chunk_left is not None and amt < self.chunk_left:
- value = self._fp._safe_read(amt) # type: ignore[union-attr]
- self.chunk_left = self.chunk_left - amt
- returned_chunk = value
- elif amt == self.chunk_left:
- value = self._fp._safe_read(amt) # type: ignore[union-attr]
- self._fp._safe_read(2) # type: ignore[union-attr] # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- returned_chunk = value
- else: # amt > self.chunk_left
- returned_chunk = self._fp._safe_read(self.chunk_left) # type: ignore[union-attr]
- self._fp._safe_read(2) # type: ignore[union-attr] # Toss the CRLF at the end of the chunk.
- self.chunk_left = None
- return returned_chunk # type: ignore[no-any-return]
-
- def read_chunked(
- self, amt: int | None = None, decode_content: bool | None = None
- ) -> typing.Generator[bytes, None, None]:
- """
- Similar to :meth:`HTTPResponse.read`, but with an additional
- parameter: ``decode_content``.
-
- :param amt:
- How much of the content to read. If specified, caching is skipped
- because it doesn't make sense to cache partial content as the full
- response.
-
- :param decode_content:
- If True, will attempt to decode the body based on the
- 'content-encoding' header.
- """
- self._init_decoder()
- # FIXME: Rewrite this method and make it a class with a better structured logic.
- if not self.chunked:
- raise ResponseNotChunked(
- "Response is not chunked. "
- "Header 'transfer-encoding: chunked' is missing."
- )
- if not self.supports_chunked_reads():
- raise BodyNotHttplibCompatible(
- "Body should be http.client.HTTPResponse like. "
- "It should have have an fp attribute which returns raw chunks."
- )
-
- with self._error_catcher():
- # Don't bother reading the body of a HEAD request.
- if self._original_response and is_response_to_head(self._original_response):
- self._original_response.close()
- return None
-
- # If a response is already read and closed
- # then return immediately.
- if self._fp.fp is None: # type: ignore[union-attr]
- return None
-
- if amt and amt < 0:
- # Negative numbers and `None` should be treated the same,
- # but httplib handles only `None` correctly.
- amt = None
-
- while True:
- self._update_chunk_length()
- if self.chunk_left == 0:
- break
- chunk = self._handle_chunk(amt)
- decoded = self._decode(
- chunk, decode_content=decode_content, flush_decoder=False
- )
- if decoded:
- yield decoded
-
- if decode_content:
- # On CPython and PyPy, we should never need to flush the
- # decoder. However, on Jython we *might* need to, so
- # lets defensively do it anyway.
- decoded = self._flush_decoder()
- if decoded: # Platform-specific: Jython.
- yield decoded
-
- # Chunk content ends with \r\n: discard it.
- while self._fp is not None:
- line = self._fp.fp.readline()
- if not line:
- # Some sites may not end with '\r\n'.
- break
- if line == b"\r\n":
- break
-
- # We read everything; close the "file".
- if self._original_response:
- self._original_response.close()
-
- @property
- def url(self) -> str | None:
- """
- Returns the URL that was the source of this response.
- If the request that generated this response redirected, this method
- will return the final redirect location.
- """
- return self._request_url
-
- @url.setter
- def url(self, url: str) -> None:
- self._request_url = url
-
- def __iter__(self) -> typing.Iterator[bytes]:
- buffer: list[bytes] = []
- for chunk in self.stream(decode_content=True):
- if b"\n" in chunk:
- chunks = chunk.split(b"\n")
- yield b"".join(buffer) + chunks[0] + b"\n"
- for x in chunks[1:-1]:
- yield x + b"\n"
- if chunks[-1]:
- buffer = [chunks[-1]]
- else:
- buffer = []
- else:
- buffer.append(chunk)
- if buffer:
- yield b"".join(buffer)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__init__.py b/.venv/lib/python3.12/site-packages/urllib3/util/__init__.py
deleted file mode 100644
index 5341260..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/__init__.py
+++ /dev/null
@@ -1,42 +0,0 @@
-# For backwards compatibility, provide imports that used to be here.
-from __future__ import annotations
-
-from .connection import is_connection_dropped
-from .request import SKIP_HEADER, SKIPPABLE_HEADERS, make_headers
-from .response import is_fp_closed
-from .retry import Retry
-from .ssl_ import (
- ALPN_PROTOCOLS,
- IS_PYOPENSSL,
- SSLContext,
- assert_fingerprint,
- create_urllib3_context,
- resolve_cert_reqs,
- resolve_ssl_version,
- ssl_wrap_socket,
-)
-from .timeout import Timeout
-from .url import Url, parse_url
-from .wait import wait_for_read, wait_for_write
-
-__all__ = (
- "IS_PYOPENSSL",
- "SSLContext",
- "ALPN_PROTOCOLS",
- "Retry",
- "Timeout",
- "Url",
- "assert_fingerprint",
- "create_urllib3_context",
- "is_connection_dropped",
- "is_fp_closed",
- "parse_url",
- "make_headers",
- "resolve_cert_reqs",
- "resolve_ssl_version",
- "ssl_wrap_socket",
- "wait_for_read",
- "wait_for_write",
- "SKIP_HEADER",
- "SKIPPABLE_HEADERS",
-)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc
deleted file mode 100644
index 84256e0..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/__init__.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc
deleted file mode 100644
index 50d6b53..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/connection.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc
deleted file mode 100644
index efb1e41..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/proxy.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc
deleted file mode 100644
index b861ec1..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/request.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc
deleted file mode 100644
index fdc6f5c..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/response.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc
deleted file mode 100644
index d131d91..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/retry.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc
deleted file mode 100644
index e63702a..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc
deleted file mode 100644
index eab0d90..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssl_match_hostname.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc
deleted file mode 100644
index 0f70dd1..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/ssltransport.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc
deleted file mode 100644
index 54437ce..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/timeout.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc
deleted file mode 100644
index e1ebd1c..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/url.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc
deleted file mode 100644
index 5019174..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/util.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc b/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc
deleted file mode 100644
index e7c5690..0000000
Binary files a/.venv/lib/python3.12/site-packages/urllib3/util/__pycache__/wait.cpython-312.pyc and /dev/null differ
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/connection.py b/.venv/lib/python3.12/site-packages/urllib3/util/connection.py
deleted file mode 100644
index 5c7da73..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/connection.py
+++ /dev/null
@@ -1,137 +0,0 @@
-from __future__ import annotations
-
-import socket
-import typing
-
-from ..exceptions import LocationParseError
-from .timeout import _DEFAULT_TIMEOUT, _TYPE_TIMEOUT
-
-_TYPE_SOCKET_OPTIONS = typing.Sequence[typing.Tuple[int, int, typing.Union[int, bytes]]]
-
-if typing.TYPE_CHECKING:
- from .._base_connection import BaseHTTPConnection
-
-
-def is_connection_dropped(conn: BaseHTTPConnection) -> bool: # Platform-specific
- """
- Returns True if the connection is dropped and should be closed.
- :param conn: :class:`urllib3.connection.HTTPConnection` object.
- """
- return not conn.is_connected
-
-
-# This function is copied from socket.py in the Python 2.7 standard
-# library test suite. Added to its signature is only `socket_options`.
-# One additional modification is that we avoid binding to IPv6 servers
-# discovered in DNS if the system doesn't have IPv6 functionality.
-def create_connection(
- address: tuple[str, int],
- timeout: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- source_address: tuple[str, int] | None = None,
- socket_options: _TYPE_SOCKET_OPTIONS | None = None,
-) -> socket.socket:
- """Connect to *address* and return the socket object.
-
- Convenience function. Connect to *address* (a 2-tuple ``(host,
- port)``) and return the socket object. Passing the optional
- *timeout* parameter will set the timeout on the socket instance
- before attempting to connect. If no *timeout* is supplied, the
- global default timeout setting returned by :func:`socket.getdefaulttimeout`
- is used. If *source_address* is set it must be a tuple of (host, port)
- for the socket to bind as a source address before making the connection.
- An host of '' or port 0 tells the OS to use the default.
- """
-
- host, port = address
- if host.startswith("["):
- host = host.strip("[]")
- err = None
-
- # Using the value from allowed_gai_family() in the context of getaddrinfo lets
- # us select whether to work with IPv4 DNS records, IPv6 records, or both.
- # The original create_connection function always returns all records.
- family = allowed_gai_family()
-
- try:
- host.encode("idna")
- except UnicodeError:
- raise LocationParseError(f"'{host}', label empty or too long") from None
-
- for res in socket.getaddrinfo(host, port, family, socket.SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
- sock = None
- try:
- sock = socket.socket(af, socktype, proto)
-
- # If provided, set socket level options before connecting.
- _set_socket_options(sock, socket_options)
-
- if timeout is not _DEFAULT_TIMEOUT:
- sock.settimeout(timeout)
- if source_address:
- sock.bind(source_address)
- sock.connect(sa)
- # Break explicitly a reference cycle
- err = None
- return sock
-
- except OSError as _:
- err = _
- if sock is not None:
- sock.close()
-
- if err is not None:
- try:
- raise err
- finally:
- # Break explicitly a reference cycle
- err = None
- else:
- raise OSError("getaddrinfo returns an empty list")
-
-
-def _set_socket_options(
- sock: socket.socket, options: _TYPE_SOCKET_OPTIONS | None
-) -> None:
- if options is None:
- return
-
- for opt in options:
- sock.setsockopt(*opt)
-
-
-def allowed_gai_family() -> socket.AddressFamily:
- """This function is designed to work in the context of
- getaddrinfo, where family=socket.AF_UNSPEC is the default and
- will perform a DNS search for both IPv6 and IPv4 records."""
-
- family = socket.AF_INET
- if HAS_IPV6:
- family = socket.AF_UNSPEC
- return family
-
-
-def _has_ipv6(host: str) -> bool:
- """Returns True if the system can bind an IPv6 address."""
- sock = None
- has_ipv6 = False
-
- if socket.has_ipv6:
- # has_ipv6 returns true if cPython was compiled with IPv6 support.
- # It does not tell us if the system has IPv6 support enabled. To
- # determine that we must bind to an IPv6 address.
- # https://github.com/urllib3/urllib3/pull/611
- # https://bugs.python.org/issue658327
- try:
- sock = socket.socket(socket.AF_INET6)
- sock.bind((host, 0))
- has_ipv6 = True
- except Exception:
- pass
-
- if sock:
- sock.close()
- return has_ipv6
-
-
-HAS_IPV6 = _has_ipv6("::1")
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/proxy.py b/.venv/lib/python3.12/site-packages/urllib3/util/proxy.py
deleted file mode 100644
index 908fc66..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/proxy.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from __future__ import annotations
-
-import typing
-
-from .url import Url
-
-if typing.TYPE_CHECKING:
- from ..connection import ProxyConfig
-
-
-def connection_requires_http_tunnel(
- proxy_url: Url | None = None,
- proxy_config: ProxyConfig | None = None,
- destination_scheme: str | None = None,
-) -> bool:
- """
- Returns True if the connection requires an HTTP CONNECT through the proxy.
-
- :param URL proxy_url:
- URL of the proxy.
- :param ProxyConfig proxy_config:
- Proxy configuration from poolmanager.py
- :param str destination_scheme:
- The scheme of the destination. (i.e https, http, etc)
- """
- # If we're not using a proxy, no way to use a tunnel.
- if proxy_url is None:
- return False
-
- # HTTP destinations never require tunneling, we always forward.
- if destination_scheme == "http":
- return False
-
- # Support for forwarding with HTTPS proxies and HTTPS destinations.
- if (
- proxy_url.scheme == "https"
- and proxy_config
- and proxy_config.use_forwarding_for_https
- ):
- return False
-
- # Otherwise always use a tunnel.
- return True
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/request.py b/.venv/lib/python3.12/site-packages/urllib3/util/request.py
deleted file mode 100644
index 859597e..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/request.py
+++ /dev/null
@@ -1,256 +0,0 @@
-from __future__ import annotations
-
-import io
-import typing
-from base64 import b64encode
-from enum import Enum
-
-from ..exceptions import UnrewindableBodyError
-from .util import to_bytes
-
-if typing.TYPE_CHECKING:
- from typing import Final
-
-# Pass as a value within ``headers`` to skip
-# emitting some HTTP headers that are added automatically.
-# The only headers that are supported are ``Accept-Encoding``,
-# ``Host``, and ``User-Agent``.
-SKIP_HEADER = "@@@SKIP_HEADER@@@"
-SKIPPABLE_HEADERS = frozenset(["accept-encoding", "host", "user-agent"])
-
-ACCEPT_ENCODING = "gzip,deflate"
-try:
- try:
- import brotlicffi as _unused_module_brotli # type: ignore[import-not-found] # noqa: F401
- except ImportError:
- import brotli as _unused_module_brotli # type: ignore[import-not-found] # noqa: F401
-except ImportError:
- pass
-else:
- ACCEPT_ENCODING += ",br"
-try:
- import zstandard as _unused_module_zstd # noqa: F401
-except ImportError:
- pass
-else:
- ACCEPT_ENCODING += ",zstd"
-
-
-class _TYPE_FAILEDTELL(Enum):
- token = 0
-
-
-_FAILEDTELL: Final[_TYPE_FAILEDTELL] = _TYPE_FAILEDTELL.token
-
-_TYPE_BODY_POSITION = typing.Union[int, _TYPE_FAILEDTELL]
-
-# When sending a request with these methods we aren't expecting
-# a body so don't need to set an explicit 'Content-Length: 0'
-# The reason we do this in the negative instead of tracking methods
-# which 'should' have a body is because unknown methods should be
-# treated as if they were 'POST' which *does* expect a body.
-_METHODS_NOT_EXPECTING_BODY = {"GET", "HEAD", "DELETE", "TRACE", "OPTIONS", "CONNECT"}
-
-
-def make_headers(
- keep_alive: bool | None = None,
- accept_encoding: bool | list[str] | str | None = None,
- user_agent: str | None = None,
- basic_auth: str | None = None,
- proxy_basic_auth: str | None = None,
- disable_cache: bool | None = None,
-) -> dict[str, str]:
- """
- Shortcuts for generating request headers.
-
- :param keep_alive:
- If ``True``, adds 'connection: keep-alive' header.
-
- :param accept_encoding:
- Can be a boolean, list, or string.
- ``True`` translates to 'gzip,deflate'. If either the ``brotli`` or
- ``brotlicffi`` package is installed 'gzip,deflate,br' is used instead.
- List will get joined by comma.
- String will be used as provided.
-
- :param user_agent:
- String representing the user-agent you want, such as
- "python-urllib3/0.6"
-
- :param basic_auth:
- Colon-separated username:password string for 'authorization: basic ...'
- auth header.
-
- :param proxy_basic_auth:
- Colon-separated username:password string for 'proxy-authorization: basic ...'
- auth header.
-
- :param disable_cache:
- If ``True``, adds 'cache-control: no-cache' header.
-
- Example:
-
- .. code-block:: python
-
- import urllib3
-
- print(urllib3.util.make_headers(keep_alive=True, user_agent="Batman/1.0"))
- # {'connection': 'keep-alive', 'user-agent': 'Batman/1.0'}
- print(urllib3.util.make_headers(accept_encoding=True))
- # {'accept-encoding': 'gzip,deflate'}
- """
- headers: dict[str, str] = {}
- if accept_encoding:
- if isinstance(accept_encoding, str):
- pass
- elif isinstance(accept_encoding, list):
- accept_encoding = ",".join(accept_encoding)
- else:
- accept_encoding = ACCEPT_ENCODING
- headers["accept-encoding"] = accept_encoding
-
- if user_agent:
- headers["user-agent"] = user_agent
-
- if keep_alive:
- headers["connection"] = "keep-alive"
-
- if basic_auth:
- headers[
- "authorization"
- ] = f"Basic {b64encode(basic_auth.encode('latin-1')).decode()}"
-
- if proxy_basic_auth:
- headers[
- "proxy-authorization"
- ] = f"Basic {b64encode(proxy_basic_auth.encode('latin-1')).decode()}"
-
- if disable_cache:
- headers["cache-control"] = "no-cache"
-
- return headers
-
-
-def set_file_position(
- body: typing.Any, pos: _TYPE_BODY_POSITION | None
-) -> _TYPE_BODY_POSITION | None:
- """
- If a position is provided, move file to that point.
- Otherwise, we'll attempt to record a position for future use.
- """
- if pos is not None:
- rewind_body(body, pos)
- elif getattr(body, "tell", None) is not None:
- try:
- pos = body.tell()
- except OSError:
- # This differentiates from None, allowing us to catch
- # a failed `tell()` later when trying to rewind the body.
- pos = _FAILEDTELL
-
- return pos
-
-
-def rewind_body(body: typing.IO[typing.AnyStr], body_pos: _TYPE_BODY_POSITION) -> None:
- """
- Attempt to rewind body to a certain position.
- Primarily used for request redirects and retries.
-
- :param body:
- File-like object that supports seek.
-
- :param int pos:
- Position to seek to in file.
- """
- body_seek = getattr(body, "seek", None)
- if body_seek is not None and isinstance(body_pos, int):
- try:
- body_seek(body_pos)
- except OSError as e:
- raise UnrewindableBodyError(
- "An error occurred when rewinding request body for redirect/retry."
- ) from e
- elif body_pos is _FAILEDTELL:
- raise UnrewindableBodyError(
- "Unable to record file position for rewinding "
- "request body during a redirect/retry."
- )
- else:
- raise ValueError(
- f"body_pos must be of type integer, instead it was {type(body_pos)}."
- )
-
-
-class ChunksAndContentLength(typing.NamedTuple):
- chunks: typing.Iterable[bytes] | None
- content_length: int | None
-
-
-def body_to_chunks(
- body: typing.Any | None, method: str, blocksize: int
-) -> ChunksAndContentLength:
- """Takes the HTTP request method, body, and blocksize and
- transforms them into an iterable of chunks to pass to
- socket.sendall() and an optional 'Content-Length' header.
-
- A 'Content-Length' of 'None' indicates the length of the body
- can't be determined so should use 'Transfer-Encoding: chunked'
- for framing instead.
- """
-
- chunks: typing.Iterable[bytes] | None
- content_length: int | None
-
- # No body, we need to make a recommendation on 'Content-Length'
- # based on whether that request method is expected to have
- # a body or not.
- if body is None:
- chunks = None
- if method.upper() not in _METHODS_NOT_EXPECTING_BODY:
- content_length = 0
- else:
- content_length = None
-
- # Bytes or strings become bytes
- elif isinstance(body, (str, bytes)):
- chunks = (to_bytes(body),)
- content_length = len(chunks[0])
-
- # File-like object, TODO: use seek() and tell() for length?
- elif hasattr(body, "read"):
-
- def chunk_readable() -> typing.Iterable[bytes]:
- nonlocal body, blocksize
- encode = isinstance(body, io.TextIOBase)
- while True:
- datablock = body.read(blocksize)
- if not datablock:
- break
- if encode:
- datablock = datablock.encode("iso-8859-1")
- yield datablock
-
- chunks = chunk_readable()
- content_length = None
-
- # Otherwise we need to start checking via duck-typing.
- else:
- try:
- # Check if the body implements the buffer API.
- mv = memoryview(body)
- except TypeError:
- try:
- # Check if the body is an iterable
- chunks = iter(body)
- content_length = None
- except TypeError:
- raise TypeError(
- f"'body' must be a bytes-like object, file-like "
- f"object, or iterable. Instead was {body!r}"
- ) from None
- else:
- # Since it implements the buffer API can be passed directly to socket.sendall()
- chunks = (body,)
- content_length = mv.nbytes
-
- return ChunksAndContentLength(chunks=chunks, content_length=content_length)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/response.py b/.venv/lib/python3.12/site-packages/urllib3/util/response.py
deleted file mode 100644
index 0f45786..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/response.py
+++ /dev/null
@@ -1,101 +0,0 @@
-from __future__ import annotations
-
-import http.client as httplib
-from email.errors import MultipartInvariantViolationDefect, StartBoundaryNotFoundDefect
-
-from ..exceptions import HeaderParsingError
-
-
-def is_fp_closed(obj: object) -> bool:
- """
- Checks whether a given file-like object is closed.
-
- :param obj:
- The file-like object to check.
- """
-
- try:
- # Check `isclosed()` first, in case Python3 doesn't set `closed`.
- # GH Issue #928
- return obj.isclosed() # type: ignore[no-any-return, attr-defined]
- except AttributeError:
- pass
-
- try:
- # Check via the official file-like-object way.
- return obj.closed # type: ignore[no-any-return, attr-defined]
- except AttributeError:
- pass
-
- try:
- # Check if the object is a container for another file-like object that
- # gets released on exhaustion (e.g. HTTPResponse).
- return obj.fp is None # type: ignore[attr-defined]
- except AttributeError:
- pass
-
- raise ValueError("Unable to determine whether fp is closed.")
-
-
-def assert_header_parsing(headers: httplib.HTTPMessage) -> None:
- """
- Asserts whether all headers have been successfully parsed.
- Extracts encountered errors from the result of parsing headers.
-
- Only works on Python 3.
-
- :param http.client.HTTPMessage headers: Headers to verify.
-
- :raises urllib3.exceptions.HeaderParsingError:
- If parsing errors are found.
- """
-
- # This will fail silently if we pass in the wrong kind of parameter.
- # To make debugging easier add an explicit check.
- if not isinstance(headers, httplib.HTTPMessage):
- raise TypeError(f"expected httplib.Message, got {type(headers)}.")
-
- unparsed_data = None
-
- # get_payload is actually email.message.Message.get_payload;
- # we're only interested in the result if it's not a multipart message
- if not headers.is_multipart():
- payload = headers.get_payload()
-
- if isinstance(payload, (bytes, str)):
- unparsed_data = payload
-
- # httplib is assuming a response body is available
- # when parsing headers even when httplib only sends
- # header data to parse_headers() This results in
- # defects on multipart responses in particular.
- # See: https://github.com/urllib3/urllib3/issues/800
-
- # So we ignore the following defects:
- # - StartBoundaryNotFoundDefect:
- # The claimed start boundary was never found.
- # - MultipartInvariantViolationDefect:
- # A message claimed to be a multipart but no subparts were found.
- defects = [
- defect
- for defect in headers.defects
- if not isinstance(
- defect, (StartBoundaryNotFoundDefect, MultipartInvariantViolationDefect)
- )
- ]
-
- if defects or unparsed_data:
- raise HeaderParsingError(defects=defects, unparsed_data=unparsed_data)
-
-
-def is_response_to_head(response: httplib.HTTPResponse) -> bool:
- """
- Checks whether the request of a response has been a HEAD-request.
-
- :param http.client.HTTPResponse response:
- Response to check if the originating request
- used 'HEAD' as a method.
- """
- # FIXME: Can we do this somehow without accessing private httplib _method?
- method_str = response._method # type: str # type: ignore[attr-defined]
- return method_str.upper() == "HEAD"
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/retry.py b/.venv/lib/python3.12/site-packages/urllib3/util/retry.py
deleted file mode 100644
index 0456cce..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/retry.py
+++ /dev/null
@@ -1,533 +0,0 @@
-from __future__ import annotations
-
-import email
-import logging
-import random
-import re
-import time
-import typing
-from itertools import takewhile
-from types import TracebackType
-
-from ..exceptions import (
- ConnectTimeoutError,
- InvalidHeader,
- MaxRetryError,
- ProtocolError,
- ProxyError,
- ReadTimeoutError,
- ResponseError,
-)
-from .util import reraise
-
-if typing.TYPE_CHECKING:
- from typing_extensions import Self
-
- from ..connectionpool import ConnectionPool
- from ..response import BaseHTTPResponse
-
-log = logging.getLogger(__name__)
-
-
-# Data structure for representing the metadata of requests that result in a retry.
-class RequestHistory(typing.NamedTuple):
- method: str | None
- url: str | None
- error: Exception | None
- status: int | None
- redirect_location: str | None
-
-
-class Retry:
- """Retry configuration.
-
- Each retry attempt will create a new Retry object with updated values, so
- they can be safely reused.
-
- Retries can be defined as a default for a pool:
-
- .. code-block:: python
-
- retries = Retry(connect=5, read=2, redirect=5)
- http = PoolManager(retries=retries)
- response = http.request("GET", "https://example.com/")
-
- Or per-request (which overrides the default for the pool):
-
- .. code-block:: python
-
- response = http.request("GET", "https://example.com/", retries=Retry(10))
-
- Retries can be disabled by passing ``False``:
-
- .. code-block:: python
-
- response = http.request("GET", "https://example.com/", retries=False)
-
- Errors will be wrapped in :class:`~urllib3.exceptions.MaxRetryError` unless
- retries are disabled, in which case the causing exception will be raised.
-
- :param int total:
- Total number of retries to allow. Takes precedence over other counts.
-
- Set to ``None`` to remove this constraint and fall back on other
- counts.
-
- Set to ``0`` to fail on the first retry.
-
- Set to ``False`` to disable and imply ``raise_on_redirect=False``.
-
- :param int connect:
- How many connection-related errors to retry on.
-
- These are errors raised before the request is sent to the remote server,
- which we assume has not triggered the server to process the request.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int read:
- How many times to retry on read errors.
-
- These errors are raised after the request was sent to the server, so the
- request may have side-effects.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int redirect:
- How many redirects to perform. Limit this to avoid infinite redirect
- loops.
-
- A redirect is a HTTP response with a status code 301, 302, 303, 307 or
- 308.
-
- Set to ``0`` to fail on the first retry of this type.
-
- Set to ``False`` to disable and imply ``raise_on_redirect=False``.
-
- :param int status:
- How many times to retry on bad status codes.
-
- These are retries made on responses, where status code matches
- ``status_forcelist``.
-
- Set to ``0`` to fail on the first retry of this type.
-
- :param int other:
- How many times to retry on other errors.
-
- Other errors are errors that are not connect, read, redirect or status errors.
- These errors might be raised after the request was sent to the server, so the
- request might have side-effects.
-
- Set to ``0`` to fail on the first retry of this type.
-
- If ``total`` is not set, it's a good idea to set this to 0 to account
- for unexpected edge cases and avoid infinite retry loops.
-
- :param Collection allowed_methods:
- Set of uppercased HTTP method verbs that we should retry on.
-
- By default, we only retry on methods which are considered to be
- idempotent (multiple requests with the same parameters end with the
- same state). See :attr:`Retry.DEFAULT_ALLOWED_METHODS`.
-
- Set to a ``None`` value to retry on any verb.
-
- :param Collection status_forcelist:
- A set of integer HTTP status codes that we should force a retry on.
- A retry is initiated if the request method is in ``allowed_methods``
- and the response status code is in ``status_forcelist``.
-
- By default, this is disabled with ``None``.
-
- :param float backoff_factor:
- A backoff factor to apply between attempts after the second try
- (most errors are resolved immediately by a second try without a
- delay). urllib3 will sleep for::
-
- {backoff factor} * (2 ** ({number of previous retries}))
-
- seconds. If `backoff_jitter` is non-zero, this sleep is extended by::
-
- random.uniform(0, {backoff jitter})
-
- seconds. For example, if the backoff_factor is 0.1, then :func:`Retry.sleep` will
- sleep for [0.0s, 0.2s, 0.4s, 0.8s, ...] between retries. No backoff will ever
- be longer than `backoff_max`.
-
- By default, backoff is disabled (factor set to 0).
-
- :param bool raise_on_redirect: Whether, if the number of redirects is
- exhausted, to raise a MaxRetryError, or to return a response with a
- response code in the 3xx range.
-
- :param bool raise_on_status: Similar meaning to ``raise_on_redirect``:
- whether we should raise an exception, or return a response,
- if status falls in ``status_forcelist`` range and retries have
- been exhausted.
-
- :param tuple history: The history of the request encountered during
- each call to :meth:`~Retry.increment`. The list is in the order
- the requests occurred. Each list item is of class :class:`RequestHistory`.
-
- :param bool respect_retry_after_header:
- Whether to respect Retry-After header on status codes defined as
- :attr:`Retry.RETRY_AFTER_STATUS_CODES` or not.
-
- :param Collection remove_headers_on_redirect:
- Sequence of headers to remove from the request when a response
- indicating a redirect is returned before firing off the redirected
- request.
- """
-
- #: Default methods to be used for ``allowed_methods``
- DEFAULT_ALLOWED_METHODS = frozenset(
- ["HEAD", "GET", "PUT", "DELETE", "OPTIONS", "TRACE"]
- )
-
- #: Default status codes to be used for ``status_forcelist``
- RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503])
-
- #: Default headers to be used for ``remove_headers_on_redirect``
- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(
- ["Cookie", "Authorization", "Proxy-Authorization"]
- )
-
- #: Default maximum backoff time.
- DEFAULT_BACKOFF_MAX = 120
-
- # Backward compatibility; assigned outside of the class.
- DEFAULT: typing.ClassVar[Retry]
-
- def __init__(
- self,
- total: bool | int | None = 10,
- connect: int | None = None,
- read: int | None = None,
- redirect: bool | int | None = None,
- status: int | None = None,
- other: int | None = None,
- allowed_methods: typing.Collection[str] | None = DEFAULT_ALLOWED_METHODS,
- status_forcelist: typing.Collection[int] | None = None,
- backoff_factor: float = 0,
- backoff_max: float = DEFAULT_BACKOFF_MAX,
- raise_on_redirect: bool = True,
- raise_on_status: bool = True,
- history: tuple[RequestHistory, ...] | None = None,
- respect_retry_after_header: bool = True,
- remove_headers_on_redirect: typing.Collection[
- str
- ] = DEFAULT_REMOVE_HEADERS_ON_REDIRECT,
- backoff_jitter: float = 0.0,
- ) -> None:
- self.total = total
- self.connect = connect
- self.read = read
- self.status = status
- self.other = other
-
- if redirect is False or total is False:
- redirect = 0
- raise_on_redirect = False
-
- self.redirect = redirect
- self.status_forcelist = status_forcelist or set()
- self.allowed_methods = allowed_methods
- self.backoff_factor = backoff_factor
- self.backoff_max = backoff_max
- self.raise_on_redirect = raise_on_redirect
- self.raise_on_status = raise_on_status
- self.history = history or ()
- self.respect_retry_after_header = respect_retry_after_header
- self.remove_headers_on_redirect = frozenset(
- h.lower() for h in remove_headers_on_redirect
- )
- self.backoff_jitter = backoff_jitter
-
- def new(self, **kw: typing.Any) -> Self:
- params = dict(
- total=self.total,
- connect=self.connect,
- read=self.read,
- redirect=self.redirect,
- status=self.status,
- other=self.other,
- allowed_methods=self.allowed_methods,
- status_forcelist=self.status_forcelist,
- backoff_factor=self.backoff_factor,
- backoff_max=self.backoff_max,
- raise_on_redirect=self.raise_on_redirect,
- raise_on_status=self.raise_on_status,
- history=self.history,
- remove_headers_on_redirect=self.remove_headers_on_redirect,
- respect_retry_after_header=self.respect_retry_after_header,
- backoff_jitter=self.backoff_jitter,
- )
-
- params.update(kw)
- return type(self)(**params) # type: ignore[arg-type]
-
- @classmethod
- def from_int(
- cls,
- retries: Retry | bool | int | None,
- redirect: bool | int | None = True,
- default: Retry | bool | int | None = None,
- ) -> Retry:
- """Backwards-compatibility for the old retries format."""
- if retries is None:
- retries = default if default is not None else cls.DEFAULT
-
- if isinstance(retries, Retry):
- return retries
-
- redirect = bool(redirect) and None
- new_retries = cls(retries, redirect=redirect)
- log.debug("Converted retries value: %r -> %r", retries, new_retries)
- return new_retries
-
- def get_backoff_time(self) -> float:
- """Formula for computing the current backoff
-
- :rtype: float
- """
- # We want to consider only the last consecutive errors sequence (Ignore redirects).
- consecutive_errors_len = len(
- list(
- takewhile(lambda x: x.redirect_location is None, reversed(self.history))
- )
- )
- if consecutive_errors_len <= 1:
- return 0
-
- backoff_value = self.backoff_factor * (2 ** (consecutive_errors_len - 1))
- if self.backoff_jitter != 0.0:
- backoff_value += random.random() * self.backoff_jitter
- return float(max(0, min(self.backoff_max, backoff_value)))
-
- def parse_retry_after(self, retry_after: str) -> float:
- seconds: float
- # Whitespace: https://tools.ietf.org/html/rfc7230#section-3.2.4
- if re.match(r"^\s*[0-9]+\s*$", retry_after):
- seconds = int(retry_after)
- else:
- retry_date_tuple = email.utils.parsedate_tz(retry_after)
- if retry_date_tuple is None:
- raise InvalidHeader(f"Invalid Retry-After header: {retry_after}")
-
- retry_date = email.utils.mktime_tz(retry_date_tuple)
- seconds = retry_date - time.time()
-
- seconds = max(seconds, 0)
-
- return seconds
-
- def get_retry_after(self, response: BaseHTTPResponse) -> float | None:
- """Get the value of Retry-After in seconds."""
-
- retry_after = response.headers.get("Retry-After")
-
- if retry_after is None:
- return None
-
- return self.parse_retry_after(retry_after)
-
- def sleep_for_retry(self, response: BaseHTTPResponse) -> bool:
- retry_after = self.get_retry_after(response)
- if retry_after:
- time.sleep(retry_after)
- return True
-
- return False
-
- def _sleep_backoff(self) -> None:
- backoff = self.get_backoff_time()
- if backoff <= 0:
- return
- time.sleep(backoff)
-
- def sleep(self, response: BaseHTTPResponse | None = None) -> None:
- """Sleep between retry attempts.
-
- This method will respect a server's ``Retry-After`` response header
- and sleep the duration of the time requested. If that is not present, it
- will use an exponential backoff. By default, the backoff factor is 0 and
- this method will return immediately.
- """
-
- if self.respect_retry_after_header and response:
- slept = self.sleep_for_retry(response)
- if slept:
- return
-
- self._sleep_backoff()
-
- def _is_connection_error(self, err: Exception) -> bool:
- """Errors when we're fairly sure that the server did not receive the
- request, so it should be safe to retry.
- """
- if isinstance(err, ProxyError):
- err = err.original_error
- return isinstance(err, ConnectTimeoutError)
-
- def _is_read_error(self, err: Exception) -> bool:
- """Errors that occur after the request has been started, so we should
- assume that the server began processing it.
- """
- return isinstance(err, (ReadTimeoutError, ProtocolError))
-
- def _is_method_retryable(self, method: str) -> bool:
- """Checks if a given HTTP method should be retried upon, depending if
- it is included in the allowed_methods
- """
- if self.allowed_methods and method.upper() not in self.allowed_methods:
- return False
- return True
-
- def is_retry(
- self, method: str, status_code: int, has_retry_after: bool = False
- ) -> bool:
- """Is this method/status code retryable? (Based on allowlists and control
- variables such as the number of total retries to allow, whether to
- respect the Retry-After header, whether this header is present, and
- whether the returned status code is on the list of status codes to
- be retried upon on the presence of the aforementioned header)
- """
- if not self._is_method_retryable(method):
- return False
-
- if self.status_forcelist and status_code in self.status_forcelist:
- return True
-
- return bool(
- self.total
- and self.respect_retry_after_header
- and has_retry_after
- and (status_code in self.RETRY_AFTER_STATUS_CODES)
- )
-
- def is_exhausted(self) -> bool:
- """Are we out of retries?"""
- retry_counts = [
- x
- for x in (
- self.total,
- self.connect,
- self.read,
- self.redirect,
- self.status,
- self.other,
- )
- if x
- ]
- if not retry_counts:
- return False
-
- return min(retry_counts) < 0
-
- def increment(
- self,
- method: str | None = None,
- url: str | None = None,
- response: BaseHTTPResponse | None = None,
- error: Exception | None = None,
- _pool: ConnectionPool | None = None,
- _stacktrace: TracebackType | None = None,
- ) -> Self:
- """Return a new Retry object with incremented retry counters.
-
- :param response: A response object, or None, if the server did not
- return a response.
- :type response: :class:`~urllib3.response.BaseHTTPResponse`
- :param Exception error: An error encountered during the request, or
- None if the response was received successfully.
-
- :return: A new ``Retry`` object.
- """
- if self.total is False and error:
- # Disabled, indicate to re-raise the error.
- raise reraise(type(error), error, _stacktrace)
-
- total = self.total
- if total is not None:
- total -= 1
-
- connect = self.connect
- read = self.read
- redirect = self.redirect
- status_count = self.status
- other = self.other
- cause = "unknown"
- status = None
- redirect_location = None
-
- if error and self._is_connection_error(error):
- # Connect retry?
- if connect is False:
- raise reraise(type(error), error, _stacktrace)
- elif connect is not None:
- connect -= 1
-
- elif error and self._is_read_error(error):
- # Read retry?
- if read is False or method is None or not self._is_method_retryable(method):
- raise reraise(type(error), error, _stacktrace)
- elif read is not None:
- read -= 1
-
- elif error:
- # Other retry?
- if other is not None:
- other -= 1
-
- elif response and response.get_redirect_location():
- # Redirect retry?
- if redirect is not None:
- redirect -= 1
- cause = "too many redirects"
- response_redirect_location = response.get_redirect_location()
- if response_redirect_location:
- redirect_location = response_redirect_location
- status = response.status
-
- else:
- # Incrementing because of a server error like a 500 in
- # status_forcelist and the given method is in the allowed_methods
- cause = ResponseError.GENERIC_ERROR
- if response and response.status:
- if status_count is not None:
- status_count -= 1
- cause = ResponseError.SPECIFIC_ERROR.format(status_code=response.status)
- status = response.status
-
- history = self.history + (
- RequestHistory(method, url, error, status, redirect_location),
- )
-
- new_retry = self.new(
- total=total,
- connect=connect,
- read=read,
- redirect=redirect,
- status=status_count,
- other=other,
- history=history,
- )
-
- if new_retry.is_exhausted():
- reason = error or ResponseError(cause)
- raise MaxRetryError(_pool, url, reason) from reason # type: ignore[arg-type]
-
- log.debug("Incremented Retry for (url='%s'): %r", url, new_retry)
-
- return new_retry
-
- def __repr__(self) -> str:
- return (
- f"{type(self).__name__}(total={self.total}, connect={self.connect}, "
- f"read={self.read}, redirect={self.redirect}, status={self.status})"
- )
-
-
-# For backwards compatibility (equivalent to pre-v1.9):
-Retry.DEFAULT = Retry(3)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/ssl_.py b/.venv/lib/python3.12/site-packages/urllib3/util/ssl_.py
deleted file mode 100644
index c46dd83..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/ssl_.py
+++ /dev/null
@@ -1,509 +0,0 @@
-from __future__ import annotations
-
-import hmac
-import os
-import socket
-import sys
-import typing
-import warnings
-from binascii import unhexlify
-from hashlib import md5, sha1, sha256
-
-from ..exceptions import ProxySchemeUnsupported, SSLError
-from .url import _BRACELESS_IPV6_ADDRZ_RE, _IPV4_RE
-
-SSLContext = None
-SSLTransport = None
-HAS_NEVER_CHECK_COMMON_NAME = False
-IS_PYOPENSSL = False
-ALPN_PROTOCOLS = ["http/1.1"]
-
-_TYPE_VERSION_INFO = typing.Tuple[int, int, int, str, int]
-
-# Maps the length of a digest to a possible hash function producing this digest
-HASHFUNC_MAP = {32: md5, 40: sha1, 64: sha256}
-
-
-def _is_bpo_43522_fixed(
- implementation_name: str,
- version_info: _TYPE_VERSION_INFO,
- pypy_version_info: _TYPE_VERSION_INFO | None,
-) -> bool:
- """Return True for CPython 3.8.9+, 3.9.3+ or 3.10+ and PyPy 7.3.8+ where
- setting SSLContext.hostname_checks_common_name to False works.
-
- Outside of CPython and PyPy we don't know which implementations work
- or not so we conservatively use our hostname matching as we know that works
- on all implementations.
-
- https://github.com/urllib3/urllib3/issues/2192#issuecomment-821832963
- https://foss.heptapod.net/pypy/pypy/-/issues/3539
- """
- if implementation_name == "pypy":
- # https://foss.heptapod.net/pypy/pypy/-/issues/3129
- return pypy_version_info >= (7, 3, 8) # type: ignore[operator]
- elif implementation_name == "cpython":
- major_minor = version_info[:2]
- micro = version_info[2]
- return (
- (major_minor == (3, 8) and micro >= 9)
- or (major_minor == (3, 9) and micro >= 3)
- or major_minor >= (3, 10)
- )
- else: # Defensive:
- return False
-
-
-def _is_has_never_check_common_name_reliable(
- openssl_version: str,
- openssl_version_number: int,
- implementation_name: str,
- version_info: _TYPE_VERSION_INFO,
- pypy_version_info: _TYPE_VERSION_INFO | None,
-) -> bool:
- # As of May 2023, all released versions of LibreSSL fail to reject certificates with
- # only common names, see https://github.com/urllib3/urllib3/pull/3024
- is_openssl = openssl_version.startswith("OpenSSL ")
- # Before fixing OpenSSL issue #14579, the SSL_new() API was not copying hostflags
- # like X509_CHECK_FLAG_NEVER_CHECK_SUBJECT, which tripped up CPython.
- # https://github.com/openssl/openssl/issues/14579
- # This was released in OpenSSL 1.1.1l+ (>=0x101010cf)
- is_openssl_issue_14579_fixed = openssl_version_number >= 0x101010CF
-
- return is_openssl and (
- is_openssl_issue_14579_fixed
- or _is_bpo_43522_fixed(implementation_name, version_info, pypy_version_info)
- )
-
-
-if typing.TYPE_CHECKING:
- from ssl import VerifyMode
- from typing import TypedDict
-
- from .ssltransport import SSLTransport as SSLTransportType
-
- class _TYPE_PEER_CERT_RET_DICT(TypedDict, total=False):
- subjectAltName: tuple[tuple[str, str], ...]
- subject: tuple[tuple[tuple[str, str], ...], ...]
- serialNumber: str
-
-
-# Mapping from 'ssl.PROTOCOL_TLSX' to 'TLSVersion.X'
-_SSL_VERSION_TO_TLS_VERSION: dict[int, int] = {}
-
-try: # Do we have ssl at all?
- import ssl
- from ssl import ( # type: ignore[assignment]
- CERT_REQUIRED,
- HAS_NEVER_CHECK_COMMON_NAME,
- OP_NO_COMPRESSION,
- OP_NO_TICKET,
- OPENSSL_VERSION,
- OPENSSL_VERSION_NUMBER,
- PROTOCOL_TLS,
- PROTOCOL_TLS_CLIENT,
- OP_NO_SSLv2,
- OP_NO_SSLv3,
- SSLContext,
- TLSVersion,
- )
-
- PROTOCOL_SSLv23 = PROTOCOL_TLS
-
- # Setting SSLContext.hostname_checks_common_name = False didn't work before CPython
- # 3.8.9, 3.9.3, and 3.10 (but OK on PyPy) or OpenSSL 1.1.1l+
- if HAS_NEVER_CHECK_COMMON_NAME and not _is_has_never_check_common_name_reliable(
- OPENSSL_VERSION,
- OPENSSL_VERSION_NUMBER,
- sys.implementation.name,
- sys.version_info,
- sys.pypy_version_info if sys.implementation.name == "pypy" else None, # type: ignore[attr-defined]
- ):
- HAS_NEVER_CHECK_COMMON_NAME = False
-
- # Need to be careful here in case old TLS versions get
- # removed in future 'ssl' module implementations.
- for attr in ("TLSv1", "TLSv1_1", "TLSv1_2"):
- try:
- _SSL_VERSION_TO_TLS_VERSION[getattr(ssl, f"PROTOCOL_{attr}")] = getattr(
- TLSVersion, attr
- )
- except AttributeError: # Defensive:
- continue
-
- from .ssltransport import SSLTransport # type: ignore[assignment]
-except ImportError:
- OP_NO_COMPRESSION = 0x20000 # type: ignore[assignment]
- OP_NO_TICKET = 0x4000 # type: ignore[assignment]
- OP_NO_SSLv2 = 0x1000000 # type: ignore[assignment]
- OP_NO_SSLv3 = 0x2000000 # type: ignore[assignment]
- PROTOCOL_SSLv23 = PROTOCOL_TLS = 2 # type: ignore[assignment]
- PROTOCOL_TLS_CLIENT = 16 # type: ignore[assignment]
-
-
-_TYPE_PEER_CERT_RET = typing.Union["_TYPE_PEER_CERT_RET_DICT", bytes, None]
-
-
-def assert_fingerprint(cert: bytes | None, fingerprint: str) -> None:
- """
- Checks if given fingerprint matches the supplied certificate.
-
- :param cert:
- Certificate as bytes object.
- :param fingerprint:
- Fingerprint as string of hexdigits, can be interspersed by colons.
- """
-
- if cert is None:
- raise SSLError("No certificate for the peer.")
-
- fingerprint = fingerprint.replace(":", "").lower()
- digest_length = len(fingerprint)
- hashfunc = HASHFUNC_MAP.get(digest_length)
- if not hashfunc:
- raise SSLError(f"Fingerprint of invalid length: {fingerprint}")
-
- # We need encode() here for py32; works on py2 and p33.
- fingerprint_bytes = unhexlify(fingerprint.encode())
-
- cert_digest = hashfunc(cert).digest()
-
- if not hmac.compare_digest(cert_digest, fingerprint_bytes):
- raise SSLError(
- f'Fingerprints did not match. Expected "{fingerprint}", got "{cert_digest.hex()}"'
- )
-
-
-def resolve_cert_reqs(candidate: None | int | str) -> VerifyMode:
- """
- Resolves the argument to a numeric constant, which can be passed to
- the wrap_socket function/method from the ssl module.
- Defaults to :data:`ssl.CERT_REQUIRED`.
- If given a string it is assumed to be the name of the constant in the
- :mod:`ssl` module or its abbreviation.
- (So you can specify `REQUIRED` instead of `CERT_REQUIRED`.
- If it's neither `None` nor a string we assume it is already the numeric
- constant which can directly be passed to wrap_socket.
- """
- if candidate is None:
- return CERT_REQUIRED
-
- if isinstance(candidate, str):
- res = getattr(ssl, candidate, None)
- if res is None:
- res = getattr(ssl, "CERT_" + candidate)
- return res # type: ignore[no-any-return]
-
- return candidate # type: ignore[return-value]
-
-
-def resolve_ssl_version(candidate: None | int | str) -> int:
- """
- like resolve_cert_reqs
- """
- if candidate is None:
- return PROTOCOL_TLS
-
- if isinstance(candidate, str):
- res = getattr(ssl, candidate, None)
- if res is None:
- res = getattr(ssl, "PROTOCOL_" + candidate)
- return typing.cast(int, res)
-
- return candidate
-
-
-def create_urllib3_context(
- ssl_version: int | None = None,
- cert_reqs: int | None = None,
- options: int | None = None,
- ciphers: str | None = None,
- ssl_minimum_version: int | None = None,
- ssl_maximum_version: int | None = None,
-) -> ssl.SSLContext:
- """Creates and configures an :class:`ssl.SSLContext` instance for use with urllib3.
-
- :param ssl_version:
- The desired protocol version to use. This will default to
- PROTOCOL_SSLv23 which will negotiate the highest protocol that both
- the server and your installation of OpenSSL support.
-
- This parameter is deprecated instead use 'ssl_minimum_version'.
- :param ssl_minimum_version:
- The minimum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value.
- :param ssl_maximum_version:
- The maximum version of TLS to be used. Use the 'ssl.TLSVersion' enum for specifying the value.
- Not recommended to set to anything other than 'ssl.TLSVersion.MAXIMUM_SUPPORTED' which is the
- default value.
- :param cert_reqs:
- Whether to require the certificate verification. This defaults to
- ``ssl.CERT_REQUIRED``.
- :param options:
- Specific OpenSSL options. These default to ``ssl.OP_NO_SSLv2``,
- ``ssl.OP_NO_SSLv3``, ``ssl.OP_NO_COMPRESSION``, and ``ssl.OP_NO_TICKET``.
- :param ciphers:
- Which cipher suites to allow the server to select. Defaults to either system configured
- ciphers if OpenSSL 1.1.1+, otherwise uses a secure default set of ciphers.
- :returns:
- Constructed SSLContext object with specified options
- :rtype: SSLContext
- """
- if SSLContext is None:
- raise TypeError("Can't create an SSLContext object without an ssl module")
-
- # This means 'ssl_version' was specified as an exact value.
- if ssl_version not in (None, PROTOCOL_TLS, PROTOCOL_TLS_CLIENT):
- # Disallow setting 'ssl_version' and 'ssl_minimum|maximum_version'
- # to avoid conflicts.
- if ssl_minimum_version is not None or ssl_maximum_version is not None:
- raise ValueError(
- "Can't specify both 'ssl_version' and either "
- "'ssl_minimum_version' or 'ssl_maximum_version'"
- )
-
- # 'ssl_version' is deprecated and will be removed in the future.
- else:
- # Use 'ssl_minimum_version' and 'ssl_maximum_version' instead.
- ssl_minimum_version = _SSL_VERSION_TO_TLS_VERSION.get(
- ssl_version, TLSVersion.MINIMUM_SUPPORTED
- )
- ssl_maximum_version = _SSL_VERSION_TO_TLS_VERSION.get(
- ssl_version, TLSVersion.MAXIMUM_SUPPORTED
- )
-
- # This warning message is pushing users to use 'ssl_minimum_version'
- # instead of both min/max. Best practice is to only set the minimum version and
- # keep the maximum version to be it's default value: 'TLSVersion.MAXIMUM_SUPPORTED'
- warnings.warn(
- "'ssl_version' option is deprecated and will be "
- "removed in urllib3 v2.1.0. Instead use 'ssl_minimum_version'",
- category=DeprecationWarning,
- stacklevel=2,
- )
-
- # PROTOCOL_TLS is deprecated in Python 3.10 so we always use PROTOCOL_TLS_CLIENT
- context = SSLContext(PROTOCOL_TLS_CLIENT)
-
- if ssl_minimum_version is not None:
- context.minimum_version = ssl_minimum_version
- else: # Python <3.10 defaults to 'MINIMUM_SUPPORTED' so explicitly set TLSv1.2 here
- context.minimum_version = TLSVersion.TLSv1_2
-
- if ssl_maximum_version is not None:
- context.maximum_version = ssl_maximum_version
-
- # Unless we're given ciphers defer to either system ciphers in
- # the case of OpenSSL 1.1.1+ or use our own secure default ciphers.
- if ciphers:
- context.set_ciphers(ciphers)
-
- # Setting the default here, as we may have no ssl module on import
- cert_reqs = ssl.CERT_REQUIRED if cert_reqs is None else cert_reqs
-
- if options is None:
- options = 0
- # SSLv2 is easily broken and is considered harmful and dangerous
- options |= OP_NO_SSLv2
- # SSLv3 has several problems and is now dangerous
- options |= OP_NO_SSLv3
- # Disable compression to prevent CRIME attacks for OpenSSL 1.0+
- # (issue #309)
- options |= OP_NO_COMPRESSION
- # TLSv1.2 only. Unless set explicitly, do not request tickets.
- # This may save some bandwidth on wire, and although the ticket is encrypted,
- # there is a risk associated with it being on wire,
- # if the server is not rotating its ticketing keys properly.
- options |= OP_NO_TICKET
-
- context.options |= options
-
- # Enable post-handshake authentication for TLS 1.3, see GH #1634. PHA is
- # necessary for conditional client cert authentication with TLS 1.3.
- # The attribute is None for OpenSSL <= 1.1.0 or does not exist when using
- # an SSLContext created by pyOpenSSL.
- if getattr(context, "post_handshake_auth", None) is not None:
- context.post_handshake_auth = True
-
- # The order of the below lines setting verify_mode and check_hostname
- # matter due to safe-guards SSLContext has to prevent an SSLContext with
- # check_hostname=True, verify_mode=NONE/OPTIONAL.
- # We always set 'check_hostname=False' for pyOpenSSL so we rely on our own
- # 'ssl.match_hostname()' implementation.
- if cert_reqs == ssl.CERT_REQUIRED and not IS_PYOPENSSL:
- context.verify_mode = cert_reqs
- context.check_hostname = True
- else:
- context.check_hostname = False
- context.verify_mode = cert_reqs
-
- try:
- context.hostname_checks_common_name = False
- except AttributeError: # Defensive: for CPython < 3.8.9 and 3.9.3; for PyPy < 7.3.8
- pass
-
- # Enable logging of TLS session keys via defacto standard environment variable
- # 'SSLKEYLOGFILE', if the feature is available (Python 3.8+). Skip empty values.
- if hasattr(context, "keylog_filename"):
- sslkeylogfile = os.environ.get("SSLKEYLOGFILE")
- if sslkeylogfile:
- context.keylog_filename = sslkeylogfile
-
- return context
-
-
-@typing.overload
-def ssl_wrap_socket(
- sock: socket.socket,
- keyfile: str | None = ...,
- certfile: str | None = ...,
- cert_reqs: int | None = ...,
- ca_certs: str | None = ...,
- server_hostname: str | None = ...,
- ssl_version: int | None = ...,
- ciphers: str | None = ...,
- ssl_context: ssl.SSLContext | None = ...,
- ca_cert_dir: str | None = ...,
- key_password: str | None = ...,
- ca_cert_data: None | str | bytes = ...,
- tls_in_tls: typing.Literal[False] = ...,
-) -> ssl.SSLSocket:
- ...
-
-
-@typing.overload
-def ssl_wrap_socket(
- sock: socket.socket,
- keyfile: str | None = ...,
- certfile: str | None = ...,
- cert_reqs: int | None = ...,
- ca_certs: str | None = ...,
- server_hostname: str | None = ...,
- ssl_version: int | None = ...,
- ciphers: str | None = ...,
- ssl_context: ssl.SSLContext | None = ...,
- ca_cert_dir: str | None = ...,
- key_password: str | None = ...,
- ca_cert_data: None | str | bytes = ...,
- tls_in_tls: bool = ...,
-) -> ssl.SSLSocket | SSLTransportType:
- ...
-
-
-def ssl_wrap_socket(
- sock: socket.socket,
- keyfile: str | None = None,
- certfile: str | None = None,
- cert_reqs: int | None = None,
- ca_certs: str | None = None,
- server_hostname: str | None = None,
- ssl_version: int | None = None,
- ciphers: str | None = None,
- ssl_context: ssl.SSLContext | None = None,
- ca_cert_dir: str | None = None,
- key_password: str | None = None,
- ca_cert_data: None | str | bytes = None,
- tls_in_tls: bool = False,
-) -> ssl.SSLSocket | SSLTransportType:
- """
- All arguments except for server_hostname, ssl_context, tls_in_tls, ca_cert_data and
- ca_cert_dir have the same meaning as they do when using
- :func:`ssl.create_default_context`, :meth:`ssl.SSLContext.load_cert_chain`,
- :meth:`ssl.SSLContext.set_ciphers` and :meth:`ssl.SSLContext.wrap_socket`.
-
- :param server_hostname:
- When SNI is supported, the expected hostname of the certificate
- :param ssl_context:
- A pre-made :class:`SSLContext` object. If none is provided, one will
- be created using :func:`create_urllib3_context`.
- :param ciphers:
- A string of ciphers we wish the client to support.
- :param ca_cert_dir:
- A directory containing CA certificates in multiple separate files, as
- supported by OpenSSL's -CApath flag or the capath argument to
- SSLContext.load_verify_locations().
- :param key_password:
- Optional password if the keyfile is encrypted.
- :param ca_cert_data:
- Optional string containing CA certificates in PEM format suitable for
- passing as the cadata parameter to SSLContext.load_verify_locations()
- :param tls_in_tls:
- Use SSLTransport to wrap the existing socket.
- """
- context = ssl_context
- if context is None:
- # Note: This branch of code and all the variables in it are only used in tests.
- # We should consider deprecating and removing this code.
- context = create_urllib3_context(ssl_version, cert_reqs, ciphers=ciphers)
-
- if ca_certs or ca_cert_dir or ca_cert_data:
- try:
- context.load_verify_locations(ca_certs, ca_cert_dir, ca_cert_data)
- except OSError as e:
- raise SSLError(e) from e
-
- elif ssl_context is None and hasattr(context, "load_default_certs"):
- # try to load OS default certs; works well on Windows.
- context.load_default_certs()
-
- # Attempt to detect if we get the goofy behavior of the
- # keyfile being encrypted and OpenSSL asking for the
- # passphrase via the terminal and instead error out.
- if keyfile and key_password is None and _is_key_file_encrypted(keyfile):
- raise SSLError("Client private key is encrypted, password is required")
-
- if certfile:
- if key_password is None:
- context.load_cert_chain(certfile, keyfile)
- else:
- context.load_cert_chain(certfile, keyfile, key_password)
-
- try:
- context.set_alpn_protocols(ALPN_PROTOCOLS)
- except NotImplementedError: # Defensive: in CI, we always have set_alpn_protocols
- pass
-
- ssl_sock = _ssl_wrap_socket_impl(sock, context, tls_in_tls, server_hostname)
- return ssl_sock
-
-
-def is_ipaddress(hostname: str | bytes) -> bool:
- """Detects whether the hostname given is an IPv4 or IPv6 address.
- Also detects IPv6 addresses with Zone IDs.
-
- :param str hostname: Hostname to examine.
- :return: True if the hostname is an IP address, False otherwise.
- """
- if isinstance(hostname, bytes):
- # IDN A-label bytes are ASCII compatible.
- hostname = hostname.decode("ascii")
- return bool(_IPV4_RE.match(hostname) or _BRACELESS_IPV6_ADDRZ_RE.match(hostname))
-
-
-def _is_key_file_encrypted(key_file: str) -> bool:
- """Detects if a key file is encrypted or not."""
- with open(key_file) as f:
- for line in f:
- # Look for Proc-Type: 4,ENCRYPTED
- if "ENCRYPTED" in line:
- return True
-
- return False
-
-
-def _ssl_wrap_socket_impl(
- sock: socket.socket,
- ssl_context: ssl.SSLContext,
- tls_in_tls: bool,
- server_hostname: str | None = None,
-) -> ssl.SSLSocket | SSLTransportType:
- if tls_in_tls:
- if not SSLTransport:
- # Import error, ssl is not available.
- raise ProxySchemeUnsupported(
- "TLS in TLS requires support for the 'ssl' module"
- )
-
- SSLTransport._validate_ssl_context_for_tls_in_tls(ssl_context)
- return SSLTransport(sock, ssl_context, server_hostname)
-
- return ssl_context.wrap_socket(sock, server_hostname=server_hostname)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/ssl_match_hostname.py b/.venv/lib/python3.12/site-packages/urllib3/util/ssl_match_hostname.py
deleted file mode 100644
index 453cfd4..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/ssl_match_hostname.py
+++ /dev/null
@@ -1,159 +0,0 @@
-"""The match_hostname() function from Python 3.5, essential when using SSL."""
-
-# Note: This file is under the PSF license as the code comes from the python
-# stdlib. http://docs.python.org/3/license.html
-# It is modified to remove commonName support.
-
-from __future__ import annotations
-
-import ipaddress
-import re
-import typing
-from ipaddress import IPv4Address, IPv6Address
-
-if typing.TYPE_CHECKING:
- from .ssl_ import _TYPE_PEER_CERT_RET_DICT
-
-__version__ = "3.5.0.1"
-
-
-class CertificateError(ValueError):
- pass
-
-
-def _dnsname_match(
- dn: typing.Any, hostname: str, max_wildcards: int = 1
-) -> typing.Match[str] | None | bool:
- """Matching according to RFC 6125, section 6.4.3
-
- http://tools.ietf.org/html/rfc6125#section-6.4.3
- """
- pats = []
- if not dn:
- return False
-
- # Ported from python3-syntax:
- # leftmost, *remainder = dn.split(r'.')
- parts = dn.split(r".")
- leftmost = parts[0]
- remainder = parts[1:]
-
- wildcards = leftmost.count("*")
- if wildcards > max_wildcards:
- # Issue #17980: avoid denials of service by refusing more
- # than one wildcard per fragment. A survey of established
- # policy among SSL implementations showed it to be a
- # reasonable choice.
- raise CertificateError(
- "too many wildcards in certificate DNS name: " + repr(dn)
- )
-
- # speed up common case w/o wildcards
- if not wildcards:
- return bool(dn.lower() == hostname.lower())
-
- # RFC 6125, section 6.4.3, subitem 1.
- # The client SHOULD NOT attempt to match a presented identifier in which
- # the wildcard character comprises a label other than the left-most label.
- if leftmost == "*":
- # When '*' is a fragment by itself, it matches a non-empty dotless
- # fragment.
- pats.append("[^.]+")
- elif leftmost.startswith("xn--") or hostname.startswith("xn--"):
- # RFC 6125, section 6.4.3, subitem 3.
- # The client SHOULD NOT attempt to match a presented identifier
- # where the wildcard character is embedded within an A-label or
- # U-label of an internationalized domain name.
- pats.append(re.escape(leftmost))
- else:
- # Otherwise, '*' matches any dotless string, e.g. www*
- pats.append(re.escape(leftmost).replace(r"\*", "[^.]*"))
-
- # add the remaining fragments, ignore any wildcards
- for frag in remainder:
- pats.append(re.escape(frag))
-
- pat = re.compile(r"\A" + r"\.".join(pats) + r"\Z", re.IGNORECASE)
- return pat.match(hostname)
-
-
-def _ipaddress_match(ipname: str, host_ip: IPv4Address | IPv6Address) -> bool:
- """Exact matching of IP addresses.
-
- RFC 9110 section 4.3.5: "A reference identity of IP-ID contains the decoded
- bytes of the IP address. An IP version 4 address is 4 octets, and an IP
- version 6 address is 16 octets. [...] A reference identity of type IP-ID
- matches if the address is identical to an iPAddress value of the
- subjectAltName extension of the certificate."
- """
- # OpenSSL may add a trailing newline to a subjectAltName's IP address
- # Divergence from upstream: ipaddress can't handle byte str
- ip = ipaddress.ip_address(ipname.rstrip())
- return bool(ip.packed == host_ip.packed)
-
-
-def match_hostname(
- cert: _TYPE_PEER_CERT_RET_DICT | None,
- hostname: str,
- hostname_checks_common_name: bool = False,
-) -> None:
- """Verify that *cert* (in decoded format as returned by
- SSLSocket.getpeercert()) matches the *hostname*. RFC 2818 and RFC 6125
- rules are followed, but IP addresses are not accepted for *hostname*.
-
- CertificateError is raised on failure. On success, the function
- returns nothing.
- """
- if not cert:
- raise ValueError(
- "empty or no certificate, match_hostname needs a "
- "SSL socket or SSL context with either "
- "CERT_OPTIONAL or CERT_REQUIRED"
- )
- try:
- # Divergence from upstream: ipaddress can't handle byte str
- #
- # The ipaddress module shipped with Python < 3.9 does not support
- # scoped IPv6 addresses so we unconditionally strip the Zone IDs for
- # now. Once we drop support for Python 3.9 we can remove this branch.
- if "%" in hostname:
- host_ip = ipaddress.ip_address(hostname[: hostname.rfind("%")])
- else:
- host_ip = ipaddress.ip_address(hostname)
-
- except ValueError:
- # Not an IP address (common case)
- host_ip = None
- dnsnames = []
- san: tuple[tuple[str, str], ...] = cert.get("subjectAltName", ())
- key: str
- value: str
- for key, value in san:
- if key == "DNS":
- if host_ip is None and _dnsname_match(value, hostname):
- return
- dnsnames.append(value)
- elif key == "IP Address":
- if host_ip is not None and _ipaddress_match(value, host_ip):
- return
- dnsnames.append(value)
-
- # We only check 'commonName' if it's enabled and we're not verifying
- # an IP address. IP addresses aren't valid within 'commonName'.
- if hostname_checks_common_name and host_ip is None and not dnsnames:
- for sub in cert.get("subject", ()):
- for key, value in sub:
- if key == "commonName":
- if _dnsname_match(value, hostname):
- return
- dnsnames.append(value)
-
- if len(dnsnames) > 1:
- raise CertificateError(
- "hostname %r "
- "doesn't match either of %s" % (hostname, ", ".join(map(repr, dnsnames)))
- )
- elif len(dnsnames) == 1:
- raise CertificateError(f"hostname {hostname!r} doesn't match {dnsnames[0]!r}")
- else:
- raise CertificateError("no appropriate subjectAltName fields were found")
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/ssltransport.py b/.venv/lib/python3.12/site-packages/urllib3/util/ssltransport.py
deleted file mode 100644
index b52c477..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/ssltransport.py
+++ /dev/null
@@ -1,279 +0,0 @@
-from __future__ import annotations
-
-import io
-import socket
-import ssl
-import typing
-
-from ..exceptions import ProxySchemeUnsupported
-
-if typing.TYPE_CHECKING:
- from typing_extensions import Self
-
- from .ssl_ import _TYPE_PEER_CERT_RET, _TYPE_PEER_CERT_RET_DICT
-
-
-_WriteBuffer = typing.Union[bytearray, memoryview]
-_ReturnValue = typing.TypeVar("_ReturnValue")
-
-SSL_BLOCKSIZE = 16384
-
-
-class SSLTransport:
- """
- The SSLTransport wraps an existing socket and establishes an SSL connection.
-
- Contrary to Python's implementation of SSLSocket, it allows you to chain
- multiple TLS connections together. It's particularly useful if you need to
- implement TLS within TLS.
-
- The class supports most of the socket API operations.
- """
-
- @staticmethod
- def _validate_ssl_context_for_tls_in_tls(ssl_context: ssl.SSLContext) -> None:
- """
- Raises a ProxySchemeUnsupported if the provided ssl_context can't be used
- for TLS in TLS.
-
- The only requirement is that the ssl_context provides the 'wrap_bio'
- methods.
- """
-
- if not hasattr(ssl_context, "wrap_bio"):
- raise ProxySchemeUnsupported(
- "TLS in TLS requires SSLContext.wrap_bio() which isn't "
- "available on non-native SSLContext"
- )
-
- def __init__(
- self,
- socket: socket.socket,
- ssl_context: ssl.SSLContext,
- server_hostname: str | None = None,
- suppress_ragged_eofs: bool = True,
- ) -> None:
- """
- Create an SSLTransport around socket using the provided ssl_context.
- """
- self.incoming = ssl.MemoryBIO()
- self.outgoing = ssl.MemoryBIO()
-
- self.suppress_ragged_eofs = suppress_ragged_eofs
- self.socket = socket
-
- self.sslobj = ssl_context.wrap_bio(
- self.incoming, self.outgoing, server_hostname=server_hostname
- )
-
- # Perform initial handshake.
- self._ssl_io_loop(self.sslobj.do_handshake)
-
- def __enter__(self) -> Self:
- return self
-
- def __exit__(self, *_: typing.Any) -> None:
- self.close()
-
- def fileno(self) -> int:
- return self.socket.fileno()
-
- def read(self, len: int = 1024, buffer: typing.Any | None = None) -> int | bytes:
- return self._wrap_ssl_read(len, buffer)
-
- def recv(self, buflen: int = 1024, flags: int = 0) -> int | bytes:
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to recv")
- return self._wrap_ssl_read(buflen)
-
- def recv_into(
- self,
- buffer: _WriteBuffer,
- nbytes: int | None = None,
- flags: int = 0,
- ) -> None | int | bytes:
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to recv_into")
- if nbytes is None:
- nbytes = len(buffer)
- return self.read(nbytes, buffer)
-
- def sendall(self, data: bytes, flags: int = 0) -> None:
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to sendall")
- count = 0
- with memoryview(data) as view, view.cast("B") as byte_view:
- amount = len(byte_view)
- while count < amount:
- v = self.send(byte_view[count:])
- count += v
-
- def send(self, data: bytes, flags: int = 0) -> int:
- if flags != 0:
- raise ValueError("non-zero flags not allowed in calls to send")
- return self._ssl_io_loop(self.sslobj.write, data)
-
- def makefile(
- self,
- mode: str,
- buffering: int | None = None,
- *,
- encoding: str | None = None,
- errors: str | None = None,
- newline: str | None = None,
- ) -> typing.BinaryIO | typing.TextIO | socket.SocketIO:
- """
- Python's httpclient uses makefile and buffered io when reading HTTP
- messages and we need to support it.
-
- This is unfortunately a copy and paste of socket.py makefile with small
- changes to point to the socket directly.
- """
- if not set(mode) <= {"r", "w", "b"}:
- raise ValueError(f"invalid mode {mode!r} (only r, w, b allowed)")
-
- writing = "w" in mode
- reading = "r" in mode or not writing
- assert reading or writing
- binary = "b" in mode
- rawmode = ""
- if reading:
- rawmode += "r"
- if writing:
- rawmode += "w"
- raw = socket.SocketIO(self, rawmode) # type: ignore[arg-type]
- self.socket._io_refs += 1 # type: ignore[attr-defined]
- if buffering is None:
- buffering = -1
- if buffering < 0:
- buffering = io.DEFAULT_BUFFER_SIZE
- if buffering == 0:
- if not binary:
- raise ValueError("unbuffered streams must be binary")
- return raw
- buffer: typing.BinaryIO
- if reading and writing:
- buffer = io.BufferedRWPair(raw, raw, buffering) # type: ignore[assignment]
- elif reading:
- buffer = io.BufferedReader(raw, buffering)
- else:
- assert writing
- buffer = io.BufferedWriter(raw, buffering)
- if binary:
- return buffer
- text = io.TextIOWrapper(buffer, encoding, errors, newline)
- text.mode = mode # type: ignore[misc]
- return text
-
- def unwrap(self) -> None:
- self._ssl_io_loop(self.sslobj.unwrap)
-
- def close(self) -> None:
- self.socket.close()
-
- @typing.overload
- def getpeercert(
- self, binary_form: typing.Literal[False] = ...
- ) -> _TYPE_PEER_CERT_RET_DICT | None:
- ...
-
- @typing.overload
- def getpeercert(self, binary_form: typing.Literal[True]) -> bytes | None:
- ...
-
- def getpeercert(self, binary_form: bool = False) -> _TYPE_PEER_CERT_RET:
- return self.sslobj.getpeercert(binary_form) # type: ignore[return-value]
-
- def version(self) -> str | None:
- return self.sslobj.version()
-
- def cipher(self) -> tuple[str, str, int] | None:
- return self.sslobj.cipher()
-
- def selected_alpn_protocol(self) -> str | None:
- return self.sslobj.selected_alpn_protocol()
-
- def selected_npn_protocol(self) -> str | None:
- return self.sslobj.selected_npn_protocol()
-
- def shared_ciphers(self) -> list[tuple[str, str, int]] | None:
- return self.sslobj.shared_ciphers()
-
- def compression(self) -> str | None:
- return self.sslobj.compression()
-
- def settimeout(self, value: float | None) -> None:
- self.socket.settimeout(value)
-
- def gettimeout(self) -> float | None:
- return self.socket.gettimeout()
-
- def _decref_socketios(self) -> None:
- self.socket._decref_socketios() # type: ignore[attr-defined]
-
- def _wrap_ssl_read(self, len: int, buffer: bytearray | None = None) -> int | bytes:
- try:
- return self._ssl_io_loop(self.sslobj.read, len, buffer)
- except ssl.SSLError as e:
- if e.errno == ssl.SSL_ERROR_EOF and self.suppress_ragged_eofs:
- return 0 # eof, return 0.
- else:
- raise
-
- # func is sslobj.do_handshake or sslobj.unwrap
- @typing.overload
- def _ssl_io_loop(self, func: typing.Callable[[], None]) -> None:
- ...
-
- # func is sslobj.write, arg1 is data
- @typing.overload
- def _ssl_io_loop(self, func: typing.Callable[[bytes], int], arg1: bytes) -> int:
- ...
-
- # func is sslobj.read, arg1 is len, arg2 is buffer
- @typing.overload
- def _ssl_io_loop(
- self,
- func: typing.Callable[[int, bytearray | None], bytes],
- arg1: int,
- arg2: bytearray | None,
- ) -> bytes:
- ...
-
- def _ssl_io_loop(
- self,
- func: typing.Callable[..., _ReturnValue],
- arg1: None | bytes | int = None,
- arg2: bytearray | None = None,
- ) -> _ReturnValue:
- """Performs an I/O loop between incoming/outgoing and the socket."""
- should_loop = True
- ret = None
-
- while should_loop:
- errno = None
- try:
- if arg1 is None and arg2 is None:
- ret = func()
- elif arg2 is None:
- ret = func(arg1)
- else:
- ret = func(arg1, arg2)
- except ssl.SSLError as e:
- if e.errno not in (ssl.SSL_ERROR_WANT_READ, ssl.SSL_ERROR_WANT_WRITE):
- # WANT_READ, and WANT_WRITE are expected, others are not.
- raise e
- errno = e.errno
-
- buf = self.outgoing.read()
- self.socket.sendall(buf)
-
- if errno is None:
- should_loop = False
- elif errno == ssl.SSL_ERROR_WANT_READ:
- buf = self.socket.recv(SSL_BLOCKSIZE)
- if buf:
- self.incoming.write(buf)
- else:
- self.incoming.write_eof()
- return typing.cast(_ReturnValue, ret)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/timeout.py b/.venv/lib/python3.12/site-packages/urllib3/util/timeout.py
deleted file mode 100644
index 4bb1be1..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/timeout.py
+++ /dev/null
@@ -1,275 +0,0 @@
-from __future__ import annotations
-
-import time
-import typing
-from enum import Enum
-from socket import getdefaulttimeout
-
-from ..exceptions import TimeoutStateError
-
-if typing.TYPE_CHECKING:
- from typing import Final
-
-
-class _TYPE_DEFAULT(Enum):
- # This value should never be passed to socket.settimeout() so for safety we use a -1.
- # socket.settimout() raises a ValueError for negative values.
- token = -1
-
-
-_DEFAULT_TIMEOUT: Final[_TYPE_DEFAULT] = _TYPE_DEFAULT.token
-
-_TYPE_TIMEOUT = typing.Optional[typing.Union[float, _TYPE_DEFAULT]]
-
-
-class Timeout:
- """Timeout configuration.
-
- Timeouts can be defined as a default for a pool:
-
- .. code-block:: python
-
- import urllib3
-
- timeout = urllib3.util.Timeout(connect=2.0, read=7.0)
-
- http = urllib3.PoolManager(timeout=timeout)
-
- resp = http.request("GET", "https://example.com/")
-
- print(resp.status)
-
- Or per-request (which overrides the default for the pool):
-
- .. code-block:: python
-
- response = http.request("GET", "https://example.com/", timeout=Timeout(10))
-
- Timeouts can be disabled by setting all the parameters to ``None``:
-
- .. code-block:: python
-
- no_timeout = Timeout(connect=None, read=None)
- response = http.request("GET", "https://example.com/", timeout=no_timeout)
-
-
- :param total:
- This combines the connect and read timeouts into one; the read timeout
- will be set to the time leftover from the connect attempt. In the
- event that both a connect timeout and a total are specified, or a read
- timeout and a total are specified, the shorter timeout will be applied.
-
- Defaults to None.
-
- :type total: int, float, or None
-
- :param connect:
- The maximum amount of time (in seconds) to wait for a connection
- attempt to a server to succeed. Omitting the parameter will default the
- connect timeout to the system default, probably `the global default
- timeout in socket.py
- `_.
- None will set an infinite timeout for connection attempts.
-
- :type connect: int, float, or None
-
- :param read:
- The maximum amount of time (in seconds) to wait between consecutive
- read operations for a response from the server. Omitting the parameter
- will default the read timeout to the system default, probably `the
- global default timeout in socket.py
- `_.
- None will set an infinite timeout.
-
- :type read: int, float, or None
-
- .. note::
-
- Many factors can affect the total amount of time for urllib3 to return
- an HTTP response.
-
- For example, Python's DNS resolver does not obey the timeout specified
- on the socket. Other factors that can affect total request time include
- high CPU load, high swap, the program running at a low priority level,
- or other behaviors.
-
- In addition, the read and total timeouts only measure the time between
- read operations on the socket connecting the client and the server,
- not the total amount of time for the request to return a complete
- response. For most requests, the timeout is raised because the server
- has not sent the first byte in the specified time. This is not always
- the case; if a server streams one byte every fifteen seconds, a timeout
- of 20 seconds will not trigger, even though the request will take
- several minutes to complete.
- """
-
- #: A sentinel object representing the default timeout value
- DEFAULT_TIMEOUT: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT
-
- def __init__(
- self,
- total: _TYPE_TIMEOUT = None,
- connect: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- read: _TYPE_TIMEOUT = _DEFAULT_TIMEOUT,
- ) -> None:
- self._connect = self._validate_timeout(connect, "connect")
- self._read = self._validate_timeout(read, "read")
- self.total = self._validate_timeout(total, "total")
- self._start_connect: float | None = None
-
- def __repr__(self) -> str:
- return f"{type(self).__name__}(connect={self._connect!r}, read={self._read!r}, total={self.total!r})"
-
- # __str__ provided for backwards compatibility
- __str__ = __repr__
-
- @staticmethod
- def resolve_default_timeout(timeout: _TYPE_TIMEOUT) -> float | None:
- return getdefaulttimeout() if timeout is _DEFAULT_TIMEOUT else timeout
-
- @classmethod
- def _validate_timeout(cls, value: _TYPE_TIMEOUT, name: str) -> _TYPE_TIMEOUT:
- """Check that a timeout attribute is valid.
-
- :param value: The timeout value to validate
- :param name: The name of the timeout attribute to validate. This is
- used to specify in error messages.
- :return: The validated and casted version of the given value.
- :raises ValueError: If it is a numeric value less than or equal to
- zero, or the type is not an integer, float, or None.
- """
- if value is None or value is _DEFAULT_TIMEOUT:
- return value
-
- if isinstance(value, bool):
- raise ValueError(
- "Timeout cannot be a boolean value. It must "
- "be an int, float or None."
- )
- try:
- float(value)
- except (TypeError, ValueError):
- raise ValueError(
- "Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value)
- ) from None
-
- try:
- if value <= 0:
- raise ValueError(
- "Attempted to set %s timeout to %s, but the "
- "timeout cannot be set to a value less "
- "than or equal to 0." % (name, value)
- )
- except TypeError:
- raise ValueError(
- "Timeout value %s was %s, but it must be an "
- "int, float or None." % (name, value)
- ) from None
-
- return value
-
- @classmethod
- def from_float(cls, timeout: _TYPE_TIMEOUT) -> Timeout:
- """Create a new Timeout from a legacy timeout value.
-
- The timeout value used by httplib.py sets the same timeout on the
- connect(), and recv() socket requests. This creates a :class:`Timeout`
- object that sets the individual timeouts to the ``timeout`` value
- passed to this function.
-
- :param timeout: The legacy timeout value.
- :type timeout: integer, float, :attr:`urllib3.util.Timeout.DEFAULT_TIMEOUT`, or None
- :return: Timeout object
- :rtype: :class:`Timeout`
- """
- return Timeout(read=timeout, connect=timeout)
-
- def clone(self) -> Timeout:
- """Create a copy of the timeout object
-
- Timeout properties are stored per-pool but each request needs a fresh
- Timeout object to ensure each one has its own start/stop configured.
-
- :return: a copy of the timeout object
- :rtype: :class:`Timeout`
- """
- # We can't use copy.deepcopy because that will also create a new object
- # for _GLOBAL_DEFAULT_TIMEOUT, which socket.py uses as a sentinel to
- # detect the user default.
- return Timeout(connect=self._connect, read=self._read, total=self.total)
-
- def start_connect(self) -> float:
- """Start the timeout clock, used during a connect() attempt
-
- :raises urllib3.exceptions.TimeoutStateError: if you attempt
- to start a timer that has been started already.
- """
- if self._start_connect is not None:
- raise TimeoutStateError("Timeout timer has already been started.")
- self._start_connect = time.monotonic()
- return self._start_connect
-
- def get_connect_duration(self) -> float:
- """Gets the time elapsed since the call to :meth:`start_connect`.
-
- :return: Elapsed time in seconds.
- :rtype: float
- :raises urllib3.exceptions.TimeoutStateError: if you attempt
- to get duration for a timer that hasn't been started.
- """
- if self._start_connect is None:
- raise TimeoutStateError(
- "Can't get connect duration for timer that has not started."
- )
- return time.monotonic() - self._start_connect
-
- @property
- def connect_timeout(self) -> _TYPE_TIMEOUT:
- """Get the value to use when setting a connection timeout.
-
- This will be a positive float or integer, the value None
- (never timeout), or the default system timeout.
-
- :return: Connect timeout.
- :rtype: int, float, :attr:`Timeout.DEFAULT_TIMEOUT` or None
- """
- if self.total is None:
- return self._connect
-
- if self._connect is None or self._connect is _DEFAULT_TIMEOUT:
- return self.total
-
- return min(self._connect, self.total) # type: ignore[type-var]
-
- @property
- def read_timeout(self) -> float | None:
- """Get the value for the read timeout.
-
- This assumes some time has elapsed in the connection timeout and
- computes the read timeout appropriately.
-
- If self.total is set, the read timeout is dependent on the amount of
- time taken by the connect timeout. If the connection time has not been
- established, a :exc:`~urllib3.exceptions.TimeoutStateError` will be
- raised.
-
- :return: Value to use for the read timeout.
- :rtype: int, float or None
- :raises urllib3.exceptions.TimeoutStateError: If :meth:`start_connect`
- has not yet been called on this object.
- """
- if (
- self.total is not None
- and self.total is not _DEFAULT_TIMEOUT
- and self._read is not None
- and self._read is not _DEFAULT_TIMEOUT
- ):
- # In case the connect timeout has not yet been established.
- if self._start_connect is None:
- return self._read
- return max(0, min(self.total - self.get_connect_duration(), self._read))
- elif self.total is not None and self.total is not _DEFAULT_TIMEOUT:
- return max(0, self.total - self.get_connect_duration())
- else:
- return self.resolve_default_timeout(self._read)
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/url.py b/.venv/lib/python3.12/site-packages/urllib3/util/url.py
deleted file mode 100644
index d53ea93..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/url.py
+++ /dev/null
@@ -1,471 +0,0 @@
-from __future__ import annotations
-
-import re
-import typing
-
-from ..exceptions import LocationParseError
-from .util import to_str
-
-# We only want to normalize urls with an HTTP(S) scheme.
-# urllib3 infers URLs without a scheme (None) to be http.
-_NORMALIZABLE_SCHEMES = ("http", "https", None)
-
-# Almost all of these patterns were derived from the
-# 'rfc3986' module: https://github.com/python-hyper/rfc3986
-_PERCENT_RE = re.compile(r"%[a-fA-F0-9]{2}")
-_SCHEME_RE = re.compile(r"^(?:[a-zA-Z][a-zA-Z0-9+-]*:|/)")
-_URI_RE = re.compile(
- r"^(?:([a-zA-Z][a-zA-Z0-9+.-]*):)?"
- r"(?://([^\\/?#]*))?"
- r"([^?#]*)"
- r"(?:\?([^#]*))?"
- r"(?:#(.*))?$",
- re.UNICODE | re.DOTALL,
-)
-
-_IPV4_PAT = r"(?:[0-9]{1,3}\.){3}[0-9]{1,3}"
-_HEX_PAT = "[0-9A-Fa-f]{1,4}"
-_LS32_PAT = "(?:{hex}:{hex}|{ipv4})".format(hex=_HEX_PAT, ipv4=_IPV4_PAT)
-_subs = {"hex": _HEX_PAT, "ls32": _LS32_PAT}
-_variations = [
- # 6( h16 ":" ) ls32
- "(?:%(hex)s:){6}%(ls32)s",
- # "::" 5( h16 ":" ) ls32
- "::(?:%(hex)s:){5}%(ls32)s",
- # [ h16 ] "::" 4( h16 ":" ) ls32
- "(?:%(hex)s)?::(?:%(hex)s:){4}%(ls32)s",
- # [ *1( h16 ":" ) h16 ] "::" 3( h16 ":" ) ls32
- "(?:(?:%(hex)s:)?%(hex)s)?::(?:%(hex)s:){3}%(ls32)s",
- # [ *2( h16 ":" ) h16 ] "::" 2( h16 ":" ) ls32
- "(?:(?:%(hex)s:){0,2}%(hex)s)?::(?:%(hex)s:){2}%(ls32)s",
- # [ *3( h16 ":" ) h16 ] "::" h16 ":" ls32
- "(?:(?:%(hex)s:){0,3}%(hex)s)?::%(hex)s:%(ls32)s",
- # [ *4( h16 ":" ) h16 ] "::" ls32
- "(?:(?:%(hex)s:){0,4}%(hex)s)?::%(ls32)s",
- # [ *5( h16 ":" ) h16 ] "::" h16
- "(?:(?:%(hex)s:){0,5}%(hex)s)?::%(hex)s",
- # [ *6( h16 ":" ) h16 ] "::"
- "(?:(?:%(hex)s:){0,6}%(hex)s)?::",
-]
-
-_UNRESERVED_PAT = r"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._\-~"
-_IPV6_PAT = "(?:" + "|".join([x % _subs for x in _variations]) + ")"
-_ZONE_ID_PAT = "(?:%25|%)(?:[" + _UNRESERVED_PAT + "]|%[a-fA-F0-9]{2})+"
-_IPV6_ADDRZ_PAT = r"\[" + _IPV6_PAT + r"(?:" + _ZONE_ID_PAT + r")?\]"
-_REG_NAME_PAT = r"(?:[^\[\]%:/?#]|%[a-fA-F0-9]{2})*"
-_TARGET_RE = re.compile(r"^(/[^?#]*)(?:\?([^#]*))?(?:#.*)?$")
-
-_IPV4_RE = re.compile("^" + _IPV4_PAT + "$")
-_IPV6_RE = re.compile("^" + _IPV6_PAT + "$")
-_IPV6_ADDRZ_RE = re.compile("^" + _IPV6_ADDRZ_PAT + "$")
-_BRACELESS_IPV6_ADDRZ_RE = re.compile("^" + _IPV6_ADDRZ_PAT[2:-2] + "$")
-_ZONE_ID_RE = re.compile("(" + _ZONE_ID_PAT + r")\]$")
-
-_HOST_PORT_PAT = ("^(%s|%s|%s)(?::0*?(|0|[1-9][0-9]{0,4}))?$") % (
- _REG_NAME_PAT,
- _IPV4_PAT,
- _IPV6_ADDRZ_PAT,
-)
-_HOST_PORT_RE = re.compile(_HOST_PORT_PAT, re.UNICODE | re.DOTALL)
-
-_UNRESERVED_CHARS = set(
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789._-~"
-)
-_SUB_DELIM_CHARS = set("!$&'()*+,;=")
-_USERINFO_CHARS = _UNRESERVED_CHARS | _SUB_DELIM_CHARS | {":"}
-_PATH_CHARS = _USERINFO_CHARS | {"@", "/"}
-_QUERY_CHARS = _FRAGMENT_CHARS = _PATH_CHARS | {"?"}
-
-
-class Url(
- typing.NamedTuple(
- "Url",
- [
- ("scheme", typing.Optional[str]),
- ("auth", typing.Optional[str]),
- ("host", typing.Optional[str]),
- ("port", typing.Optional[int]),
- ("path", typing.Optional[str]),
- ("query", typing.Optional[str]),
- ("fragment", typing.Optional[str]),
- ],
- )
-):
- """
- Data structure for representing an HTTP URL. Used as a return value for
- :func:`parse_url`. Both the scheme and host are normalized as they are
- both case-insensitive according to RFC 3986.
- """
-
- def __new__( # type: ignore[no-untyped-def]
- cls,
- scheme: str | None = None,
- auth: str | None = None,
- host: str | None = None,
- port: int | None = None,
- path: str | None = None,
- query: str | None = None,
- fragment: str | None = None,
- ):
- if path and not path.startswith("/"):
- path = "/" + path
- if scheme is not None:
- scheme = scheme.lower()
- return super().__new__(cls, scheme, auth, host, port, path, query, fragment)
-
- @property
- def hostname(self) -> str | None:
- """For backwards-compatibility with urlparse. We're nice like that."""
- return self.host
-
- @property
- def request_uri(self) -> str:
- """Absolute path including the query string."""
- uri = self.path or "/"
-
- if self.query is not None:
- uri += "?" + self.query
-
- return uri
-
- @property
- def authority(self) -> str | None:
- """
- Authority component as defined in RFC 3986 3.2.
- This includes userinfo (auth), host and port.
-
- i.e.
- userinfo@host:port
- """
- userinfo = self.auth
- netloc = self.netloc
- if netloc is None or userinfo is None:
- return netloc
- else:
- return f"{userinfo}@{netloc}"
-
- @property
- def netloc(self) -> str | None:
- """
- Network location including host and port.
-
- If you need the equivalent of urllib.parse's ``netloc``,
- use the ``authority`` property instead.
- """
- if self.host is None:
- return None
- if self.port:
- return f"{self.host}:{self.port}"
- return self.host
-
- @property
- def url(self) -> str:
- """
- Convert self into a url
-
- This function should more or less round-trip with :func:`.parse_url`. The
- returned url may not be exactly the same as the url inputted to
- :func:`.parse_url`, but it should be equivalent by the RFC (e.g., urls
- with a blank port will have : removed).
-
- Example:
-
- .. code-block:: python
-
- import urllib3
-
- U = urllib3.util.parse_url("https://google.com/mail/")
-
- print(U.url)
- # "https://google.com/mail/"
-
- print( urllib3.util.Url("https", "username:password",
- "host.com", 80, "/path", "query", "fragment"
- ).url
- )
- # "https://username:password@host.com:80/path?query#fragment"
- """
- scheme, auth, host, port, path, query, fragment = self
- url = ""
-
- # We use "is not None" we want things to happen with empty strings (or 0 port)
- if scheme is not None:
- url += scheme + "://"
- if auth is not None:
- url += auth + "@"
- if host is not None:
- url += host
- if port is not None:
- url += ":" + str(port)
- if path is not None:
- url += path
- if query is not None:
- url += "?" + query
- if fragment is not None:
- url += "#" + fragment
-
- return url
-
- def __str__(self) -> str:
- return self.url
-
-
-@typing.overload
-def _encode_invalid_chars(
- component: str, allowed_chars: typing.Container[str]
-) -> str: # Abstract
- ...
-
-
-@typing.overload
-def _encode_invalid_chars(
- component: None, allowed_chars: typing.Container[str]
-) -> None: # Abstract
- ...
-
-
-def _encode_invalid_chars(
- component: str | None, allowed_chars: typing.Container[str]
-) -> str | None:
- """Percent-encodes a URI component without reapplying
- onto an already percent-encoded component.
- """
- if component is None:
- return component
-
- component = to_str(component)
-
- # Normalize existing percent-encoded bytes.
- # Try to see if the component we're encoding is already percent-encoded
- # so we can skip all '%' characters but still encode all others.
- component, percent_encodings = _PERCENT_RE.subn(
- lambda match: match.group(0).upper(), component
- )
-
- uri_bytes = component.encode("utf-8", "surrogatepass")
- is_percent_encoded = percent_encodings == uri_bytes.count(b"%")
- encoded_component = bytearray()
-
- for i in range(0, len(uri_bytes)):
- # Will return a single character bytestring
- byte = uri_bytes[i : i + 1]
- byte_ord = ord(byte)
- if (is_percent_encoded and byte == b"%") or (
- byte_ord < 128 and byte.decode() in allowed_chars
- ):
- encoded_component += byte
- continue
- encoded_component.extend(b"%" + (hex(byte_ord)[2:].encode().zfill(2).upper()))
-
- return encoded_component.decode()
-
-
-def _remove_path_dot_segments(path: str) -> str:
- # See http://tools.ietf.org/html/rfc3986#section-5.2.4 for pseudo-code
- segments = path.split("/") # Turn the path into a list of segments
- output = [] # Initialize the variable to use to store output
-
- for segment in segments:
- # '.' is the current directory, so ignore it, it is superfluous
- if segment == ".":
- continue
- # Anything other than '..', should be appended to the output
- if segment != "..":
- output.append(segment)
- # In this case segment == '..', if we can, we should pop the last
- # element
- elif output:
- output.pop()
-
- # If the path starts with '/' and the output is empty or the first string
- # is non-empty
- if path.startswith("/") and (not output or output[0]):
- output.insert(0, "")
-
- # If the path starts with '/.' or '/..' ensure we add one more empty
- # string to add a trailing '/'
- if path.endswith(("/.", "/..")):
- output.append("")
-
- return "/".join(output)
-
-
-@typing.overload
-def _normalize_host(host: None, scheme: str | None) -> None:
- ...
-
-
-@typing.overload
-def _normalize_host(host: str, scheme: str | None) -> str:
- ...
-
-
-def _normalize_host(host: str | None, scheme: str | None) -> str | None:
- if host:
- if scheme in _NORMALIZABLE_SCHEMES:
- is_ipv6 = _IPV6_ADDRZ_RE.match(host)
- if is_ipv6:
- # IPv6 hosts of the form 'a::b%zone' are encoded in a URL as
- # such per RFC 6874: 'a::b%25zone'. Unquote the ZoneID
- # separator as necessary to return a valid RFC 4007 scoped IP.
- match = _ZONE_ID_RE.search(host)
- if match:
- start, end = match.span(1)
- zone_id = host[start:end]
-
- if zone_id.startswith("%25") and zone_id != "%25":
- zone_id = zone_id[3:]
- else:
- zone_id = zone_id[1:]
- zone_id = _encode_invalid_chars(zone_id, _UNRESERVED_CHARS)
- return f"{host[:start].lower()}%{zone_id}{host[end:]}"
- else:
- return host.lower()
- elif not _IPV4_RE.match(host):
- return to_str(
- b".".join([_idna_encode(label) for label in host.split(".")]),
- "ascii",
- )
- return host
-
-
-def _idna_encode(name: str) -> bytes:
- if not name.isascii():
- try:
- import idna
- except ImportError:
- raise LocationParseError(
- "Unable to parse URL without the 'idna' module"
- ) from None
-
- try:
- return idna.encode(name.lower(), strict=True, std3_rules=True)
- except idna.IDNAError:
- raise LocationParseError(
- f"Name '{name}' is not a valid IDNA label"
- ) from None
-
- return name.lower().encode("ascii")
-
-
-def _encode_target(target: str) -> str:
- """Percent-encodes a request target so that there are no invalid characters
-
- Pre-condition for this function is that 'target' must start with '/'.
- If that is the case then _TARGET_RE will always produce a match.
- """
- match = _TARGET_RE.match(target)
- if not match: # Defensive:
- raise LocationParseError(f"{target!r} is not a valid request URI")
-
- path, query = match.groups()
- encoded_target = _encode_invalid_chars(path, _PATH_CHARS)
- if query is not None:
- query = _encode_invalid_chars(query, _QUERY_CHARS)
- encoded_target += "?" + query
- return encoded_target
-
-
-def parse_url(url: str) -> Url:
- """
- Given a url, return a parsed :class:`.Url` namedtuple. Best-effort is
- performed to parse incomplete urls. Fields not provided will be None.
- This parser is RFC 3986 and RFC 6874 compliant.
-
- The parser logic and helper functions are based heavily on
- work done in the ``rfc3986`` module.
-
- :param str url: URL to parse into a :class:`.Url` namedtuple.
-
- Partly backwards-compatible with :mod:`urllib.parse`.
-
- Example:
-
- .. code-block:: python
-
- import urllib3
-
- print( urllib3.util.parse_url('http://google.com/mail/'))
- # Url(scheme='http', host='google.com', port=None, path='/mail/', ...)
-
- print( urllib3.util.parse_url('google.com:80'))
- # Url(scheme=None, host='google.com', port=80, path=None, ...)
-
- print( urllib3.util.parse_url('/foo?bar'))
- # Url(scheme=None, host=None, port=None, path='/foo', query='bar', ...)
- """
- if not url:
- # Empty
- return Url()
-
- source_url = url
- if not _SCHEME_RE.search(url):
- url = "//" + url
-
- scheme: str | None
- authority: str | None
- auth: str | None
- host: str | None
- port: str | None
- port_int: int | None
- path: str | None
- query: str | None
- fragment: str | None
-
- try:
- scheme, authority, path, query, fragment = _URI_RE.match(url).groups() # type: ignore[union-attr]
- normalize_uri = scheme is None or scheme.lower() in _NORMALIZABLE_SCHEMES
-
- if scheme:
- scheme = scheme.lower()
-
- if authority:
- auth, _, host_port = authority.rpartition("@")
- auth = auth or None
- host, port = _HOST_PORT_RE.match(host_port).groups() # type: ignore[union-attr]
- if auth and normalize_uri:
- auth = _encode_invalid_chars(auth, _USERINFO_CHARS)
- if port == "":
- port = None
- else:
- auth, host, port = None, None, None
-
- if port is not None:
- port_int = int(port)
- if not (0 <= port_int <= 65535):
- raise LocationParseError(url)
- else:
- port_int = None
-
- host = _normalize_host(host, scheme)
-
- if normalize_uri and path:
- path = _remove_path_dot_segments(path)
- path = _encode_invalid_chars(path, _PATH_CHARS)
- if normalize_uri and query:
- query = _encode_invalid_chars(query, _QUERY_CHARS)
- if normalize_uri and fragment:
- fragment = _encode_invalid_chars(fragment, _FRAGMENT_CHARS)
-
- except (ValueError, AttributeError) as e:
- raise LocationParseError(source_url) from e
-
- # For the sake of backwards compatibility we put empty
- # string values for path if there are any defined values
- # beyond the path in the URL.
- # TODO: Remove this when we break backwards compatibility.
- if not path:
- if query is not None or fragment is not None:
- path = ""
- else:
- path = None
-
- return Url(
- scheme=scheme,
- auth=auth,
- host=host,
- port=port_int,
- path=path,
- query=query,
- fragment=fragment,
- )
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/util.py b/.venv/lib/python3.12/site-packages/urllib3/util/util.py
deleted file mode 100644
index 35c77e4..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/util.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from __future__ import annotations
-
-import typing
-from types import TracebackType
-
-
-def to_bytes(
- x: str | bytes, encoding: str | None = None, errors: str | None = None
-) -> bytes:
- if isinstance(x, bytes):
- return x
- elif not isinstance(x, str):
- raise TypeError(f"not expecting type {type(x).__name__}")
- if encoding or errors:
- return x.encode(encoding or "utf-8", errors=errors or "strict")
- return x.encode()
-
-
-def to_str(
- x: str | bytes, encoding: str | None = None, errors: str | None = None
-) -> str:
- if isinstance(x, str):
- return x
- elif not isinstance(x, bytes):
- raise TypeError(f"not expecting type {type(x).__name__}")
- if encoding or errors:
- return x.decode(encoding or "utf-8", errors=errors or "strict")
- return x.decode()
-
-
-def reraise(
- tp: type[BaseException] | None,
- value: BaseException,
- tb: TracebackType | None = None,
-) -> typing.NoReturn:
- try:
- if value.__traceback__ is not tb:
- raise value.with_traceback(tb)
- raise value
- finally:
- value = None # type: ignore[assignment]
- tb = None
diff --git a/.venv/lib/python3.12/site-packages/urllib3/util/wait.py b/.venv/lib/python3.12/site-packages/urllib3/util/wait.py
deleted file mode 100644
index aeca0c7..0000000
--- a/.venv/lib/python3.12/site-packages/urllib3/util/wait.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from __future__ import annotations
-
-import select
-import socket
-from functools import partial
-
-__all__ = ["wait_for_read", "wait_for_write"]
-
-
-# How should we wait on sockets?
-#
-# There are two types of APIs you can use for waiting on sockets: the fancy
-# modern stateful APIs like epoll/kqueue, and the older stateless APIs like
-# select/poll. The stateful APIs are more efficient when you have a lots of
-# sockets to keep track of, because you can set them up once and then use them
-# lots of times. But we only ever want to wait on a single socket at a time
-# and don't want to keep track of state, so the stateless APIs are actually
-# more efficient. So we want to use select() or poll().
-#
-# Now, how do we choose between select() and poll()? On traditional Unixes,
-# select() has a strange calling convention that makes it slow, or fail
-# altogether, for high-numbered file descriptors. The point of poll() is to fix
-# that, so on Unixes, we prefer poll().
-#
-# On Windows, there is no poll() (or at least Python doesn't provide a wrapper
-# for it), but that's OK, because on Windows, select() doesn't have this
-# strange calling convention; plain select() works fine.
-#
-# So: on Windows we use select(), and everywhere else we use poll(). We also
-# fall back to select() in case poll() is somehow broken or missing.
-
-
-def select_wait_for_socket(
- sock: socket.socket,
- read: bool = False,
- write: bool = False,
- timeout: float | None = None,
-) -> bool:
- if not read and not write:
- raise RuntimeError("must specify at least one of read=True, write=True")
- rcheck = []
- wcheck = []
- if read:
- rcheck.append(sock)
- if write:
- wcheck.append(sock)
- # When doing a non-blocking connect, most systems signal success by
- # marking the socket writable. Windows, though, signals success by marked
- # it as "exceptional". We paper over the difference by checking the write
- # sockets for both conditions. (The stdlib selectors module does the same
- # thing.)
- fn = partial(select.select, rcheck, wcheck, wcheck)
- rready, wready, xready = fn(timeout)
- return bool(rready or wready or xready)
-
-
-def poll_wait_for_socket(
- sock: socket.socket,
- read: bool = False,
- write: bool = False,
- timeout: float | None = None,
-) -> bool:
- if not read and not write:
- raise RuntimeError("must specify at least one of read=True, write=True")
- mask = 0
- if read:
- mask |= select.POLLIN
- if write:
- mask |= select.POLLOUT
- poll_obj = select.poll()
- poll_obj.register(sock, mask)
-
- # For some reason, poll() takes timeout in milliseconds
- def do_poll(t: float | None) -> list[tuple[int, int]]:
- if t is not None:
- t *= 1000
- return poll_obj.poll(t)
-
- return bool(do_poll(timeout))
-
-
-def _have_working_poll() -> bool:
- # Apparently some systems have a select.poll that fails as soon as you try
- # to use it, either due to strange configuration or broken monkeypatching
- # from libraries like eventlet/greenlet.
- try:
- poll_obj = select.poll()
- poll_obj.poll(0)
- except (AttributeError, OSError):
- return False
- else:
- return True
-
-
-def wait_for_socket(
- sock: socket.socket,
- read: bool = False,
- write: bool = False,
- timeout: float | None = None,
-) -> bool:
- # We delay choosing which implementation to use until the first time we're
- # called. We could do it at import time, but then we might make the wrong
- # decision if someone goes wild with monkeypatching select.poll after
- # we're imported.
- global wait_for_socket
- if _have_working_poll():
- wait_for_socket = poll_wait_for_socket
- elif hasattr(select, "select"):
- wait_for_socket = select_wait_for_socket
- return wait_for_socket(sock, read, write, timeout)
-
-
-def wait_for_read(sock: socket.socket, timeout: float | None = None) -> bool:
- """Waits for reading to be available on a given socket.
- Returns True if the socket is readable, or False if the timeout expired.
- """
- return wait_for_socket(sock, read=True, timeout=timeout)
-
-
-def wait_for_write(sock: socket.socket, timeout: float | None = None) -> bool:
- """Waits for writing to be available on a given socket.
- Returns True if the socket is readable, or False if the timeout expired.
- """
- return wait_for_socket(sock, write=True, timeout=timeout)
diff --git a/.venv/pyvenv.cfg b/.venv/pyvenv.cfg
index 3e51560..d9adafd 100644
--- a/.venv/pyvenv.cfg
+++ b/.venv/pyvenv.cfg
@@ -1,5 +1,5 @@
-home = /bin
+home = /usr/bin
include-system-site-packages = false
version = 3.12.3
executable = /usr/bin/python3.12
-command = /bin/python -m venv /home/rpetrovich/code/Misc/.venv
+command = /usr/bin/python -m venv /home/rpetrovich/code/miscellaneous/.venv
diff --git a/.vscode/settings.json b/.vscode/settings.json
new file mode 100644
index 0000000..70ae8fa
--- /dev/null
+++ b/.vscode/settings.json
@@ -0,0 +1,3 @@
+{
+ "github-enterprise.uri": "https://github.lmru.tech/"
+}
\ No newline at end of file
diff --git a/blocked_ips.txt b/blocked_ips.txt
new file mode 100644
index 0000000..29acab9
--- /dev/null
+++ b/blocked_ips.txt
@@ -0,0 +1,280 @@
+104.110.240.106 repository.jboss.org
+104.110.240.130 repository.jboss.org
+104.16.0.35 registry.yarnpkg.com
+104.16.0.35 registry.npmjs.org
+104.16.1.35 registry.yarnpkg.com
+104.16.1.35 registry.npmjs.org
+104.16.168.120 dl.yarnpkg.com
+104.16.169.120 dl.yarnpkg.com
+104.16.2.35 registry.npmjs.org
+104.16.2.35 registry.yarnpkg.com
+104.16.24.34 registry.yarnpkg.com
+104.16.24.34 registry.npmjs.org
+104.16.25.34 registry.npmjs.org
+104.16.25.34 registry.yarnpkg.com
+104.16.26.34 registry.npmjs.org
+104.16.26.34 registry.yarnpkg.com
+104.16.27.34 registry.yarnpkg.com
+104.16.27.34 registry.npmjs.org
+104.16.28.34 registry.yarnpkg.com
+104.16.28.34 registry.npmjs.org
+104.16.29.34 registry.npmjs.org
+104.16.29.34 registry.yarnpkg.com
+104.16.3.35 registry.yarnpkg.com
+104.16.3.35 registry.npmjs.org
+104.16.30.34 registry.yarnpkg.com
+104.16.30.34 registry.npmjs.org
+104.16.31.34 registry.yarnpkg.com
+104.16.31.34 registry.npmjs.org
+104.16.72.101 services.gradle.org
+104.16.72.101 plugins.gradle.org
+104.16.73.101 services.gradle.org
+104.16.73.101 plugins.gradle.org
+104.21.13.85 node-precompiled-binaries.grpc.io
+104.21.80.4 cdn.sheetjs.com
+107.21.12.206 quay.io
+107.22.21.208 oss.sonatype.org
+108.138.26.102 hdd48109.live.dynatrace.com
+108.138.26.102 wtk16575.live.dynatrace.com
+108.138.26.109 hdd48109.live.dynatrace.com
+108.138.26.109 wtk16575.live.dynatrace.com
+108.138.26.11 hdd48109.live.dynatrace.com
+108.138.26.11 wtk16575.live.dynatrace.com
+108.138.26.123 hdd48109.live.dynatrace.com
+108.138.26.123 wtk16575.live.dynatrace.com
+108.156.22.103 binaries.sonarsource.com
+108.156.22.35 binaries.sonarsource.com
+108.156.22.43 binaries.sonarsource.com
+108.156.22.52 binaries.sonarsource.com
+108.157.229.17 helm.releases.hashicorp.com
+108.157.229.3 helm.releases.hashicorp.com
+108.157.229.36 helm.releases.hashicorp.com
+108.157.229.86 helm.releases.hashicorp.com
+116.203.44.5 registry-gitlab.smarthead.ru
+13.107.246.44 www.powershellgallery.com
+13.107.246.67 www.powershellgallery.com
+13.107.246.67 packages.microsoft.com
+13.107.253.72 repo.adobe.com
+13.33.187.52 releases.hashicorp.com
+13.33.187.85 releases.hashicorp.com
+13.33.187.87 releases.hashicorp.com
+13.33.187.98 releases.hashicorp.com
+13.90.137.153 dist.apache.org
+140.82.121.3 github.com
+140.82.121.33 ghcr.io
+142.250.150.82 gcr.io
+146.59.69.202 packages.sury.org
+146.75.120.209 repo1.maven.org
+146.75.54.132 deb.debian.org
+147.75.85.69 apt.postgresql.org
+150.171.69.10 mcr.microsoft.com
+150.171.70.10 mcr.microsoft.com
+151.101.1.227 rubygems.org
+151.101.129.227 rubygems.org
+151.101.130.132 security.debian.org
+151.101.193.227 rubygems.org
+151.101.194.132 security.debian.org
+151.101.2.132 dlcdn.apache.org
+151.101.2.132 security.debian.org
+151.101.65.227 rubygems.org
+151.101.66.132 security.debian.org
+151.101.84.223 files.pythonhosted.org
+151.101.84.223 pypi.python.org
+157.90.160.34 dl.qameta.io
+158.160.130.222 art.platformeco.cloud
+172.67.132.164 node-precompiled-binaries.grpc.io
+172.67.172.85 cdn.sheetjs.com
+173.194.221.82 eu.gcr.io
+173.194.221.82 k8s.gcr.io
+178.128.6.101 repo.zabbix.com
+18.165.140.100 hdd48109.live.dynatrace.com
+18.165.140.100 wtk16575.live.dynatrace.com
+18.165.140.122 hdd48109.live.dynatrace.com
+18.165.140.122 wtk16575.live.dynatrace.com
+18.165.140.2 hdd48109.live.dynatrace.com
+18.165.140.2 wtk16575.live.dynatrace.com
+18.165.140.61 hdd48109.live.dynatrace.com
+18.165.140.61 wtk16575.live.dynatrace.com
+18.172.112.106 fastdl.mongodb.org
+18.172.112.108 fastdl.mongodb.org
+18.172.112.122 fastdl.mongodb.org
+18.172.112.53 fastdl.mongodb.org
+18.193.107.15 app.camunda.com
+18.198.112.44 plus-pkgs.nginx.com
+18.198.212.80 plus-pkgs.nginx.com
+18.214.194.113 jcenter.bintray.com
+18.214.194.113 dl.bintray.com
+18.232.172.199 jcenter.bintray.com
+18.232.172.199 dl.bintray.com
+185.12.28.11 hub.verme.ru
+185.125.190.81 archive.ubuntu.com
+185.125.190.81 security.ubuntu.com
+185.125.190.82 archive.ubuntu.com
+185.125.190.82 security.ubuntu.com
+185.125.190.83 archive.ubuntu.com
+185.125.190.83 security.ubuntu.com
+185.199.108.133 raw.githubusercontent.com
+185.199.108.153 helm.tricksterproxy.io
+185.199.108.153 provectus.github.io
+185.199.108.153 victoriametrics.github.io
+185.199.108.153 ansible-community.github.io
+185.199.108.153 grafana.github.io
+185.199.108.153 prometheus-community.github.io
+185.199.108.153 open-telemetry.github.io
+185.199.109.133 raw.githubusercontent.com
+185.199.109.153 provectus.github.io
+185.199.109.153 victoriametrics.github.io
+185.199.109.153 helm.tricksterproxy.io
+185.199.109.153 ansible-community.github.io
+185.199.109.153 grafana.github.io
+185.199.109.153 prometheus-community.github.io
+185.199.109.153 open-telemetry.github.io
+185.199.110.133 raw.githubusercontent.com
+185.199.110.153 prometheus-community.github.io
+185.199.110.153 helm.tricksterproxy.io
+185.199.110.153 provectus.github.io
+185.199.110.153 victoriametrics.github.io
+185.199.110.153 ansible-community.github.io
+185.199.110.153 open-telemetry.github.io
+185.199.110.153 grafana.github.io
+185.199.111.133 raw.githubusercontent.com
+185.199.111.153 helm.tricksterproxy.io
+185.199.111.153 provectus.github.io
+185.199.111.153 victoriametrics.github.io
+185.199.111.153 ansible-community.github.io
+185.199.111.153 open-telemetry.github.io
+185.199.111.153 grafana.github.io
+185.199.111.153 prometheus-community.github.io
+188.114.96.1 node-precompiled-binaries.grpc.io
+188.114.97.1 node-precompiled-binaries.grpc.io
+188.114.98.229 jitpack.io
+188.114.98.229 charts.jetstack.io
+188.114.98.229 api.cypress.io
+188.114.98.233 api.cypress.io
+188.114.99.229 jitpack.io
+188.114.99.229 charts.jetstack.io
+188.114.99.229 api.cypress.io
+188.114.99.233 api.cypress.io
+199.232.192.209 repo1.maven.org
+199.232.196.209 repo1.maven.org
+2.19.204.49 developer.huawei.com
+2.19.204.85 developer.huawei.com
+213.180.204.183 mirror.yandex.ru
+216.239.32.21 go.dev
+216.239.34.21 go.dev
+216.239.36.21 go.dev
+216.239.38.21 go.dev
+216.58.210.142 maven.google.com
+217.196.149.55 apt.postgresql.org
+3.123.220.237 adeo-docker.jfrog.io
+3.123.220.237 adeo-docker-adeo-habitation-social-platform-community-release.jfrog.io
+3.123.220.237 adeo-docker-public.jfrog.io
+3.123.220.237 adeo.jfrog.io
+3.123.220.237 adeo-docker-adeo-supplier-portal-dev.jfrog.io
+3.123.220.237 artifacts.camunda.com
+3.164.206.102 download.docker.com
+3.164.206.39 download.docker.com
+3.164.206.5 download.docker.com
+3.164.206.93 download.docker.com
+3.164.230.119 packages.confluent.io
+3.164.230.21 packages.confluent.io
+3.164.230.3 packages.confluent.io
+3.164.230.95 packages.confluent.io
+3.164.68.105 fastdl.mongodb.org
+3.164.68.120 fastdl.mongodb.org
+3.164.68.120 packages.atlassian.com
+3.164.68.125 packages.atlassian.com
+3.164.68.13 charts.bitnami.com
+3.164.68.18 charts.bitnami.com
+3.164.68.34 fastdl.mongodb.org
+3.164.68.49 fastdl.mongodb.org
+3.164.68.51 charts.bitnami.com
+3.164.68.55 packages.atlassian.com
+3.164.68.60 packages.atlassian.com
+3.164.68.70 charts.bitnami.com
+3.219.239.5 registry-1.docker.io
+3.221.179.99 releases.jfrog.io
+3.221.179.99 docker.bintray.io
+3.224.227.198 docker.io
+3.64.156.118 adeo.jfrog.io
+3.64.156.118 adeo-docker.jfrog.io
+3.64.156.118 adeo-docker-adeo-habitation-social-platform-community-release.jfrog.io
+3.64.156.118 adeo-docker-public.jfrog.io
+3.64.156.118 adeo-docker-adeo-supplier-portal-dev.jfrog.io
+3.64.156.118 artifacts.camunda.com
+3.95.117.170 dl.bintray.com
+3.95.117.170 jcenter.bintray.com
+34.120.127.130 helm.elastic.co
+34.120.127.130 artifacts.elastic.co
+34.120.251.192 maven.fabric.io
+34.194.247.182 quay.io
+34.204.25.116 quay.io
+34.225.228.28 repo.spring.io
+34.225.228.28 repo.jenkins-ci.org
+34.225.228.28 jaspersoft.jfrog.io
+34.226.69.105 registry-1.docker.io
+34.234.119.86 registry.aquasec.com
+34.236.131.237 quay.io
+34.68.230.202 docker.elastic.co
+34.96.108.209 registry.k8s.io
+44.193.181.103 docker.io
+44.199.98.27 registry.aquasec.com
+44.209.124.32 jaspersoft.jfrog.io
+44.209.124.32 repo.spring.io
+44.209.124.32 repo.jenkins-ci.org
+44.217.227.31 oss.sonatype.org
+44.219.3.189 docker.io
+46.148.230.218 registry.deckhouse.io
+46.148.230.218 tuf.trdl.dev
+46.148.230.218 tuf.werf.io
+5.182.227.150 registry.flant.com
+50.17.28.229 releases.jfrog.io
+50.17.28.229 docker.bintray.io
+51.250.108.143 reg.qatools.ru
+51.250.42.133 nexus.uxfeedback.ru
+52.22.177.50 jaspersoft.jfrog.io
+52.22.177.50 repo.jenkins-ci.org
+52.22.177.50 repo.spring.io
+52.240.159.111 www.nuget.org
+52.52.69.196 packagecloud.io
+52.59.103.36 adeo-docker.jfrog.io
+52.59.103.36 adeo-docker-adeo-habitation-social-platform-community-release.jfrog.io
+52.59.103.36 adeo-docker-public.jfrog.io
+52.59.103.36 adeo.jfrog.io
+52.59.103.36 adeo-docker-adeo-supplier-portal-dev.jfrog.io
+52.59.103.36 artifacts.camunda.com
+52.85.49.108 packages.confluent.io
+52.85.49.128 packages.confluent.io
+52.85.49.20 packages.confluent.io
+52.85.49.85 packages.confluent.io
+52.86.230.159 registry.aquasec.com
+54.183.9.100 airbyte.mycloudrepo.io
+54.196.99.49 registry-1.docker.io
+54.205.219.235 quay.io
+54.219.142.32 airbyte.mycloudrepo.io
+54.219.193.67 packagecloud.io
+54.221.82.220 releases.jfrog.io
+54.221.82.220 docker.bintray.io
+54.85.190.97 quay.io
+62.84.127.94 hub.elma365.tech
+64.233.164.141 proxy.golang.org
+64.233.165.82 eu.gcr.io
+65.109.119.155 repository.apache.org
+72.32.157.246 apt.postgresql.org
+77.223.118.150 registry.sbdagroup.com
+77.223.120.232 registry.deckhouse.io
+77.223.120.232 tuf.trdl.dev
+77.223.120.232 tuf.werf.io
+82.202.247.250 gitlab-registry-leroy.agora.ru
+84.201.144.250 registry.infra.platformeco.tech
+84.201.171.239 cr.yandex
+84.201.185.129 hashicorp-releases.yandexcloud.net
+87.238.57.227 apt.postgresql.org
+91.134.164.156 maven.jahia.org
+91.189.91.81 security.ubuntu.com
+91.189.91.81 archive.ubuntu.com
+91.189.91.82 security.ubuntu.com
+91.189.91.82 archive.ubuntu.com
+95.213.31.200 artifactory-external.vkpartner.ru
+96.16.54.184 repository.jboss.org
+96.16.54.200 repository.jboss.org
diff --git a/ng_labels_with_aqua.py b/ng_labels_with_aqua.py
new file mode 100644
index 0000000..e6d3390
--- /dev/null
+++ b/ng_labels_with_aqua.py
@@ -0,0 +1,186 @@
+from ruamel.yaml import YAML, comments
+from ruamel.yaml.scalarstring import DoubleQuotedScalarString as dq
+import os
+
+
+base_dir = "/home/rpetrovich/code/Repos/lmru--devops--argocd-apps/"
+
+yaml = YAML()
+yaml.preserve_quotes = True
+yaml.explicit_start = True
+yaml.indent(mapping=2, sequence=4, offset=2)
+yaml.allow_duplicate_keys = True
+
+def load_yaml(file_path):
+ with open(file_path, 'r') as file:
+ data = list(yaml.load_all(file))
+ return data
+
+def save_yaml(data, file_path):
+ with open(file_path, 'w') as file:
+ yaml.dump_all(data, file)
+
+def extract_cluster_info(node_path):
+ parts = node_path.split('/')
+ nodes_index = parts.index('nodes')
+ env = parts[nodes_index - 2]
+ cluster_index = parts.index('clusters') + 1
+ cluster_name = parts[cluster_index]
+ subpath = '-'.join(parts[cluster_index + 2:nodes_index - 1]) if nodes_index - cluster_index > 2 else ''
+ return cluster_name, env, subpath
+
+def add_label_if_needed(node_group):
+ excluded_labels = [
+ "d8-", "opendistro", "opensearch", "otel-", "system",
+ "mimir-", "prometheus", "frontend", "elastic", "master",
+ "loadbalancer", "deckhouse", "router", "moon-", "sentry",
+ "odfe-", "obs-grafana", "devops-core-argocd", "victoria-",
+ "clickhouse", "redis", "rabbit", "loki","cassandra", "jaeger", "vm-",
+ "memcached", "kafka"
+ ]
+
+ name = node_group['metadata']['name']
+ print(f"Processing NodeGroup: {name}")
+
+ if any(excluded in name for excluded in excluded_labels):
+ print(f"Excluded by name: {name}")
+ return False # Пропускаем обработку, если имя в списке исключений
+
+ node_template = node_group['spec'].setdefault('nodeTemplate', comments.CommentedMap())
+ labels = node_template.setdefault('labels', comments.CommentedMap())
+ filtered_labels = {k: v for k, v in labels.items() if not k.startswith("threshold.")}
+
+ if any(excluded in label for label in filtered_labels for excluded in excluded_labels):
+ print(f"Excluded by existing labels: {filtered_labels}")
+ return False # Пропускаем обработку, если метки в списке исключений
+
+ new_label_key = 'node-role.k8s.lmru.tech/application'
+
+ # Добавляем логику: проверяем метку, но продолжаем проверку тейнтов
+ label_already_present = new_label_key in labels
+ if label_already_present:
+ print(f"Label already present for {name}, but checking taints...")
+ else:
+ labels[new_label_key] = ""
+ print(f"Label added for {name}: {new_label_key}")
+
+ # Возвращаем True для продолжения обработки, даже если метка уже есть
+ return True
+
+def find_cluster_file(base_dir, cluster_name, env):
+ target_directory = f"{base_dir}/common/aqua-kube-enforcer/{env}/values/"
+
+ if not os.path.exists(target_directory):
+ print(f"Directory does not exist: {target_directory}")
+ return None
+
+ for file in os.listdir(target_directory):
+ if cluster_name in file and env in file and file.endswith('cluster.yaml') and '-elk-' not in file:
+ return os.path.join(target_directory, file)
+
+ print(f"No matching cluster file found that contains both '{cluster_name}' and '{env}' in {target_directory}")
+ return None
+
+def process_yaml_file(node_file):
+ if '/elk/' in node_file:
+ print(f"Skipping: {node_file} due to '/elk/'")
+ return
+
+ cluster_name, env, _ = extract_cluster_info(node_file)
+ data = load_yaml(node_file)
+
+ if not data:
+ print(f"No data found in {node_file}")
+ return
+
+ changed = False
+ tolerations = []
+
+ for doc in data:
+ if doc is None:
+ print(f"Skipping invalid or empty YAML document in {node_file}")
+ continue
+
+ # Проверяем метки и продолжаем даже если метка уже есть
+ if doc.get('kind') == "NodeGroup" and add_label_if_needed(doc):
+ changed = True
+ taints = doc.get('spec', {}).get('nodeTemplate', {}).get('taints', [])
+ if taints:
+ print(f"Taints found in NodeGroup {doc['metadata']['name']}: {taints}")
+ for taint in taints:
+ if 'key' in taint and 'value' in taint:
+ tolerations.append({
+ "key": taint['key'],
+ "operator": "Equal",
+ "effect": dq(taint.get('effect', '')),
+ "value": taint['value']
+ })
+ print(f"Adding toleration for {doc['metadata']['name']}: {taint}")
+
+ if changed:
+ save_yaml(data, node_file)
+ print(f"Changes saved to {node_file}")
+
+ if tolerations:
+ cluster_file = find_cluster_file(base_dir, cluster_name, env)
+ if cluster_file:
+ print(f"Found cluster file for {cluster_name} in {env}: {cluster_file}")
+ update_cluster_file(cluster_file, tolerations)
+ else:
+ print(f"No cluster file found for {cluster_name} in {env}")
+ else:
+ print(f"No tolerations found to add for {node_file}")
+
+
+def update_cluster_file(cluster_file, new_tolerations):
+ if not cluster_file:
+ print("No matching cluster file found.")
+ return
+
+ print(f"Attempting to update cluster file: {cluster_file} with tolerations: {new_tolerations}")
+
+ try:
+ data = load_yaml(cluster_file)
+ updated = False # Флаг для отслеживания изменений
+
+ for doc in data:
+ # Убедимся, что раздел enforcer присутствует
+ enforcer = doc.setdefault('enforcer', comments.CommentedMap())
+
+ # Добавляем nodeSelector, если отсутствует
+ enforcer.setdefault('nodeSelector', {})['node-role.k8s.lmru.tech/application'] = ''
+
+ # Проверяем и добавляем новые tolerations
+ existing_tolerations = enforcer.setdefault('tolerations', [])
+ for new_tol in new_tolerations:
+ # Проверяем, если такая же toleration уже присутствует
+ if not any(
+ tol['key'] == new_tol['key'] and
+ tol['operator'] == new_tol['operator'] and
+ tol['effect'] == new_tol['effect'] and
+ tol['value'] == new_tol['value']
+ for tol in existing_tolerations
+ ):
+ existing_tolerations.append(new_tol)
+ updated = True # Устанавливаем флаг, что произошли изменения
+
+ if updated:
+ save_yaml(data, cluster_file)
+ print(f"Updated cluster file successfully: {cluster_file}")
+ else:
+ print(f"No updates were needed for {cluster_file}")
+
+ except Exception as e:
+ print(f"Failed to update cluster file {cluster_file}: {e}")
+
+def process_directory(directory):
+ for root, _, files in os.walk(directory, topdown=True):
+ if "stage" not in root: # comment if you don't want to restrict "stage" only
+ continue
+ for file in files:
+ if file == 'node_groups.yaml':
+ full_path = os.path.join(root, file)
+ print(f"Processing: {full_path}")
+ process_yaml_file(full_path)
+
+process_directory(base_dir)
diff --git a/salt/init.sls b/salt/init.sls
index 7aec692..eff98dd 100644
--- a/salt/init.sls
+++ b/salt/init.sls
@@ -1,44 +1,20 @@
-{% for ip in [
- "54.67.28.63",
- "13.56.23.197",
- "213.180.204.183",
- "151.101.130.132",
- "151.101.194.132",
- "151.101.2.132",
- "151.101.246.132",
- "151.101.66.132",
- "147.75.85.69",
- "217.196.149.55",
- "72.32.157.246",
- "87.238.57.227",
- "104.16.168.120",
- "104.16.169.120",
- "52.85.49.108",
- "52.85.49.128",
- "52.85.49.20",
- "52.85.49.85",
- "18.198.112.44",
- "18.198.212.80",
- "146.59.69.202"
-] %}
-remove_ip_{{ ip.replace('.', '_') }}_output:
+remove_ip_64.233.162.82_output:
iptables.delete:
- table: filter
- chain: OUTPUT
- - destination: {{ ip }}
+ - destination: 64.233.162.82
- jump: REJECT
-remove_ip_{{ ip.replace('.', '_') }}_forward:
+remove_ip_64.233.162.82_forward:
iptables.delete:
- table: filter
- chain: FORWARD
- - destination: {{ ip }}
+ - destination: 64.233.162.82
- jump: REJECT
-remove_ip_{{ ip.replace('.', '_') }}_docker_user:
+remove_ip_64.233.162.82_docker_user:
iptables.delete:
- table: filter
- chain: DOCKER-USER
- - destination: {{ ip }}
+ - destination: 64.233.162.82
- jump: REJECT
-{% endfor %}
\ No newline at end of file