)63hyZEzvD_
zCc`tI-Q;m%5^0%cMdakKz5vEN5{mCWDWyLU)&!o;ajthh8|%Vj&ocIzz92#!pB_x2
zL;B>*(qdzgb(dU^;DtVBUb;NIOrW(-qSa6Fb5U!Vudjy5EB-dLq4?IYjPS#nM?Tod
z57ai#CWp;VT!h*_c>|s{sZrsgX|3+~cOs!lt%6T$Jnsab;w-s{1-ikzB0d@EbFDtR
z2#|Aoq00$enF34(UeDlZ?6dC*)&zP2eTl6{_-efw2|xetk&r$)(czPFBi5t@p6^zf
z_-+#u>u+nU_x=2ykXu*dQ8L@{LwpU2KQVDAJxok3f{$#C`M484^Lsx&pJA<8N;D(e
z$vCgj0_CJ{P8(2U-8I%&R^YVOkUMGAj}v`jeYMgb<<}t(ya7)VYEpbntSyj@gxUi5
zY6n|q={3xHy>nhVbrLLye8o49Odw(*BXL}U8SHhraM&{z>vuR|t&Mj47`MFQM=T7o
zr8#jLONZp4$UJm`hx2AVhj&S+6@G_0i&j_08#m8x{ksRl~+EDyzSVsD>#(wN-
z$F#ZoWP^XNn8cSbr;yE
zm^lW&7eZfZw=M4p#O$?PV`+)i8TT9LS9*#DB?SJqD~!KK#}B6YD
zPmCUgZ}xBNd|vWz?FzVyxcOqa8h^os@8+j?NO`2=fAEVSI>z7eY}`(ZobrWdH7mt8
lT>ttH0n_z=y8dr+KS7zFG__V&<|R$(l=G1yH#cWp{tw5sSYH4D
literal 0
HcmV?d00001
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/LICENSE.rst b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/LICENSE.rst
new file mode 100644
index 0000000..191ddaf
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/LICENSE.rst
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Laurent LAPORTE
+
+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/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/METADATA
new file mode 100644
index 0000000..9ecede2
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/METADATA
@@ -0,0 +1,181 @@
+Metadata-Version: 2.1
+Name: Deprecated
+Version: 1.2.14
+Summary: Python @deprecated decorator to deprecate old python classes, functions or methods.
+Home-page: https://github.com/tantale/deprecated
+Author: Laurent LAPORTE
+Author-email: tantale.solutions@gmail.com
+License: MIT
+Project-URL: Documentation, https://deprecated.readthedocs.io/en/latest/
+Project-URL: Source, https://github.com/tantale/deprecated
+Project-URL: Bug Tracker, https://github.com/tantale/deprecated/issues
+Keywords: deprecate,deprecated,deprecation,warning,warn,decorator
+Platform: any
+Classifier: Development Status :: 5 - Production/Stable
+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 :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+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: Topic :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*
+Description-Content-Type: text/x-rst
+License-File: LICENSE.rst
+Requires-Dist: wrapt (<2,>=1.10)
+Provides-Extra: dev
+Requires-Dist: tox ; extra == 'dev'
+Requires-Dist: PyTest ; extra == 'dev'
+Requires-Dist: PyTest-Cov ; extra == 'dev'
+Requires-Dist: bump2version (<1) ; extra == 'dev'
+Requires-Dist: sphinx (<2) ; extra == 'dev'
+
+
+Deprecated Library
+------------------
+
+Deprecated is Easy to Use
+`````````````````````````
+
+If you need to mark a function or a method as deprecated,
+you can use the ``@deprecated`` decorator:
+
+Save in a hello.py:
+
+.. code:: python
+
+ from deprecated import deprecated
+
+
+ @deprecated(version='1.2.1', reason="You should use another function")
+ def some_old_function(x, y):
+ return x + y
+
+
+ class SomeClass(object):
+ @deprecated(version='1.3.0', reason="This method is deprecated")
+ def some_old_method(self, x, y):
+ return x + y
+
+
+ some_old_function(12, 34)
+ obj = SomeClass()
+ obj.some_old_method(5, 8)
+
+
+And Easy to Setup
+`````````````````
+
+And run it:
+
+.. code:: bash
+
+ $ pip install Deprecated
+ $ python hello.py
+ hello.py:15: DeprecationWarning: Call to deprecated function (or staticmethod) some_old_function.
+ (You should use another function) -- Deprecated since version 1.2.0.
+ some_old_function(12, 34)
+ hello.py:17: DeprecationWarning: Call to deprecated method some_old_method.
+ (This method is deprecated) -- Deprecated since version 1.3.0.
+ obj.some_old_method(5, 8)
+
+
+You can document your code
+``````````````````````````
+
+Have you ever wonder how to document that some functions, classes, methods, etc. are deprecated?
+This is now possible with the integrated Sphinx directives:
+
+For instance, in hello_sphinx.py:
+
+.. code:: python
+
+ from deprecated.sphinx import deprecated
+ from deprecated.sphinx import versionadded
+ from deprecated.sphinx import versionchanged
+
+
+ @versionadded(version='1.0', reason="This function is new")
+ def function_one():
+ '''This is the function one'''
+
+
+ @versionchanged(version='1.0', reason="This function is modified")
+ def function_two():
+ '''This is the function two'''
+
+
+ @deprecated(version='1.0', reason="This function will be removed soon")
+ def function_three():
+ '''This is the function three'''
+
+
+ function_one()
+ function_two()
+ function_three() # warns
+
+ help(function_one)
+ help(function_two)
+ help(function_three)
+
+
+The result it immediate
+```````````````````````
+
+Run it:
+
+.. code:: bash
+
+ $ python hello_sphinx.py
+
+ hello_sphinx.py:23: DeprecationWarning: Call to deprecated function (or staticmethod) function_three.
+ (This function will be removed soon) -- Deprecated since version 1.0.
+ function_three() # warns
+
+ Help on function function_one in module __main__:
+
+ function_one()
+ This is the function one
+
+ .. versionadded:: 1.0
+ This function is new
+
+ Help on function function_two in module __main__:
+
+ function_two()
+ This is the function two
+
+ .. versionchanged:: 1.0
+ This function is modified
+
+ Help on function function_three in module __main__:
+
+ function_three()
+ This is the function three
+
+ .. deprecated:: 1.0
+ This function will be removed soon
+
+
+Links
+`````
+
+* `Python package index (PyPi) `_
+* `GitHub website `_
+* `Read The Docs `_
+* `EBook on Lulu.com `_
+* `StackOverFlow Q&A `_
+* `Development version
+ `_
+
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/RECORD
new file mode 100644
index 0000000..d8f67cb
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/RECORD
@@ -0,0 +1,13 @@
+Deprecated-1.2.14.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+Deprecated-1.2.14.dist-info/LICENSE.rst,sha256=HoPt0VvkGbXVveNy4yXlJ_9PmRX1SOfHUxS0H2aZ6Dw,1081
+Deprecated-1.2.14.dist-info/METADATA,sha256=xQYvk5nwOfnkxxRD-VHkpE-sMu0IBHRZ8ayspypfkTs,5354
+Deprecated-1.2.14.dist-info/RECORD,,
+Deprecated-1.2.14.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+Deprecated-1.2.14.dist-info/WHEEL,sha256=a-zpFRIJzOq5QfuhBzbhiA1eHTzNCJn8OdRvhdNX0Rk,110
+Deprecated-1.2.14.dist-info/top_level.txt,sha256=nHbOYawKPQQE5lQl-toUB1JBRJjUyn_m_Mb8RVJ0RjA,11
+deprecated/__init__.py,sha256=ZphiULqDVrESSB0mLV2WA88JyhQxZSK44zuDGbV5k-g,349
+deprecated/__pycache__/__init__.cpython-311.pyc,,
+deprecated/__pycache__/classic.cpython-311.pyc,,
+deprecated/__pycache__/sphinx.cpython-311.pyc,,
+deprecated/classic.py,sha256=QugmUi7IhBvp2nDvMtyWqFDPRR43-9nfSZG1ZJSDpFM,9880
+deprecated/sphinx.py,sha256=NqQ0oKGcVn6yUe23iGbCieCgvWbEDQSPt9QelbXJnDU,10258
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/WHEEL
new file mode 100644
index 0000000..f771c29
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.40.0)
+Root-Is-Purelib: true
+Tag: py2-none-any
+Tag: py3-none-any
+
diff --git a/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/top_level.txt b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/top_level.txt
new file mode 100644
index 0000000..9f8d550
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/Deprecated-1.2.14.dist-info/top_level.txt
@@ -0,0 +1 @@
+deprecated
diff --git a/lambdas/aws-dd-forwarder-3.127.0/META_INF/aws_signer_signature_v1.0.SF b/lambdas/aws-dd-forwarder-3.127.0/META_INF/aws_signer_signature_v1.0.SF
new file mode 100644
index 0000000..b55229a
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/META_INF/aws_signer_signature_v1.0.SF
@@ -0,0 +1,70 @@
+-----BEGIN PKCS7-----
+MIAGCSqGSIb3DQEHAqCAMIACAQExDTALBglghkgBZQMEAgIwCwYJKoZIhvcNAQcB
+oIAwggJ7MIICAqADAgECAhEAgseesYiwj2v65uNdIxGWjDAKBggqhkjOPQQDAzBp
+MQswCQYDVQQGEwJVUzEMMAoGA1UECgwDQVdTMRUwEwYDVQQLDAxDcnlwdG9ncmFw
+aHkxCzAJBgNVBAgMAldBMSgwJgYDVQQDDB9TaWduZXIgdXMtZWFzdC0xIFNVQk9S
+RElOQVRFIENBMB4XDTI0MTAxMTAzNTUwNloXDTI0MTAxNDA0NTUwNVowYjELMAkG
+A1UEBhMCVVMxCzAJBgNVBAgMAldBMRAwDgYDVQQHDAdTZWF0dGxlMQwwCgYDVQQK
+DANBV1MxFTATBgNVBAsMDENyeXB0b2dyYXBoeTEPMA0GA1UEAwwGc2lnbmVyMHYw
+EAYHKoZIzj0CAQYFK4EEACIDYgAENEJBApwU+6Uew83wGVUmaoQVqhH8OWJ8uhNK
+pYeGe2aO+ltRW56QVdcbTV5bndUcW9nslQ946H5Zn1Un/j/WPxkBJjUfNZvKvwDL
+kD2kbr6fpJnpTrylWuJC/JyRXP3Uo3UwczAJBgNVHRMEAjAAMB8GA1UdIwQYMBaA
+FBW0Hd/bDRgmoXefjl93qtSKwJXVMB0GA1UdDgQWBBRcF773L+DbVZJg2nkGpbHH
+SGoCJDAOBgNVHQ8BAf8EBAMCB4AwFgYDVR0lAQH/BAwwCgYIKwYBBQUHAwMwCgYI
+KoZIzj0EAwMDZwAwZAIwEVaZHYn31KWcjTkpUDxyYtN2OZdFmDx05ZwyOjz74MbS
+ZI1gWjpUz8fG5ZeZ2rzfAjAiJzHe0f6PnC29XXlT+XbaLCgX+93ma2BO0ssYugs6
+FMXwBljceZQwC+X4Dpp58agwggJzMIIB+qADAgECAhEAzX5q6bZNJ1qnMgY/JSNY
+BDAKBggqhkjOPQQDAzBpMQswCQYDVQQGEwJVUzEMMAoGA1UECgwDQVdTMRUwEwYD
+VQQLDAxDcnlwdG9ncmFwaHkxCzAJBgNVBAgMAldBMSgwJgYDVQQDDB9TaWduZXIg
+dXMtd2VzdC0yIFNVQk9SRElOQVRFIENBMB4XDTI0MDgwMTE0MjIxNloXDTI1MDUw
+MTE1MjIxNlowaTELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0FXUzEVMBMGA1UECwwM
+Q3J5cHRvZ3JhcGh5MQswCQYDVQQIDAJXQTEoMCYGA1UEAwwfU2lnbmVyIHVzLWVh
+c3QtMSBTVUJPUkRJTkFURSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABB6NdKgv
+U6rWCAUVIeCLunsKQNOQeSGS0+Vu1NMa3pyx8kJTdhkB/Alc2BiC9q8Vg7JS8I9y
+sLS73z4eTu915XFBRPNEszWLLcjuxyms5V1261wOnVompfb6sWohfQDQ9aNmMGQw
+EgYDVR0TAQH/BAgwBgEB/wIBADAfBgNVHSMEGDAWgBQiEqKJBM6ppy9zVIGE+K0F
+Mi1HazAdBgNVHQ4EFgQUFbQd39sNGCahd5+OX3eq1IrAldUwDgYDVR0PAQH/BAQD
+AgGGMAoGCCqGSM49BAMDA2cAMGQCMBXdKjpiudEhq7Fb/vVcb9DVuelVi2O8SENH
+kwH5aBiMe1S1VYTkP8eRtaiM6Qzh8wIwEz/oPBUFEDawCkVpg7i726Db75ZdISZ+
+IzTrUnDdv0xinWVl7/2oKs7UQx1birspMIICbTCCAfOgAwIBAgIRANBJlLz1Fa3M
+o9YlS8oV3AUwCgYIKoZIzj0EAwMwYjELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0FX
+UzEVMBMGA1UECwwMQ3J5cHRvZ3JhcGh5MQswCQYDVQQIDAJXQTEhMB8GA1UEAwwY
+U2lnbmVyIHVzLXdlc3QtMiBST09UIENBMB4XDTIxMDcxMjE5NTAzN1oXDTI2MDcx
+MjIwNTAzN1owaTELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0FXUzEVMBMGA1UECwwM
+Q3J5cHRvZ3JhcGh5MQswCQYDVQQIDAJXQTEoMCYGA1UEAwwfU2lnbmVyIHVzLXdl
+c3QtMiBTVUJPUkRJTkFURSBDQTB2MBAGByqGSM49AgEGBSuBBAAiA2IABNzE7TkM
+6mrYlE9trVdemsxNbCWXUwjM1x8mOqtZ04mL6xLPnubDeGX0C+Zx4QjH3/kspxcZ
+hAyvV2wvs8SA/HMVv1gMVwrmqtMgsNzBF7DjROPZ2aVRaNdb4DZYpVKTk6NmMGQw
+EgYDVR0TAQH/BAgwBgEB/wIBATAfBgNVHSMEGDAWgBR57Gmd9LD9Ijf7LzNGP0Gx
+CPahXzAdBgNVHQ4EFgQUIhKiiQTOqacvc1SBhPitBTItR2swDgYDVR0PAQH/BAQD
+AgGGMAoGCCqGSM49BAMDA2gAMGUCMDK5gsIf52Gh5TFT2WQDWwgLfoHlaUqGq2yv
+/TPFvJQ6PeU52DxsFkUjBK9y3D/CdwIxANHVSZ9E625jNBrq7211RBbA9FG39N8z
+dDyrvpQPuCid4fruMkuAPOLnoWOk5YpV+DCCAkQwggHKoAMCAQICEQCwD+lKFGkZ
+G4M9/Aaa0RubMAoGCCqGSM49BAMDMGIxCzAJBgNVBAYTAlVTMQwwCgYDVQQKDANB
+V1MxFTATBgNVBAsMDENyeXB0b2dyYXBoeTELMAkGA1UECAwCV0ExITAfBgNVBAMM
+GFNpZ25lciB1cy13ZXN0LTIgUk9PVCBDQTAgFw0yMDA3MTYxODIxNDdaGA8yMTIw
+MDcxNjE5MjE0N1owYjELMAkGA1UEBhMCVVMxDDAKBgNVBAoMA0FXUzEVMBMGA1UE
+CwwMQ3J5cHRvZ3JhcGh5MQswCQYDVQQIDAJXQTEhMB8GA1UEAwwYU2lnbmVyIHVz
+LXdlc3QtMiBST09UIENBMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEZVHVljB0VcdR
+HM0iy/fmrq8iLSA4W1myRPlG7EDEXD5jwZ05J3oWceNJ9RQjHhSRBUEWu1UEhGJ8
+GSQcE0CoT2qp5qKFjBrPyRD9L3K9w/ZIumQvYsuv30zlJDPyo4Xuo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBR57Gmd9LD9Ijf7LzNGP0GxCPahXzAOBgNV
+HQ8BAf8EBAMCAYYwCgYIKoZIzj0EAwMDaAAwZQIxAOZ2pyA0jXTej7akG1tz3/PQ
+dubi6A+9ZhzMx4kIWvdd/AflwCy33hvVPDoWbVG8vAIwHrwSAF/cyvDpmSnbJmll
+5gHk0spcT17Y5BEEkXSENlsajdDLje9JjGgvaUdVLqMcAAAxggKrMIICpwIBATB+
+MGkxCzAJBgNVBAYTAlVTMQwwCgYDVQQKDANBV1MxFTATBgNVBAsMDENyeXB0b2dy
+YXBoeTELMAkGA1UECAwCV0ExKDAmBgNVBAMMH1NpZ25lciB1cy1lYXN0LTEgU1VC
+T1JESU5BVEUgQ0ECEQCCx56xiLCPa/rm410jEZaMMAsGCWCGSAFlAwQCAqCCAZ8w
+GAYJKoZIhvcNAQkDMQsGCSqGSIb3DQEHATAgBgcrgTuBCQEDMRUYEzIwMzYwMTEx
+MTU1MDUzLjcwMVowIgYJKoZIhvcNAQkFMRUYEzIwMjQxMDExMTU1MDUzLjcwMVow
+KAYJKoZIhvcNAQk0MRswGTALBglghkgBZQMEAgKhCgYIKoZIzj0EAwMwPwYJKoZI
+hvcNAQkEMTIEMLjbYXVmR5oZlI5YUD9xABhD9seqVJ1fKmT3UkDiWBZK3RlBus8+
+xB7MlG/8YxEn/DBlBgcrgTuBCQECMVoMWGFybjphd3M6c2lnbmVyOnVzLWVhc3Qt
+MTo0NjQ2MjI1MzIwMTI6L3NpZ25pbmctam9icy9jODlkOTE4NC1mY2FhLTRjYzUt
+ODFmMC0zMjQyZjdmYjllMTUwawYHK4E7gQkBBDFgDF5hcm46YXdzOnNpZ25lcjp1
+cy1lYXN0LTE6NDY0NjIyNTMyMDEyOi9zaWduaW5nLXByb2ZpbGVzL0RhdGFkb2dM
+YW1iZGFTaWduaW5nUHJvZmlsZS85dk1JOVpBR0xjMAoGCCqGSM49BAMDBGYwZAIw
+M+knoFUHpSY1U+qmX1EUQCenrg4n+wc1fK5pv8K+LddOf9KHqrY28GkutH3sLF31
+AjBX0SUoW/3rEedtYJ/N9uGDlNn69Iw2ooboeBNjK9xb4QMTHsCPBR8PBFve33rq
+ADYAAAAAAAA=
+-----END PKCS7-----
diff --git a/lambdas/aws-dd-forwarder-3.127.0/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/__init__.py
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.py
new file mode 100644
index 0000000..51b1c25
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.py
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: MIT
+
+"""
+Classes Without Boilerplate
+"""
+
+from functools import partial
+from typing import Callable
+
+from . import converters, exceptions, filters, setters, validators
+from ._cmp import cmp_using
+from ._compat import Protocol
+from ._config import get_run_validators, set_run_validators
+from ._funcs import asdict, assoc, astuple, evolve, has, resolve_types
+from ._make import (
+ NOTHING,
+ Attribute,
+ Converter,
+ Factory,
+ attrib,
+ attrs,
+ fields,
+ fields_dict,
+ make_class,
+ validate,
+)
+from ._next_gen import define, field, frozen, mutable
+from ._version_info import VersionInfo
+
+
+s = attributes = attrs
+ib = attr = attrib
+dataclass = partial(attrs, auto_attribs=True) # happy Easter ;)
+
+
+class AttrsInstance(Protocol):
+ pass
+
+
+__all__ = [
+ "Attribute",
+ "AttrsInstance",
+ "Converter",
+ "Factory",
+ "NOTHING",
+ "asdict",
+ "assoc",
+ "astuple",
+ "attr",
+ "attrib",
+ "attributes",
+ "attrs",
+ "cmp_using",
+ "converters",
+ "define",
+ "evolve",
+ "exceptions",
+ "field",
+ "fields",
+ "fields_dict",
+ "filters",
+ "frozen",
+ "get_run_validators",
+ "has",
+ "ib",
+ "make_class",
+ "mutable",
+ "resolve_types",
+ "s",
+ "set_run_validators",
+ "setters",
+ "validate",
+ "validators",
+]
+
+
+def _make_getattr(mod_name: str) -> Callable:
+ """
+ Create a metadata proxy for packaging information that uses *mod_name* in
+ its warnings and errors.
+ """
+
+ def __getattr__(name: str) -> str:
+ if name not in ("__version__", "__version_info__"):
+ msg = f"module {mod_name} has no attribute {name}"
+ raise AttributeError(msg)
+
+ try:
+ from importlib.metadata import metadata
+ except ImportError:
+ from importlib_metadata import metadata
+
+ meta = metadata("attrs")
+
+ if name == "__version_info__":
+ return VersionInfo._from_version_string(meta["version"])
+
+ return meta["version"]
+
+ return __getattr__
+
+
+__getattr__ = _make_getattr(__name__)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.pyi
new file mode 100644
index 0000000..6ae0a83
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/__init__.pyi
@@ -0,0 +1,388 @@
+import enum
+import sys
+
+from typing import (
+ Any,
+ Callable,
+ Generic,
+ Mapping,
+ Protocol,
+ Sequence,
+ TypeVar,
+ overload,
+)
+
+# `import X as X` is required to make these public
+from . import converters as converters
+from . import exceptions as exceptions
+from . import filters as filters
+from . import setters as setters
+from . import validators as validators
+from ._cmp import cmp_using as cmp_using
+from ._typing_compat import AttrsInstance_
+from ._version_info import VersionInfo
+from attrs import (
+ define as define,
+ field as field,
+ mutable as mutable,
+ frozen as frozen,
+ _EqOrderType,
+ _ValidatorType,
+ _ConverterType,
+ _ReprArgType,
+ _OnSetAttrType,
+ _OnSetAttrArgType,
+ _FieldTransformer,
+ _ValidatorArgType,
+)
+
+if sys.version_info >= (3, 10):
+ from typing import TypeGuard
+else:
+ from typing_extensions import TypeGuard
+
+if sys.version_info >= (3, 11):
+ from typing import dataclass_transform
+else:
+ from typing_extensions import dataclass_transform
+
+__version__: str
+__version_info__: VersionInfo
+__title__: str
+__description__: str
+__url__: str
+__uri__: str
+__author__: str
+__email__: str
+__license__: str
+__copyright__: str
+
+_T = TypeVar("_T")
+_C = TypeVar("_C", bound=type)
+
+_FilterType = Callable[["Attribute[_T]", _T], bool]
+
+# We subclass this here to keep the protocol's qualified name clean.
+class AttrsInstance(AttrsInstance_, Protocol):
+ pass
+
+_A = TypeVar("_A", bound=type[AttrsInstance])
+
+class _Nothing(enum.Enum):
+ NOTHING = enum.auto()
+
+NOTHING = _Nothing.NOTHING
+
+# NOTE: Factory lies about its return type to make this possible:
+# `x: List[int] # = Factory(list)`
+# Work around mypy issue #4554 in the common case by using an overload.
+if sys.version_info >= (3, 8):
+ from typing import Literal
+ @overload
+ def Factory(factory: Callable[[], _T]) -> _T: ...
+ @overload
+ def Factory(
+ factory: Callable[[Any], _T],
+ takes_self: Literal[True],
+ ) -> _T: ...
+ @overload
+ def Factory(
+ factory: Callable[[], _T],
+ takes_self: Literal[False],
+ ) -> _T: ...
+
+else:
+ @overload
+ def Factory(factory: Callable[[], _T]) -> _T: ...
+ @overload
+ def Factory(
+ factory: Union[Callable[[Any], _T], Callable[[], _T]],
+ takes_self: bool = ...,
+ ) -> _T: ...
+
+In = TypeVar("In")
+Out = TypeVar("Out")
+
+class Converter(Generic[In, Out]):
+ @overload
+ def __init__(self, converter: Callable[[In], Out]) -> None: ...
+ @overload
+ def __init__(
+ self,
+ converter: Callable[[In, AttrsInstance, Attribute], Out],
+ *,
+ takes_self: Literal[True],
+ takes_field: Literal[True],
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ converter: Callable[[In, Attribute], Out],
+ *,
+ takes_field: Literal[True],
+ ) -> None: ...
+ @overload
+ def __init__(
+ self,
+ converter: Callable[[In, AttrsInstance], Out],
+ *,
+ takes_self: Literal[True],
+ ) -> None: ...
+
+class Attribute(Generic[_T]):
+ name: str
+ default: _T | None
+ validator: _ValidatorType[_T] | None
+ repr: _ReprArgType
+ cmp: _EqOrderType
+ eq: _EqOrderType
+ order: _EqOrderType
+ hash: bool | None
+ init: bool
+ converter: _ConverterType | Converter[Any, _T] | None
+ metadata: dict[Any, Any]
+ type: type[_T] | None
+ kw_only: bool
+ on_setattr: _OnSetAttrType
+ alias: str | None
+
+ def evolve(self, **changes: Any) -> "Attribute[Any]": ...
+
+# NOTE: We had several choices for the annotation to use for type arg:
+# 1) Type[_T]
+# - Pros: Handles simple cases correctly
+# - Cons: Might produce less informative errors in the case of conflicting
+# TypeVars e.g. `attr.ib(default='bad', type=int)`
+# 2) Callable[..., _T]
+# - Pros: Better error messages than #1 for conflicting TypeVars
+# - Cons: Terrible error messages for validator checks.
+# e.g. attr.ib(type=int, validator=validate_str)
+# -> error: Cannot infer function type argument
+# 3) type (and do all of the work in the mypy plugin)
+# - Pros: Simple here, and we could customize the plugin with our own errors.
+# - Cons: Would need to write mypy plugin code to handle all the cases.
+# We chose option #1.
+
+# `attr` lies about its return type to make the following possible:
+# attr() -> Any
+# attr(8) -> int
+# attr(validator=) -> Whatever the callable expects.
+# This makes this type of assignments possible:
+# x: int = attr(8)
+#
+# This form catches explicit None or no default but with no other arguments
+# returns Any.
+@overload
+def attrib(
+ default: None = ...,
+ validator: None = ...,
+ repr: _ReprArgType = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ type: None = ...,
+ converter: None = ...,
+ factory: None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+) -> Any: ...
+
+# This form catches an explicit None or no default and infers the type from the
+# other arguments.
+@overload
+def attrib(
+ default: None = ...,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ type: type[_T] | None = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+) -> _T: ...
+
+# This form catches an explicit default argument.
+@overload
+def attrib(
+ default: _T,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ type: type[_T] | None = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+) -> _T: ...
+
+# This form covers type=non-Type: e.g. forward references (str), Any
+@overload
+def attrib(
+ default: _T | None = ...,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ type: object = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+) -> Any: ...
+@overload
+@dataclass_transform(order_default=True, field_specifiers=(attrib, field))
+def attrs(
+ maybe_cls: _C,
+ these: dict[str, Any] | None = ...,
+ repr_ns: str | None = ...,
+ repr: bool = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ auto_detect: bool = ...,
+ collect_by_mro: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+ unsafe_hash: bool | None = ...,
+) -> _C: ...
+@overload
+@dataclass_transform(order_default=True, field_specifiers=(attrib, field))
+def attrs(
+ maybe_cls: None = ...,
+ these: dict[str, Any] | None = ...,
+ repr_ns: str | None = ...,
+ repr: bool = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ auto_detect: bool = ...,
+ collect_by_mro: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+ unsafe_hash: bool | None = ...,
+) -> Callable[[_C], _C]: ...
+def fields(cls: type[AttrsInstance]) -> Any: ...
+def fields_dict(cls: type[AttrsInstance]) -> dict[str, Attribute[Any]]: ...
+def validate(inst: AttrsInstance) -> None: ...
+def resolve_types(
+ cls: _A,
+ globalns: dict[str, Any] | None = ...,
+ localns: dict[str, Any] | None = ...,
+ attribs: list[Attribute[Any]] | None = ...,
+ include_extras: bool = ...,
+) -> _A: ...
+
+# TODO: add support for returning a proper attrs class from the mypy plugin
+# we use Any instead of _CountingAttr so that e.g. `make_class('Foo',
+# [attr.ib()])` is valid
+def make_class(
+ name: str,
+ attrs: list[str] | tuple[str, ...] | dict[str, Any],
+ bases: tuple[type, ...] = ...,
+ class_body: dict[str, Any] | None = ...,
+ repr_ns: str | None = ...,
+ repr: bool = ...,
+ cmp: _EqOrderType | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ collect_by_mro: bool = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+) -> type: ...
+
+# _funcs --
+
+# TODO: add support for returning TypedDict from the mypy plugin
+# FIXME: asdict/astuple do not honor their factory args. Waiting on one of
+# these:
+# https://github.com/python/mypy/issues/4236
+# https://github.com/python/typing/issues/253
+# XXX: remember to fix attrs.asdict/astuple too!
+def asdict(
+ inst: AttrsInstance,
+ recurse: bool = ...,
+ filter: _FilterType[Any] | None = ...,
+ dict_factory: type[Mapping[Any, Any]] = ...,
+ retain_collection_types: bool = ...,
+ value_serializer: Callable[[type, Attribute[Any], Any], Any] | None = ...,
+ tuple_keys: bool | None = ...,
+) -> dict[str, Any]: ...
+
+# TODO: add support for returning NamedTuple from the mypy plugin
+def astuple(
+ inst: AttrsInstance,
+ recurse: bool = ...,
+ filter: _FilterType[Any] | None = ...,
+ tuple_factory: type[Sequence[Any]] = ...,
+ retain_collection_types: bool = ...,
+) -> tuple[Any, ...]: ...
+def has(cls: type) -> TypeGuard[type[AttrsInstance]]: ...
+def assoc(inst: _T, **changes: Any) -> _T: ...
+def evolve(inst: _T, **changes: Any) -> _T: ...
+
+# _config --
+
+def set_run_validators(run: bool) -> None: ...
+def get_run_validators() -> bool: ...
+
+# aliases --
+
+s = attributes = attrs
+ib = attr = attrib
+dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.py
new file mode 100644
index 0000000..f367bb3
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.py
@@ -0,0 +1,160 @@
+# SPDX-License-Identifier: MIT
+
+
+import functools
+import types
+
+from ._make import _make_ne
+
+
+_operation_names = {"eq": "==", "lt": "<", "le": "<=", "gt": ">", "ge": ">="}
+
+
+def cmp_using(
+ eq=None,
+ lt=None,
+ le=None,
+ gt=None,
+ ge=None,
+ require_same_type=True,
+ class_name="Comparable",
+):
+ """
+ Create a class that can be passed into `attrs.field`'s ``eq``, ``order``,
+ and ``cmp`` arguments to customize field comparison.
+
+ The resulting class will have a full set of ordering methods if at least
+ one of ``{lt, le, gt, ge}`` and ``eq`` are provided.
+
+ Args:
+ eq (typing.Callable | None):
+ Callable used to evaluate equality of two objects.
+
+ lt (typing.Callable | None):
+ Callable used to evaluate whether one object is less than another
+ object.
+
+ le (typing.Callable | None):
+ Callable used to evaluate whether one object is less than or equal
+ to another object.
+
+ gt (typing.Callable | None):
+ Callable used to evaluate whether one object is greater than
+ another object.
+
+ ge (typing.Callable | None):
+ Callable used to evaluate whether one object is greater than or
+ equal to another object.
+
+ require_same_type (bool):
+ When `True`, equality and ordering methods will return
+ `NotImplemented` if objects are not of the same type.
+
+ class_name (str | None): Name of class. Defaults to "Comparable".
+
+ See `comparison` for more details.
+
+ .. versionadded:: 21.1.0
+ """
+
+ body = {
+ "__slots__": ["value"],
+ "__init__": _make_init(),
+ "_requirements": [],
+ "_is_comparable_to": _is_comparable_to,
+ }
+
+ # Add operations.
+ num_order_functions = 0
+ has_eq_function = False
+
+ if eq is not None:
+ has_eq_function = True
+ body["__eq__"] = _make_operator("eq", eq)
+ body["__ne__"] = _make_ne()
+
+ if lt is not None:
+ num_order_functions += 1
+ body["__lt__"] = _make_operator("lt", lt)
+
+ if le is not None:
+ num_order_functions += 1
+ body["__le__"] = _make_operator("le", le)
+
+ if gt is not None:
+ num_order_functions += 1
+ body["__gt__"] = _make_operator("gt", gt)
+
+ if ge is not None:
+ num_order_functions += 1
+ body["__ge__"] = _make_operator("ge", ge)
+
+ type_ = types.new_class(
+ class_name, (object,), {}, lambda ns: ns.update(body)
+ )
+
+ # Add same type requirement.
+ if require_same_type:
+ type_._requirements.append(_check_same_type)
+
+ # Add total ordering if at least one operation was defined.
+ if 0 < num_order_functions < 4:
+ if not has_eq_function:
+ # functools.total_ordering requires __eq__ to be defined,
+ # so raise early error here to keep a nice stack.
+ msg = "eq must be define is order to complete ordering from lt, le, gt, ge."
+ raise ValueError(msg)
+ type_ = functools.total_ordering(type_)
+
+ return type_
+
+
+def _make_init():
+ """
+ Create __init__ method.
+ """
+
+ def __init__(self, value):
+ """
+ Initialize object with *value*.
+ """
+ self.value = value
+
+ return __init__
+
+
+def _make_operator(name, func):
+ """
+ Create operator method.
+ """
+
+ def method(self, other):
+ if not self._is_comparable_to(other):
+ return NotImplemented
+
+ result = func(self.value, other.value)
+ if result is NotImplemented:
+ return NotImplemented
+
+ return result
+
+ method.__name__ = f"__{name}__"
+ method.__doc__ = (
+ f"Return a {_operation_names[name]} b. Computed by attrs."
+ )
+
+ return method
+
+
+def _is_comparable_to(self, other):
+ """
+ Check whether `other` is comparable to `self`.
+ """
+ return all(func(self, other) for func in self._requirements)
+
+
+def _check_same_type(self, other):
+ """
+ Return True if *self* and *other* are of the same type, False otherwise.
+ """
+ return other.value.__class__ is self.value.__class__
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.pyi
new file mode 100644
index 0000000..cc7893b
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_cmp.pyi
@@ -0,0 +1,13 @@
+from typing import Any, Callable
+
+_CompareWithType = Callable[[Any, Any], bool]
+
+def cmp_using(
+ eq: _CompareWithType | None = ...,
+ lt: _CompareWithType | None = ...,
+ le: _CompareWithType | None = ...,
+ gt: _CompareWithType | None = ...,
+ ge: _CompareWithType | None = ...,
+ require_same_type: bool = ...,
+ class_name: str = ...,
+) -> type: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_compat.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_compat.py
new file mode 100644
index 0000000..104eeb0
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_compat.py
@@ -0,0 +1,103 @@
+# SPDX-License-Identifier: MIT
+
+import inspect
+import platform
+import sys
+import threading
+
+from collections.abc import Mapping, Sequence # noqa: F401
+from typing import _GenericAlias
+
+
+PYPY = platform.python_implementation() == "PyPy"
+PY_3_8_PLUS = sys.version_info[:2] >= (3, 8)
+PY_3_9_PLUS = sys.version_info[:2] >= (3, 9)
+PY_3_10_PLUS = sys.version_info[:2] >= (3, 10)
+PY_3_11_PLUS = sys.version_info[:2] >= (3, 11)
+PY_3_12_PLUS = sys.version_info[:2] >= (3, 12)
+PY_3_13_PLUS = sys.version_info[:2] >= (3, 13)
+PY_3_14_PLUS = sys.version_info[:2] >= (3, 14)
+
+
+if sys.version_info < (3, 8):
+ try:
+ from typing_extensions import Protocol
+ except ImportError: # pragma: no cover
+ Protocol = object
+else:
+ from typing import Protocol # noqa: F401
+
+if PY_3_14_PLUS: # pragma: no cover
+ import annotationlib
+
+ _get_annotations = annotationlib.get_annotations
+
+else:
+
+ def _get_annotations(cls):
+ """
+ Get annotations for *cls*.
+ """
+ return cls.__dict__.get("__annotations__", {})
+
+
+class _AnnotationExtractor:
+ """
+ Extract type annotations from a callable, returning None whenever there
+ is none.
+ """
+
+ __slots__ = ["sig"]
+
+ def __init__(self, callable):
+ try:
+ self.sig = inspect.signature(callable)
+ except (ValueError, TypeError): # inspect failed
+ self.sig = None
+
+ def get_first_param_type(self):
+ """
+ Return the type annotation of the first argument if it's not empty.
+ """
+ if not self.sig:
+ return None
+
+ params = list(self.sig.parameters.values())
+ if params and params[0].annotation is not inspect.Parameter.empty:
+ return params[0].annotation
+
+ return None
+
+ def get_return_type(self):
+ """
+ Return the return type if it's not empty.
+ """
+ if (
+ self.sig
+ and self.sig.return_annotation is not inspect.Signature.empty
+ ):
+ return self.sig.return_annotation
+
+ return None
+
+
+# Thread-local global to track attrs instances which are already being repr'd.
+# This is needed because there is no other (thread-safe) way to pass info
+# about the instances that are already being repr'd through the call stack
+# in order to ensure we don't perform infinite recursion.
+#
+# For instance, if an instance contains a dict which contains that instance,
+# we need to know that we're already repr'ing the outside instance from within
+# the dict's repr() call.
+#
+# This lives here rather than in _make.py so that the functions in _make.py
+# don't have a direct reference to the thread-local in their globals dict.
+# If they have such a reference, it breaks cloudpickle.
+repr_context = threading.local()
+
+
+def get_generic_base(cl):
+ """If this is a generic class (A[str]), return the generic base for it."""
+ if cl.__class__ is _GenericAlias:
+ return cl.__origin__
+ return None
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_config.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_config.py
new file mode 100644
index 0000000..9c245b1
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_config.py
@@ -0,0 +1,31 @@
+# SPDX-License-Identifier: MIT
+
+__all__ = ["set_run_validators", "get_run_validators"]
+
+_run_validators = True
+
+
+def set_run_validators(run):
+ """
+ Set whether or not validators are run. By default, they are run.
+
+ .. deprecated:: 21.3.0 It will not be removed, but it also will not be
+ moved to new ``attrs`` namespace. Use `attrs.validators.set_disabled()`
+ instead.
+ """
+ if not isinstance(run, bool):
+ msg = "'run' must be bool."
+ raise TypeError(msg)
+ global _run_validators
+ _run_validators = run
+
+
+def get_run_validators():
+ """
+ Return whether or not validators are run.
+
+ .. deprecated:: 21.3.0 It will not be removed, but it also will not be
+ moved to new ``attrs`` namespace. Use `attrs.validators.get_disabled()`
+ instead.
+ """
+ return _run_validators
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_funcs.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_funcs.py
new file mode 100644
index 0000000..355cef4
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_funcs.py
@@ -0,0 +1,522 @@
+# SPDX-License-Identifier: MIT
+
+
+import copy
+
+from ._compat import PY_3_9_PLUS, get_generic_base
+from ._make import _OBJ_SETATTR, NOTHING, fields
+from .exceptions import AttrsAttributeNotFoundError
+
+
+def asdict(
+ inst,
+ recurse=True,
+ filter=None,
+ dict_factory=dict,
+ retain_collection_types=False,
+ value_serializer=None,
+):
+ """
+ Return the *attrs* attribute values of *inst* as a dict.
+
+ Optionally recurse into other *attrs*-decorated classes.
+
+ Args:
+ inst: Instance of an *attrs*-decorated class.
+
+ recurse (bool): Recurse into classes that are also *attrs*-decorated.
+
+ filter (~typing.Callable):
+ A callable whose return code determines whether an attribute or
+ element is included (`True`) or dropped (`False`). Is called with
+ the `attrs.Attribute` as the first argument and the value as the
+ second argument.
+
+ dict_factory (~typing.Callable):
+ A callable to produce dictionaries from. For example, to produce
+ ordered dictionaries instead of normal Python dictionaries, pass in
+ ``collections.OrderedDict``.
+
+ retain_collection_types (bool):
+ Do not convert to `list` when encountering an attribute whose type
+ is `tuple` or `set`. Only meaningful if *recurse* is `True`.
+
+ value_serializer (typing.Callable | None):
+ A hook that is called for every attribute or dict key/value. It
+ receives the current instance, field and value and must return the
+ (updated) value. The hook is run *after* the optional *filter* has
+ been applied.
+
+ Returns:
+ Return type of *dict_factory*.
+
+ Raises:
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ .. versionadded:: 16.0.0 *dict_factory*
+ .. versionadded:: 16.1.0 *retain_collection_types*
+ .. versionadded:: 20.3.0 *value_serializer*
+ .. versionadded:: 21.3.0
+ If a dict has a collection for a key, it is serialized as a tuple.
+ """
+ attrs = fields(inst.__class__)
+ rv = dict_factory()
+ for a in attrs:
+ v = getattr(inst, a.name)
+ if filter is not None and not filter(a, v):
+ continue
+
+ if value_serializer is not None:
+ v = value_serializer(inst, a, v)
+
+ if recurse is True:
+ if has(v.__class__):
+ rv[a.name] = asdict(
+ v,
+ recurse=True,
+ filter=filter,
+ dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ )
+ elif isinstance(v, (tuple, list, set, frozenset)):
+ cf = v.__class__ if retain_collection_types is True else list
+ items = [
+ _asdict_anything(
+ i,
+ is_key=False,
+ filter=filter,
+ dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ )
+ for i in v
+ ]
+ try:
+ rv[a.name] = cf(items)
+ except TypeError:
+ if not issubclass(cf, tuple):
+ raise
+ # Workaround for TypeError: cf.__new__() missing 1 required
+ # positional argument (which appears, for a namedturle)
+ rv[a.name] = cf(*items)
+ elif isinstance(v, dict):
+ df = dict_factory
+ rv[a.name] = df(
+ (
+ _asdict_anything(
+ kk,
+ is_key=True,
+ filter=filter,
+ dict_factory=df,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ ),
+ _asdict_anything(
+ vv,
+ is_key=False,
+ filter=filter,
+ dict_factory=df,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ ),
+ )
+ for kk, vv in v.items()
+ )
+ else:
+ rv[a.name] = v
+ else:
+ rv[a.name] = v
+ return rv
+
+
+def _asdict_anything(
+ val,
+ is_key,
+ filter,
+ dict_factory,
+ retain_collection_types,
+ value_serializer,
+):
+ """
+ ``asdict`` only works on attrs instances, this works on anything.
+ """
+ if getattr(val.__class__, "__attrs_attrs__", None) is not None:
+ # Attrs class.
+ rv = asdict(
+ val,
+ recurse=True,
+ filter=filter,
+ dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ )
+ elif isinstance(val, (tuple, list, set, frozenset)):
+ if retain_collection_types is True:
+ cf = val.__class__
+ elif is_key:
+ cf = tuple
+ else:
+ cf = list
+
+ rv = cf(
+ [
+ _asdict_anything(
+ i,
+ is_key=False,
+ filter=filter,
+ dict_factory=dict_factory,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ )
+ for i in val
+ ]
+ )
+ elif isinstance(val, dict):
+ df = dict_factory
+ rv = df(
+ (
+ _asdict_anything(
+ kk,
+ is_key=True,
+ filter=filter,
+ dict_factory=df,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ ),
+ _asdict_anything(
+ vv,
+ is_key=False,
+ filter=filter,
+ dict_factory=df,
+ retain_collection_types=retain_collection_types,
+ value_serializer=value_serializer,
+ ),
+ )
+ for kk, vv in val.items()
+ )
+ else:
+ rv = val
+ if value_serializer is not None:
+ rv = value_serializer(None, None, rv)
+
+ return rv
+
+
+def astuple(
+ inst,
+ recurse=True,
+ filter=None,
+ tuple_factory=tuple,
+ retain_collection_types=False,
+):
+ """
+ Return the *attrs* attribute values of *inst* as a tuple.
+
+ Optionally recurse into other *attrs*-decorated classes.
+
+ Args:
+ inst: Instance of an *attrs*-decorated class.
+
+ recurse (bool):
+ Recurse into classes that are also *attrs*-decorated.
+
+ filter (~typing.Callable):
+ A callable whose return code determines whether an attribute or
+ element is included (`True`) or dropped (`False`). Is called with
+ the `attrs.Attribute` as the first argument and the value as the
+ second argument.
+
+ tuple_factory (~typing.Callable):
+ A callable to produce tuples from. For example, to produce lists
+ instead of tuples.
+
+ retain_collection_types (bool):
+ Do not convert to `list` or `dict` when encountering an attribute
+ which type is `tuple`, `dict` or `set`. Only meaningful if
+ *recurse* is `True`.
+
+ Returns:
+ Return type of *tuple_factory*
+
+ Raises:
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ .. versionadded:: 16.2.0
+ """
+ attrs = fields(inst.__class__)
+ rv = []
+ retain = retain_collection_types # Very long. :/
+ for a in attrs:
+ v = getattr(inst, a.name)
+ if filter is not None and not filter(a, v):
+ continue
+ if recurse is True:
+ if has(v.__class__):
+ rv.append(
+ astuple(
+ v,
+ recurse=True,
+ filter=filter,
+ tuple_factory=tuple_factory,
+ retain_collection_types=retain,
+ )
+ )
+ elif isinstance(v, (tuple, list, set, frozenset)):
+ cf = v.__class__ if retain is True else list
+ items = [
+ (
+ astuple(
+ j,
+ recurse=True,
+ filter=filter,
+ tuple_factory=tuple_factory,
+ retain_collection_types=retain,
+ )
+ if has(j.__class__)
+ else j
+ )
+ for j in v
+ ]
+ try:
+ rv.append(cf(items))
+ except TypeError:
+ if not issubclass(cf, tuple):
+ raise
+ # Workaround for TypeError: cf.__new__() missing 1 required
+ # positional argument (which appears, for a namedturle)
+ rv.append(cf(*items))
+ elif isinstance(v, dict):
+ df = v.__class__ if retain is True else dict
+ rv.append(
+ df(
+ (
+ (
+ astuple(
+ kk,
+ tuple_factory=tuple_factory,
+ retain_collection_types=retain,
+ )
+ if has(kk.__class__)
+ else kk
+ ),
+ (
+ astuple(
+ vv,
+ tuple_factory=tuple_factory,
+ retain_collection_types=retain,
+ )
+ if has(vv.__class__)
+ else vv
+ ),
+ )
+ for kk, vv in v.items()
+ )
+ )
+ else:
+ rv.append(v)
+ else:
+ rv.append(v)
+
+ return rv if tuple_factory is list else tuple_factory(rv)
+
+
+def has(cls):
+ """
+ Check whether *cls* is a class with *attrs* attributes.
+
+ Args:
+ cls (type): Class to introspect.
+
+ Raises:
+ TypeError: If *cls* is not a class.
+
+ Returns:
+ bool:
+ """
+ attrs = getattr(cls, "__attrs_attrs__", None)
+ if attrs is not None:
+ return True
+
+ # No attrs, maybe it's a specialized generic (A[str])?
+ generic_base = get_generic_base(cls)
+ if generic_base is not None:
+ generic_attrs = getattr(generic_base, "__attrs_attrs__", None)
+ if generic_attrs is not None:
+ # Stick it on here for speed next time.
+ cls.__attrs_attrs__ = generic_attrs
+ return generic_attrs is not None
+ return False
+
+
+def assoc(inst, **changes):
+ """
+ Copy *inst* and apply *changes*.
+
+ This is different from `evolve` that applies the changes to the arguments
+ that create the new instance.
+
+ `evolve`'s behavior is preferable, but there are `edge cases`_ where it
+ doesn't work. Therefore `assoc` is deprecated, but will not be removed.
+
+ .. _`edge cases`: https://github.com/python-attrs/attrs/issues/251
+
+ Args:
+ inst: Instance of a class with *attrs* attributes.
+
+ changes: Keyword changes in the new copy.
+
+ Returns:
+ A copy of inst with *changes* incorporated.
+
+ Raises:
+ attrs.exceptions.AttrsAttributeNotFoundError:
+ If *attr_name* couldn't be found on *cls*.
+
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ .. deprecated:: 17.1.0
+ Use `attrs.evolve` instead if you can. This function will not be
+ removed du to the slightly different approach compared to
+ `attrs.evolve`, though.
+ """
+ new = copy.copy(inst)
+ attrs = fields(inst.__class__)
+ for k, v in changes.items():
+ a = getattr(attrs, k, NOTHING)
+ if a is NOTHING:
+ msg = f"{k} is not an attrs attribute on {new.__class__}."
+ raise AttrsAttributeNotFoundError(msg)
+ _OBJ_SETATTR(new, k, v)
+ return new
+
+
+def evolve(*args, **changes):
+ """
+ Create a new instance, based on the first positional argument with
+ *changes* applied.
+
+ Args:
+
+ inst:
+ Instance of a class with *attrs* attributes. *inst* must be passed
+ as a positional argument.
+
+ changes:
+ Keyword changes in the new copy.
+
+ Returns:
+ A copy of inst with *changes* incorporated.
+
+ Raises:
+ TypeError:
+ If *attr_name* couldn't be found in the class ``__init__``.
+
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ .. versionadded:: 17.1.0
+ .. deprecated:: 23.1.0
+ It is now deprecated to pass the instance using the keyword argument
+ *inst*. It will raise a warning until at least April 2024, after which
+ it will become an error. Always pass the instance as a positional
+ argument.
+ .. versionchanged:: 24.1.0
+ *inst* can't be passed as a keyword argument anymore.
+ """
+ try:
+ (inst,) = args
+ except ValueError:
+ msg = (
+ f"evolve() takes 1 positional argument, but {len(args)} were given"
+ )
+ raise TypeError(msg) from None
+
+ cls = inst.__class__
+ attrs = fields(cls)
+ for a in attrs:
+ if not a.init:
+ continue
+ attr_name = a.name # To deal with private attributes.
+ init_name = a.alias
+ if init_name not in changes:
+ changes[init_name] = getattr(inst, attr_name)
+
+ return cls(**changes)
+
+
+def resolve_types(
+ cls, globalns=None, localns=None, attribs=None, include_extras=True
+):
+ """
+ Resolve any strings and forward annotations in type annotations.
+
+ This is only required if you need concrete types in :class:`Attribute`'s
+ *type* field. In other words, you don't need to resolve your types if you
+ only use them for static type checking.
+
+ With no arguments, names will be looked up in the module in which the class
+ was created. If this is not what you want, for example, if the name only
+ exists inside a method, you may pass *globalns* or *localns* to specify
+ other dictionaries in which to look up these names. See the docs of
+ `typing.get_type_hints` for more details.
+
+ Args:
+ cls (type): Class to resolve.
+
+ globalns (dict | None): Dictionary containing global variables.
+
+ localns (dict | None): Dictionary containing local variables.
+
+ attribs (list | None):
+ List of attribs for the given class. This is necessary when calling
+ from inside a ``field_transformer`` since *cls* is not an *attrs*
+ class yet.
+
+ include_extras (bool):
+ Resolve more accurately, if possible. Pass ``include_extras`` to
+ ``typing.get_hints``, if supported by the typing module. On
+ supported Python versions (3.9+), this resolves the types more
+ accurately.
+
+ Raises:
+ TypeError: If *cls* is not a class.
+
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class and you didn't pass any attribs.
+
+ NameError: If types cannot be resolved because of missing variables.
+
+ Returns:
+ *cls* so you can use this function also as a class decorator. Please
+ note that you have to apply it **after** `attrs.define`. That means the
+ decorator has to come in the line **before** `attrs.define`.
+
+ .. versionadded:: 20.1.0
+ .. versionadded:: 21.1.0 *attribs*
+ .. versionadded:: 23.1.0 *include_extras*
+ """
+ # Since calling get_type_hints is expensive we cache whether we've
+ # done it already.
+ if getattr(cls, "__attrs_types_resolved__", None) != cls:
+ import typing
+
+ kwargs = {"globalns": globalns, "localns": localns}
+
+ if PY_3_9_PLUS:
+ kwargs["include_extras"] = include_extras
+
+ hints = typing.get_type_hints(cls, **kwargs)
+ for field in fields(cls) if attribs is None else attribs:
+ if field.name in hints:
+ # Since fields have been frozen we must work around it.
+ _OBJ_SETATTR(field, "type", hints[field.name])
+ # We store the class we resolved so that subclasses know they haven't
+ # been resolved.
+ cls.__attrs_types_resolved__ = cls
+
+ # Return the class so you can use it as a decorator too.
+ return cls
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_make.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_make.py
new file mode 100644
index 0000000..bf00c5f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_make.py
@@ -0,0 +1,2960 @@
+# SPDX-License-Identifier: MIT
+
+from __future__ import annotations
+
+import abc
+import contextlib
+import copy
+import enum
+import functools
+import inspect
+import itertools
+import linecache
+import sys
+import types
+import typing
+
+from operator import itemgetter
+
+# We need to import _compat itself in addition to the _compat members to avoid
+# having the thread-local in the globals here.
+from . import _compat, _config, setters
+from ._compat import (
+ PY_3_8_PLUS,
+ PY_3_10_PLUS,
+ PY_3_11_PLUS,
+ _AnnotationExtractor,
+ _get_annotations,
+ get_generic_base,
+)
+from .exceptions import (
+ DefaultAlreadySetError,
+ FrozenInstanceError,
+ NotAnAttrsClassError,
+ UnannotatedAttributeError,
+)
+
+
+# This is used at least twice, so cache it here.
+_OBJ_SETATTR = object.__setattr__
+_INIT_FACTORY_PAT = "__attr_factory_%s"
+_CLASSVAR_PREFIXES = (
+ "typing.ClassVar",
+ "t.ClassVar",
+ "ClassVar",
+ "typing_extensions.ClassVar",
+)
+# we don't use a double-underscore prefix because that triggers
+# name mangling when trying to create a slot for the field
+# (when slots=True)
+_HASH_CACHE_FIELD = "_attrs_cached_hash"
+
+_EMPTY_METADATA_SINGLETON = types.MappingProxyType({})
+
+# Unique object for unequivocal getattr() defaults.
+_SENTINEL = object()
+
+_DEFAULT_ON_SETATTR = setters.pipe(setters.convert, setters.validate)
+
+
+class _Nothing(enum.Enum):
+ """
+ Sentinel to indicate the lack of a value when `None` is ambiguous.
+
+ If extending attrs, you can use ``typing.Literal[NOTHING]`` to show
+ that a value may be ``NOTHING``.
+
+ .. versionchanged:: 21.1.0 ``bool(NOTHING)`` is now False.
+ .. versionchanged:: 22.2.0 ``NOTHING`` is now an ``enum.Enum`` variant.
+ """
+
+ NOTHING = enum.auto()
+
+ def __repr__(self):
+ return "NOTHING"
+
+ def __bool__(self):
+ return False
+
+
+NOTHING = _Nothing.NOTHING
+"""
+Sentinel to indicate the lack of a value when `None` is ambiguous.
+"""
+
+
+class _CacheHashWrapper(int):
+ """
+ An integer subclass that pickles / copies as None
+
+ This is used for non-slots classes with ``cache_hash=True``, to avoid
+ serializing a potentially (even likely) invalid hash value. Since `None`
+ is the default value for uncalculated hashes, whenever this is copied,
+ the copy's value for the hash should automatically reset.
+
+ See GH #613 for more details.
+ """
+
+ def __reduce__(self, _none_constructor=type(None), _args=()): # noqa: B008
+ return _none_constructor, _args
+
+
+def attrib(
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ hash=None,
+ init=True,
+ metadata=None,
+ type=None,
+ converter=None,
+ factory=None,
+ kw_only=False,
+ eq=None,
+ order=None,
+ on_setattr=None,
+ alias=None,
+):
+ """
+ Create a new field / attribute on a class.
+
+ Identical to `attrs.field`, except it's not keyword-only.
+
+ Consider using `attrs.field` in new code (``attr.ib`` will *never* go away,
+ though).
+
+ .. warning::
+
+ Does **nothing** unless the class is also decorated with
+ `attr.s` (or similar)!
+
+
+ .. versionadded:: 15.2.0 *convert*
+ .. versionadded:: 16.3.0 *metadata*
+ .. versionchanged:: 17.1.0 *validator* can be a ``list`` now.
+ .. versionchanged:: 17.1.0
+ *hash* is `None` and therefore mirrors *eq* by default.
+ .. versionadded:: 17.3.0 *type*
+ .. deprecated:: 17.4.0 *convert*
+ .. versionadded:: 17.4.0
+ *converter* as a replacement for the deprecated *convert* to achieve
+ consistency with other noun-based arguments.
+ .. versionadded:: 18.1.0
+ ``factory=f`` is syntactic sugar for ``default=attr.Factory(f)``.
+ .. versionadded:: 18.2.0 *kw_only*
+ .. versionchanged:: 19.2.0 *convert* keyword argument removed.
+ .. versionchanged:: 19.2.0 *repr* also accepts a custom callable.
+ .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
+ .. versionadded:: 19.2.0 *eq* and *order*
+ .. versionadded:: 20.1.0 *on_setattr*
+ .. versionchanged:: 20.3.0 *kw_only* backported to Python 2
+ .. versionchanged:: 21.1.0
+ *eq*, *order*, and *cmp* also accept a custom callable
+ .. versionchanged:: 21.1.0 *cmp* undeprecated
+ .. versionadded:: 22.2.0 *alias*
+ """
+ eq, eq_key, order, order_key = _determine_attrib_eq_order(
+ cmp, eq, order, True
+ )
+
+ if hash is not None and hash is not True and hash is not False:
+ msg = "Invalid value for hash. Must be True, False, or None."
+ raise TypeError(msg)
+
+ if factory is not None:
+ if default is not NOTHING:
+ msg = (
+ "The `default` and `factory` arguments are mutually exclusive."
+ )
+ raise ValueError(msg)
+ if not callable(factory):
+ msg = "The `factory` argument must be a callable."
+ raise ValueError(msg)
+ default = Factory(factory)
+
+ if metadata is None:
+ metadata = {}
+
+ # Apply syntactic sugar by auto-wrapping.
+ if isinstance(on_setattr, (list, tuple)):
+ on_setattr = setters.pipe(*on_setattr)
+
+ if validator and isinstance(validator, (list, tuple)):
+ validator = and_(*validator)
+
+ if converter and isinstance(converter, (list, tuple)):
+ converter = pipe(*converter)
+
+ return _CountingAttr(
+ default=default,
+ validator=validator,
+ repr=repr,
+ cmp=None,
+ hash=hash,
+ init=init,
+ converter=converter,
+ metadata=metadata,
+ type=type,
+ kw_only=kw_only,
+ eq=eq,
+ eq_key=eq_key,
+ order=order,
+ order_key=order_key,
+ on_setattr=on_setattr,
+ alias=alias,
+ )
+
+
+def _compile_and_eval(script, globs, locs=None, filename=""):
+ """
+ Evaluate the script with the given global (globs) and local (locs)
+ variables.
+ """
+ bytecode = compile(script, filename, "exec")
+ eval(bytecode, globs, locs)
+
+
+def _make_method(name, script, filename, globs, locals=None):
+ """
+ Create the method with the script given and return the method object.
+ """
+ locs = {} if locals is None else locals
+
+ # In order of debuggers like PDB being able to step through the code,
+ # we add a fake linecache entry.
+ count = 1
+ base_filename = filename
+ while True:
+ linecache_tuple = (
+ len(script),
+ None,
+ script.splitlines(True),
+ filename,
+ )
+ old_val = linecache.cache.setdefault(filename, linecache_tuple)
+ if old_val == linecache_tuple:
+ break
+
+ filename = f"{base_filename[:-1]}-{count}>"
+ count += 1
+
+ _compile_and_eval(script, globs, locs, filename)
+
+ return locs[name]
+
+
+def _make_attr_tuple_class(cls_name, attr_names):
+ """
+ Create a tuple subclass to hold `Attribute`s for an `attrs` class.
+
+ The subclass is a bare tuple with properties for names.
+
+ class MyClassAttributes(tuple):
+ __slots__ = ()
+ x = property(itemgetter(0))
+ """
+ attr_class_name = f"{cls_name}Attributes"
+ attr_class_template = [
+ f"class {attr_class_name}(tuple):",
+ " __slots__ = ()",
+ ]
+ if attr_names:
+ for i, attr_name in enumerate(attr_names):
+ attr_class_template.append(
+ f" {attr_name} = _attrs_property(_attrs_itemgetter({i}))"
+ )
+ else:
+ attr_class_template.append(" pass")
+ globs = {"_attrs_itemgetter": itemgetter, "_attrs_property": property}
+ _compile_and_eval("\n".join(attr_class_template), globs)
+ return globs[attr_class_name]
+
+
+# Tuple class for extracted attributes from a class definition.
+# `base_attrs` is a subset of `attrs`.
+_Attributes = _make_attr_tuple_class(
+ "_Attributes",
+ [
+ # all attributes to build dunder methods for
+ "attrs",
+ # attributes that have been inherited
+ "base_attrs",
+ # map inherited attributes to their originating classes
+ "base_attrs_map",
+ ],
+)
+
+
+def _is_class_var(annot):
+ """
+ Check whether *annot* is a typing.ClassVar.
+
+ The string comparison hack is used to avoid evaluating all string
+ annotations which would put attrs-based classes at a performance
+ disadvantage compared to plain old classes.
+ """
+ annot = str(annot)
+
+ # Annotation can be quoted.
+ if annot.startswith(("'", '"')) and annot.endswith(("'", '"')):
+ annot = annot[1:-1]
+
+ return annot.startswith(_CLASSVAR_PREFIXES)
+
+
+def _has_own_attribute(cls, attrib_name):
+ """
+ Check whether *cls* defines *attrib_name* (and doesn't just inherit it).
+ """
+ return attrib_name in cls.__dict__
+
+
+def _collect_base_attrs(cls, taken_attr_names):
+ """
+ Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
+ """
+ base_attrs = []
+ base_attr_map = {} # A dictionary of base attrs to their classes.
+
+ # Traverse the MRO and collect attributes.
+ for base_cls in reversed(cls.__mro__[1:-1]):
+ for a in getattr(base_cls, "__attrs_attrs__", []):
+ if a.inherited or a.name in taken_attr_names:
+ continue
+
+ a = a.evolve(inherited=True) # noqa: PLW2901
+ base_attrs.append(a)
+ base_attr_map[a.name] = base_cls
+
+ # For each name, only keep the freshest definition i.e. the furthest at the
+ # back. base_attr_map is fine because it gets overwritten with every new
+ # instance.
+ filtered = []
+ seen = set()
+ for a in reversed(base_attrs):
+ if a.name in seen:
+ continue
+ filtered.insert(0, a)
+ seen.add(a.name)
+
+ return filtered, base_attr_map
+
+
+def _collect_base_attrs_broken(cls, taken_attr_names):
+ """
+ Collect attr.ibs from base classes of *cls*, except *taken_attr_names*.
+
+ N.B. *taken_attr_names* will be mutated.
+
+ Adhere to the old incorrect behavior.
+
+ Notably it collects from the front and considers inherited attributes which
+ leads to the buggy behavior reported in #428.
+ """
+ base_attrs = []
+ base_attr_map = {} # A dictionary of base attrs to their classes.
+
+ # Traverse the MRO and collect attributes.
+ for base_cls in cls.__mro__[1:-1]:
+ for a in getattr(base_cls, "__attrs_attrs__", []):
+ if a.name in taken_attr_names:
+ continue
+
+ a = a.evolve(inherited=True) # noqa: PLW2901
+ taken_attr_names.add(a.name)
+ base_attrs.append(a)
+ base_attr_map[a.name] = base_cls
+
+ return base_attrs, base_attr_map
+
+
+def _transform_attrs(
+ cls, these, auto_attribs, kw_only, collect_by_mro, field_transformer
+):
+ """
+ Transform all `_CountingAttr`s on a class into `Attribute`s.
+
+ If *these* is passed, use that and don't look for them on the class.
+
+ If *collect_by_mro* is True, collect them in the correct MRO order,
+ otherwise use the old -- incorrect -- order. See #428.
+
+ Return an `_Attributes`.
+ """
+ cd = cls.__dict__
+ anns = _get_annotations(cls)
+
+ if these is not None:
+ ca_list = list(these.items())
+ elif auto_attribs is True:
+ ca_names = {
+ name
+ for name, attr in cd.items()
+ if isinstance(attr, _CountingAttr)
+ }
+ ca_list = []
+ annot_names = set()
+ for attr_name, type in anns.items():
+ if _is_class_var(type):
+ continue
+ annot_names.add(attr_name)
+ a = cd.get(attr_name, NOTHING)
+
+ if not isinstance(a, _CountingAttr):
+ a = attrib() if a is NOTHING else attrib(default=a)
+ ca_list.append((attr_name, a))
+
+ unannotated = ca_names - annot_names
+ if len(unannotated) > 0:
+ raise UnannotatedAttributeError(
+ "The following `attr.ib`s lack a type annotation: "
+ + ", ".join(
+ sorted(unannotated, key=lambda n: cd.get(n).counter)
+ )
+ + "."
+ )
+ else:
+ ca_list = sorted(
+ (
+ (name, attr)
+ for name, attr in cd.items()
+ if isinstance(attr, _CountingAttr)
+ ),
+ key=lambda e: e[1].counter,
+ )
+
+ own_attrs = [
+ Attribute.from_counting_attr(
+ name=attr_name, ca=ca, type=anns.get(attr_name)
+ )
+ for attr_name, ca in ca_list
+ ]
+
+ if collect_by_mro:
+ base_attrs, base_attr_map = _collect_base_attrs(
+ cls, {a.name for a in own_attrs}
+ )
+ else:
+ base_attrs, base_attr_map = _collect_base_attrs_broken(
+ cls, {a.name for a in own_attrs}
+ )
+
+ if kw_only:
+ own_attrs = [a.evolve(kw_only=True) for a in own_attrs]
+ base_attrs = [a.evolve(kw_only=True) for a in base_attrs]
+
+ attrs = base_attrs + own_attrs
+
+ # Mandatory vs non-mandatory attr order only matters when they are part of
+ # the __init__ signature and when they aren't kw_only (which are moved to
+ # the end and can be mandatory or non-mandatory in any order, as they will
+ # be specified as keyword args anyway). Check the order of those attrs:
+ had_default = False
+ for a in (a for a in attrs if a.init is not False and a.kw_only is False):
+ if had_default is True and a.default is NOTHING:
+ msg = f"No mandatory attributes allowed after an attribute with a default value or factory. Attribute in question: {a!r}"
+ raise ValueError(msg)
+
+ if had_default is False and a.default is not NOTHING:
+ had_default = True
+
+ if field_transformer is not None:
+ attrs = field_transformer(cls, attrs)
+
+ # Resolve default field alias after executing field_transformer.
+ # This allows field_transformer to differentiate between explicit vs
+ # default aliases and supply their own defaults.
+ attrs = [
+ a.evolve(alias=_default_init_alias_for(a.name)) if not a.alias else a
+ for a in attrs
+ ]
+
+ # Create AttrsClass *after* applying the field_transformer since it may
+ # add or remove attributes!
+ attr_names = [a.name for a in attrs]
+ AttrsClass = _make_attr_tuple_class(cls.__name__, attr_names)
+
+ return _Attributes((AttrsClass(attrs), base_attrs, base_attr_map))
+
+
+def _make_cached_property_getattr(cached_properties, original_getattr, cls):
+ lines = [
+ # Wrapped to get `__class__` into closure cell for super()
+ # (It will be replaced with the newly constructed class after construction).
+ "def wrapper(_cls):",
+ " __class__ = _cls",
+ " def __getattr__(self, item, cached_properties=cached_properties, original_getattr=original_getattr, _cached_setattr_get=_cached_setattr_get):",
+ " func = cached_properties.get(item)",
+ " if func is not None:",
+ " result = func(self)",
+ " _setter = _cached_setattr_get(self)",
+ " _setter(item, result)",
+ " return result",
+ ]
+ if original_getattr is not None:
+ lines.append(
+ " return original_getattr(self, item)",
+ )
+ else:
+ lines.extend(
+ [
+ " try:",
+ " return super().__getattribute__(item)",
+ " except AttributeError:",
+ " if not hasattr(super(), '__getattr__'):",
+ " raise",
+ " return super().__getattr__(item)",
+ " original_error = f\"'{self.__class__.__name__}' object has no attribute '{item}'\"",
+ " raise AttributeError(original_error)",
+ ]
+ )
+
+ lines.extend(
+ [
+ " return __getattr__",
+ "__getattr__ = wrapper(_cls)",
+ ]
+ )
+
+ unique_filename = _generate_unique_filename(cls, "getattr")
+
+ glob = {
+ "cached_properties": cached_properties,
+ "_cached_setattr_get": _OBJ_SETATTR.__get__,
+ "original_getattr": original_getattr,
+ }
+
+ return _make_method(
+ "__getattr__",
+ "\n".join(lines),
+ unique_filename,
+ glob,
+ locals={
+ "_cls": cls,
+ },
+ )
+
+
+def _frozen_setattrs(self, name, value):
+ """
+ Attached to frozen classes as __setattr__.
+ """
+ if isinstance(self, BaseException) and name in (
+ "__cause__",
+ "__context__",
+ "__traceback__",
+ ):
+ BaseException.__setattr__(self, name, value)
+ return
+
+ raise FrozenInstanceError()
+
+
+def _frozen_delattrs(self, name):
+ """
+ Attached to frozen classes as __delattr__.
+ """
+ raise FrozenInstanceError()
+
+
+class _ClassBuilder:
+ """
+ Iteratively build *one* class.
+ """
+
+ __slots__ = (
+ "_attr_names",
+ "_attrs",
+ "_base_attr_map",
+ "_base_names",
+ "_cache_hash",
+ "_cls",
+ "_cls_dict",
+ "_delete_attribs",
+ "_frozen",
+ "_has_pre_init",
+ "_pre_init_has_args",
+ "_has_post_init",
+ "_is_exc",
+ "_on_setattr",
+ "_slots",
+ "_weakref_slot",
+ "_wrote_own_setattr",
+ "_has_custom_setattr",
+ )
+
+ def __init__(
+ self,
+ cls,
+ these,
+ slots,
+ frozen,
+ weakref_slot,
+ getstate_setstate,
+ auto_attribs,
+ kw_only,
+ cache_hash,
+ is_exc,
+ collect_by_mro,
+ on_setattr,
+ has_custom_setattr,
+ field_transformer,
+ ):
+ attrs, base_attrs, base_map = _transform_attrs(
+ cls,
+ these,
+ auto_attribs,
+ kw_only,
+ collect_by_mro,
+ field_transformer,
+ )
+
+ self._cls = cls
+ self._cls_dict = dict(cls.__dict__) if slots else {}
+ self._attrs = attrs
+ self._base_names = {a.name for a in base_attrs}
+ self._base_attr_map = base_map
+ self._attr_names = tuple(a.name for a in attrs)
+ self._slots = slots
+ self._frozen = frozen
+ self._weakref_slot = weakref_slot
+ self._cache_hash = cache_hash
+ self._has_pre_init = bool(getattr(cls, "__attrs_pre_init__", False))
+ self._pre_init_has_args = False
+ if self._has_pre_init:
+ # Check if the pre init method has more arguments than just `self`
+ # We want to pass arguments if pre init expects arguments
+ pre_init_func = cls.__attrs_pre_init__
+ pre_init_signature = inspect.signature(pre_init_func)
+ self._pre_init_has_args = len(pre_init_signature.parameters) > 1
+ self._has_post_init = bool(getattr(cls, "__attrs_post_init__", False))
+ self._delete_attribs = not bool(these)
+ self._is_exc = is_exc
+ self._on_setattr = on_setattr
+
+ self._has_custom_setattr = has_custom_setattr
+ self._wrote_own_setattr = False
+
+ self._cls_dict["__attrs_attrs__"] = self._attrs
+
+ if frozen:
+ self._cls_dict["__setattr__"] = _frozen_setattrs
+ self._cls_dict["__delattr__"] = _frozen_delattrs
+
+ self._wrote_own_setattr = True
+ elif on_setattr in (
+ _DEFAULT_ON_SETATTR,
+ setters.validate,
+ setters.convert,
+ ):
+ has_validator = has_converter = False
+ for a in attrs:
+ if a.validator is not None:
+ has_validator = True
+ if a.converter is not None:
+ has_converter = True
+
+ if has_validator and has_converter:
+ break
+ if (
+ (
+ on_setattr == _DEFAULT_ON_SETATTR
+ and not (has_validator or has_converter)
+ )
+ or (on_setattr == setters.validate and not has_validator)
+ or (on_setattr == setters.convert and not has_converter)
+ ):
+ # If class-level on_setattr is set to convert + validate, but
+ # there's no field to convert or validate, pretend like there's
+ # no on_setattr.
+ self._on_setattr = None
+
+ if getstate_setstate:
+ (
+ self._cls_dict["__getstate__"],
+ self._cls_dict["__setstate__"],
+ ) = self._make_getstate_setstate()
+
+ def __repr__(self):
+ return f"<_ClassBuilder(cls={self._cls.__name__})>"
+
+ def build_class(self):
+ """
+ Finalize class based on the accumulated configuration.
+
+ Builder cannot be used after calling this method.
+ """
+ if self._slots is True:
+ cls = self._create_slots_class()
+ else:
+ cls = self._patch_original_class()
+ if PY_3_10_PLUS:
+ cls = abc.update_abstractmethods(cls)
+
+ # The method gets only called if it's not inherited from a base class.
+ # _has_own_attribute does NOT work properly for classmethods.
+ if (
+ getattr(cls, "__attrs_init_subclass__", None)
+ and "__attrs_init_subclass__" not in cls.__dict__
+ ):
+ cls.__attrs_init_subclass__()
+
+ return cls
+
+ def _patch_original_class(self):
+ """
+ Apply accumulated methods and return the class.
+ """
+ cls = self._cls
+ base_names = self._base_names
+
+ # Clean class of attribute definitions (`attr.ib()`s).
+ if self._delete_attribs:
+ for name in self._attr_names:
+ if (
+ name not in base_names
+ and getattr(cls, name, _SENTINEL) is not _SENTINEL
+ ):
+ # An AttributeError can happen if a base class defines a
+ # class variable and we want to set an attribute with the
+ # same name by using only a type annotation.
+ with contextlib.suppress(AttributeError):
+ delattr(cls, name)
+
+ # Attach our dunder methods.
+ for name, value in self._cls_dict.items():
+ setattr(cls, name, value)
+
+ # If we've inherited an attrs __setattr__ and don't write our own,
+ # reset it to object's.
+ if not self._wrote_own_setattr and getattr(
+ cls, "__attrs_own_setattr__", False
+ ):
+ cls.__attrs_own_setattr__ = False
+
+ if not self._has_custom_setattr:
+ cls.__setattr__ = _OBJ_SETATTR
+
+ return cls
+
+ def _create_slots_class(self):
+ """
+ Build and return a new class with a `__slots__` attribute.
+ """
+ cd = {
+ k: v
+ for k, v in self._cls_dict.items()
+ if k not in (*tuple(self._attr_names), "__dict__", "__weakref__")
+ }
+
+ # If our class doesn't have its own implementation of __setattr__
+ # (either from the user or by us), check the bases, if one of them has
+ # an attrs-made __setattr__, that needs to be reset. We don't walk the
+ # MRO because we only care about our immediate base classes.
+ # XXX: This can be confused by subclassing a slotted attrs class with
+ # XXX: a non-attrs class and subclass the resulting class with an attrs
+ # XXX: class. See `test_slotted_confused` for details. For now that's
+ # XXX: OK with us.
+ if not self._wrote_own_setattr:
+ cd["__attrs_own_setattr__"] = False
+
+ if not self._has_custom_setattr:
+ for base_cls in self._cls.__bases__:
+ if base_cls.__dict__.get("__attrs_own_setattr__", False):
+ cd["__setattr__"] = _OBJ_SETATTR
+ break
+
+ # Traverse the MRO to collect existing slots
+ # and check for an existing __weakref__.
+ existing_slots = {}
+ weakref_inherited = False
+ for base_cls in self._cls.__mro__[1:-1]:
+ if base_cls.__dict__.get("__weakref__", None) is not None:
+ weakref_inherited = True
+ existing_slots.update(
+ {
+ name: getattr(base_cls, name)
+ for name in getattr(base_cls, "__slots__", [])
+ }
+ )
+
+ base_names = set(self._base_names)
+
+ names = self._attr_names
+ if (
+ self._weakref_slot
+ and "__weakref__" not in getattr(self._cls, "__slots__", ())
+ and "__weakref__" not in names
+ and not weakref_inherited
+ ):
+ names += ("__weakref__",)
+
+ if PY_3_8_PLUS:
+ cached_properties = {
+ name: cached_property.func
+ for name, cached_property in cd.items()
+ if isinstance(cached_property, functools.cached_property)
+ }
+ else:
+ # `functools.cached_property` was introduced in 3.8.
+ # So can't be used before this.
+ cached_properties = {}
+
+ # Collect methods with a `__class__` reference that are shadowed in the new class.
+ # To know to update them.
+ additional_closure_functions_to_update = []
+ if cached_properties:
+ class_annotations = _get_annotations(self._cls)
+ for name, func in cached_properties.items():
+ # Add cached properties to names for slotting.
+ names += (name,)
+ # Clear out function from class to avoid clashing.
+ del cd[name]
+ additional_closure_functions_to_update.append(func)
+ annotation = inspect.signature(func).return_annotation
+ if annotation is not inspect.Parameter.empty:
+ class_annotations[name] = annotation
+
+ original_getattr = cd.get("__getattr__")
+ if original_getattr is not None:
+ additional_closure_functions_to_update.append(original_getattr)
+
+ cd["__getattr__"] = _make_cached_property_getattr(
+ cached_properties, original_getattr, self._cls
+ )
+
+ # We only add the names of attributes that aren't inherited.
+ # Setting __slots__ to inherited attributes wastes memory.
+ slot_names = [name for name in names if name not in base_names]
+
+ # There are slots for attributes from current class
+ # that are defined in parent classes.
+ # As their descriptors may be overridden by a child class,
+ # we collect them here and update the class dict
+ reused_slots = {
+ slot: slot_descriptor
+ for slot, slot_descriptor in existing_slots.items()
+ if slot in slot_names
+ }
+ slot_names = [name for name in slot_names if name not in reused_slots]
+ cd.update(reused_slots)
+ if self._cache_hash:
+ slot_names.append(_HASH_CACHE_FIELD)
+
+ cd["__slots__"] = tuple(slot_names)
+
+ cd["__qualname__"] = self._cls.__qualname__
+
+ # Create new class based on old class and our methods.
+ cls = type(self._cls)(self._cls.__name__, self._cls.__bases__, cd)
+
+ # The following is a fix for
+ # .
+ # If a method mentions `__class__` or uses the no-arg super(), the
+ # compiler will bake a reference to the class in the method itself
+ # as `method.__closure__`. Since we replace the class with a
+ # clone, we rewrite these references so it keeps working.
+ for item in itertools.chain(
+ cls.__dict__.values(), additional_closure_functions_to_update
+ ):
+ if isinstance(item, (classmethod, staticmethod)):
+ # Class- and staticmethods hide their functions inside.
+ # These might need to be rewritten as well.
+ closure_cells = getattr(item.__func__, "__closure__", None)
+ elif isinstance(item, property):
+ # Workaround for property `super()` shortcut (PY3-only).
+ # There is no universal way for other descriptors.
+ closure_cells = getattr(item.fget, "__closure__", None)
+ else:
+ closure_cells = getattr(item, "__closure__", None)
+
+ if not closure_cells: # Catch None or the empty list.
+ continue
+ for cell in closure_cells:
+ try:
+ match = cell.cell_contents is self._cls
+ except ValueError: # noqa: PERF203
+ # ValueError: Cell is empty
+ pass
+ else:
+ if match:
+ cell.cell_contents = cls
+ return cls
+
+ def add_repr(self, ns):
+ self._cls_dict["__repr__"] = self._add_method_dunders(
+ _make_repr(self._attrs, ns, self._cls)
+ )
+ return self
+
+ def add_str(self):
+ repr = self._cls_dict.get("__repr__")
+ if repr is None:
+ msg = "__str__ can only be generated if a __repr__ exists."
+ raise ValueError(msg)
+
+ def __str__(self):
+ return self.__repr__()
+
+ self._cls_dict["__str__"] = self._add_method_dunders(__str__)
+ return self
+
+ def _make_getstate_setstate(self):
+ """
+ Create custom __setstate__ and __getstate__ methods.
+ """
+ # __weakref__ is not writable.
+ state_attr_names = tuple(
+ an for an in self._attr_names if an != "__weakref__"
+ )
+
+ def slots_getstate(self):
+ """
+ Automatically created by attrs.
+ """
+ return {name: getattr(self, name) for name in state_attr_names}
+
+ hash_caching_enabled = self._cache_hash
+
+ def slots_setstate(self, state):
+ """
+ Automatically created by attrs.
+ """
+ __bound_setattr = _OBJ_SETATTR.__get__(self)
+ if isinstance(state, tuple):
+ # Backward compatibility with attrs instances pickled with
+ # attrs versions before v22.2.0 which stored tuples.
+ for name, value in zip(state_attr_names, state):
+ __bound_setattr(name, value)
+ else:
+ for name in state_attr_names:
+ if name in state:
+ __bound_setattr(name, state[name])
+
+ # The hash code cache is not included when the object is
+ # serialized, but it still needs to be initialized to None to
+ # indicate that the first call to __hash__ should be a cache
+ # miss.
+ if hash_caching_enabled:
+ __bound_setattr(_HASH_CACHE_FIELD, None)
+
+ return slots_getstate, slots_setstate
+
+ def make_unhashable(self):
+ self._cls_dict["__hash__"] = None
+ return self
+
+ def add_hash(self):
+ self._cls_dict["__hash__"] = self._add_method_dunders(
+ _make_hash(
+ self._cls,
+ self._attrs,
+ frozen=self._frozen,
+ cache_hash=self._cache_hash,
+ )
+ )
+
+ return self
+
+ def add_init(self):
+ self._cls_dict["__init__"] = self._add_method_dunders(
+ _make_init(
+ self._cls,
+ self._attrs,
+ self._has_pre_init,
+ self._pre_init_has_args,
+ self._has_post_init,
+ self._frozen,
+ self._slots,
+ self._cache_hash,
+ self._base_attr_map,
+ self._is_exc,
+ self._on_setattr,
+ attrs_init=False,
+ )
+ )
+
+ return self
+
+ def add_match_args(self):
+ self._cls_dict["__match_args__"] = tuple(
+ field.name
+ for field in self._attrs
+ if field.init and not field.kw_only
+ )
+
+ def add_attrs_init(self):
+ self._cls_dict["__attrs_init__"] = self._add_method_dunders(
+ _make_init(
+ self._cls,
+ self._attrs,
+ self._has_pre_init,
+ self._pre_init_has_args,
+ self._has_post_init,
+ self._frozen,
+ self._slots,
+ self._cache_hash,
+ self._base_attr_map,
+ self._is_exc,
+ self._on_setattr,
+ attrs_init=True,
+ )
+ )
+
+ return self
+
+ def add_eq(self):
+ cd = self._cls_dict
+
+ cd["__eq__"] = self._add_method_dunders(
+ _make_eq(self._cls, self._attrs)
+ )
+ cd["__ne__"] = self._add_method_dunders(_make_ne())
+
+ return self
+
+ def add_order(self):
+ cd = self._cls_dict
+
+ cd["__lt__"], cd["__le__"], cd["__gt__"], cd["__ge__"] = (
+ self._add_method_dunders(meth)
+ for meth in _make_order(self._cls, self._attrs)
+ )
+
+ return self
+
+ def add_setattr(self):
+ if self._frozen:
+ return self
+
+ sa_attrs = {}
+ for a in self._attrs:
+ on_setattr = a.on_setattr or self._on_setattr
+ if on_setattr and on_setattr is not setters.NO_OP:
+ sa_attrs[a.name] = a, on_setattr
+
+ if not sa_attrs:
+ return self
+
+ if self._has_custom_setattr:
+ # We need to write a __setattr__ but there already is one!
+ msg = "Can't combine custom __setattr__ with on_setattr hooks."
+ raise ValueError(msg)
+
+ # docstring comes from _add_method_dunders
+ def __setattr__(self, name, val):
+ try:
+ a, hook = sa_attrs[name]
+ except KeyError:
+ nval = val
+ else:
+ nval = hook(self, a, val)
+
+ _OBJ_SETATTR(self, name, nval)
+
+ self._cls_dict["__attrs_own_setattr__"] = True
+ self._cls_dict["__setattr__"] = self._add_method_dunders(__setattr__)
+ self._wrote_own_setattr = True
+
+ return self
+
+ def _add_method_dunders(self, method):
+ """
+ Add __module__ and __qualname__ to a *method* if possible.
+ """
+ with contextlib.suppress(AttributeError):
+ method.__module__ = self._cls.__module__
+
+ with contextlib.suppress(AttributeError):
+ method.__qualname__ = f"{self._cls.__qualname__}.{method.__name__}"
+
+ with contextlib.suppress(AttributeError):
+ method.__doc__ = (
+ "Method generated by attrs for class "
+ f"{self._cls.__qualname__}."
+ )
+
+ return method
+
+
+def _determine_attrs_eq_order(cmp, eq, order, default_eq):
+ """
+ Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
+ values of eq and order. If *eq* is None, set it to *default_eq*.
+ """
+ if cmp is not None and any((eq is not None, order is not None)):
+ msg = "Don't mix `cmp` with `eq' and `order`."
+ raise ValueError(msg)
+
+ # cmp takes precedence due to bw-compatibility.
+ if cmp is not None:
+ return cmp, cmp
+
+ # If left None, equality is set to the specified default and ordering
+ # mirrors equality.
+ if eq is None:
+ eq = default_eq
+
+ if order is None:
+ order = eq
+
+ if eq is False and order is True:
+ msg = "`order` can only be True if `eq` is True too."
+ raise ValueError(msg)
+
+ return eq, order
+
+
+def _determine_attrib_eq_order(cmp, eq, order, default_eq):
+ """
+ Validate the combination of *cmp*, *eq*, and *order*. Derive the effective
+ values of eq and order. If *eq* is None, set it to *default_eq*.
+ """
+ if cmp is not None and any((eq is not None, order is not None)):
+ msg = "Don't mix `cmp` with `eq' and `order`."
+ raise ValueError(msg)
+
+ def decide_callable_or_boolean(value):
+ """
+ Decide whether a key function is used.
+ """
+ if callable(value):
+ value, key = True, value
+ else:
+ key = None
+ return value, key
+
+ # cmp takes precedence due to bw-compatibility.
+ if cmp is not None:
+ cmp, cmp_key = decide_callable_or_boolean(cmp)
+ return cmp, cmp_key, cmp, cmp_key
+
+ # If left None, equality is set to the specified default and ordering
+ # mirrors equality.
+ if eq is None:
+ eq, eq_key = default_eq, None
+ else:
+ eq, eq_key = decide_callable_or_boolean(eq)
+
+ if order is None:
+ order, order_key = eq, eq_key
+ else:
+ order, order_key = decide_callable_or_boolean(order)
+
+ if eq is False and order is True:
+ msg = "`order` can only be True if `eq` is True too."
+ raise ValueError(msg)
+
+ return eq, eq_key, order, order_key
+
+
+def _determine_whether_to_implement(
+ cls, flag, auto_detect, dunders, default=True
+):
+ """
+ Check whether we should implement a set of methods for *cls*.
+
+ *flag* is the argument passed into @attr.s like 'init', *auto_detect* the
+ same as passed into @attr.s and *dunders* is a tuple of attribute names
+ whose presence signal that the user has implemented it themselves.
+
+ Return *default* if no reason for either for or against is found.
+ """
+ if flag is True or flag is False:
+ return flag
+
+ if flag is None and auto_detect is False:
+ return default
+
+ # Logically, flag is None and auto_detect is True here.
+ for dunder in dunders:
+ if _has_own_attribute(cls, dunder):
+ return False
+
+ return default
+
+
+def attrs(
+ maybe_cls=None,
+ these=None,
+ repr_ns=None,
+ repr=None,
+ cmp=None,
+ hash=None,
+ init=None,
+ slots=False,
+ frozen=False,
+ weakref_slot=True,
+ str=False,
+ auto_attribs=False,
+ kw_only=False,
+ cache_hash=False,
+ auto_exc=False,
+ eq=None,
+ order=None,
+ auto_detect=False,
+ collect_by_mro=False,
+ getstate_setstate=None,
+ on_setattr=None,
+ field_transformer=None,
+ match_args=True,
+ unsafe_hash=None,
+):
+ r"""
+ A class decorator that adds :term:`dunder methods` according to the
+ specified attributes using `attr.ib` or the *these* argument.
+
+ Consider using `attrs.define` / `attrs.frozen` in new code (``attr.s`` will
+ *never* go away, though).
+
+ Args:
+ repr_ns (str):
+ When using nested classes, there was no way in Python 2 to
+ automatically detect that. This argument allows to set a custom
+ name for a more meaningful ``repr`` output. This argument is
+ pointless in Python 3 and is therefore deprecated.
+
+ .. caution::
+ Refer to `attrs.define` for the rest of the parameters, but note that they
+ can have different defaults.
+
+ Notably, leaving *on_setattr* as `None` will **not** add any hooks.
+
+ .. versionadded:: 16.0.0 *slots*
+ .. versionadded:: 16.1.0 *frozen*
+ .. versionadded:: 16.3.0 *str*
+ .. versionadded:: 16.3.0 Support for ``__attrs_post_init__``.
+ .. versionchanged:: 17.1.0
+ *hash* supports `None` as value which is also the default now.
+ .. versionadded:: 17.3.0 *auto_attribs*
+ .. versionchanged:: 18.1.0
+ If *these* is passed, no attributes are deleted from the class body.
+ .. versionchanged:: 18.1.0 If *these* is ordered, the order is retained.
+ .. versionadded:: 18.2.0 *weakref_slot*
+ .. deprecated:: 18.2.0
+ ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now raise a
+ `DeprecationWarning` if the classes compared are subclasses of
+ each other. ``__eq`` and ``__ne__`` never tried to compared subclasses
+ to each other.
+ .. versionchanged:: 19.2.0
+ ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__`` now do not consider
+ subclasses comparable anymore.
+ .. versionadded:: 18.2.0 *kw_only*
+ .. versionadded:: 18.2.0 *cache_hash*
+ .. versionadded:: 19.1.0 *auto_exc*
+ .. deprecated:: 19.2.0 *cmp* Removal on or after 2021-06-01.
+ .. versionadded:: 19.2.0 *eq* and *order*
+ .. versionadded:: 20.1.0 *auto_detect*
+ .. versionadded:: 20.1.0 *collect_by_mro*
+ .. versionadded:: 20.1.0 *getstate_setstate*
+ .. versionadded:: 20.1.0 *on_setattr*
+ .. versionadded:: 20.3.0 *field_transformer*
+ .. versionchanged:: 21.1.0
+ ``init=False`` injects ``__attrs_init__``
+ .. versionchanged:: 21.1.0 Support for ``__attrs_pre_init__``
+ .. versionchanged:: 21.1.0 *cmp* undeprecated
+ .. versionadded:: 21.3.0 *match_args*
+ .. versionadded:: 22.2.0
+ *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance).
+ .. deprecated:: 24.1.0 *repr_ns*
+ .. versionchanged:: 24.1.0
+ Instances are not compared as tuples of attributes anymore, but using a
+ big ``and`` condition. This is faster and has more correct behavior for
+ uncomparable values like `math.nan`.
+ .. versionadded:: 24.1.0
+ If a class has an *inherited* classmethod called
+ ``__attrs_init_subclass__``, it is executed after the class is created.
+ .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*.
+ """
+ if repr_ns is not None:
+ import warnings
+
+ warnings.warn(
+ DeprecationWarning(
+ "The `repr_ns` argument is deprecated and will be removed in or after August 2025."
+ ),
+ stacklevel=2,
+ )
+
+ eq_, order_ = _determine_attrs_eq_order(cmp, eq, order, None)
+
+ # unsafe_hash takes precedence due to PEP 681.
+ if unsafe_hash is not None:
+ hash = unsafe_hash
+
+ if isinstance(on_setattr, (list, tuple)):
+ on_setattr = setters.pipe(*on_setattr)
+
+ def wrap(cls):
+ is_frozen = frozen or _has_frozen_base_class(cls)
+ is_exc = auto_exc is True and issubclass(cls, BaseException)
+ has_own_setattr = auto_detect and _has_own_attribute(
+ cls, "__setattr__"
+ )
+
+ if has_own_setattr and is_frozen:
+ msg = "Can't freeze a class with a custom __setattr__."
+ raise ValueError(msg)
+
+ builder = _ClassBuilder(
+ cls,
+ these,
+ slots,
+ is_frozen,
+ weakref_slot,
+ _determine_whether_to_implement(
+ cls,
+ getstate_setstate,
+ auto_detect,
+ ("__getstate__", "__setstate__"),
+ default=slots,
+ ),
+ auto_attribs,
+ kw_only,
+ cache_hash,
+ is_exc,
+ collect_by_mro,
+ on_setattr,
+ has_own_setattr,
+ field_transformer,
+ )
+ if _determine_whether_to_implement(
+ cls, repr, auto_detect, ("__repr__",)
+ ):
+ builder.add_repr(repr_ns)
+ if str is True:
+ builder.add_str()
+
+ eq = _determine_whether_to_implement(
+ cls, eq_, auto_detect, ("__eq__", "__ne__")
+ )
+ if not is_exc and eq is True:
+ builder.add_eq()
+ if not is_exc and _determine_whether_to_implement(
+ cls, order_, auto_detect, ("__lt__", "__le__", "__gt__", "__ge__")
+ ):
+ builder.add_order()
+
+ builder.add_setattr()
+
+ nonlocal hash
+ if (
+ hash is None
+ and auto_detect is True
+ and _has_own_attribute(cls, "__hash__")
+ ):
+ hash = False
+
+ if hash is not True and hash is not False and hash is not None:
+ # Can't use `hash in` because 1 == True for example.
+ msg = "Invalid value for hash. Must be True, False, or None."
+ raise TypeError(msg)
+
+ if hash is False or (hash is None and eq is False) or is_exc:
+ # Don't do anything. Should fall back to __object__'s __hash__
+ # which is by id.
+ if cache_hash:
+ msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
+ raise TypeError(msg)
+ elif hash is True or (
+ hash is None and eq is True and is_frozen is True
+ ):
+ # Build a __hash__ if told so, or if it's safe.
+ builder.add_hash()
+ else:
+ # Raise TypeError on attempts to hash.
+ if cache_hash:
+ msg = "Invalid value for cache_hash. To use hash caching, hashing must be either explicitly or implicitly enabled."
+ raise TypeError(msg)
+ builder.make_unhashable()
+
+ if _determine_whether_to_implement(
+ cls, init, auto_detect, ("__init__",)
+ ):
+ builder.add_init()
+ else:
+ builder.add_attrs_init()
+ if cache_hash:
+ msg = "Invalid value for cache_hash. To use hash caching, init must be True."
+ raise TypeError(msg)
+
+ if (
+ PY_3_10_PLUS
+ and match_args
+ and not _has_own_attribute(cls, "__match_args__")
+ ):
+ builder.add_match_args()
+
+ return builder.build_class()
+
+ # maybe_cls's type depends on the usage of the decorator. It's a class
+ # if it's used as `@attrs` but `None` if used as `@attrs()`.
+ if maybe_cls is None:
+ return wrap
+
+ return wrap(maybe_cls)
+
+
+_attrs = attrs
+"""
+Internal alias so we can use it in functions that take an argument called
+*attrs*.
+"""
+
+
+def _has_frozen_base_class(cls):
+ """
+ Check whether *cls* has a frozen ancestor by looking at its
+ __setattr__.
+ """
+ return cls.__setattr__ is _frozen_setattrs
+
+
+def _generate_unique_filename(cls, func_name):
+ """
+ Create a "filename" suitable for a function being generated.
+ """
+ return (
+ f""
+ )
+
+
+def _make_hash(cls, attrs, frozen, cache_hash):
+ attrs = tuple(
+ a for a in attrs if a.hash is True or (a.hash is None and a.eq is True)
+ )
+
+ tab = " "
+
+ unique_filename = _generate_unique_filename(cls, "hash")
+ type_hash = hash(unique_filename)
+ # If eq is custom generated, we need to include the functions in globs
+ globs = {}
+
+ hash_def = "def __hash__(self"
+ hash_func = "hash(("
+ closing_braces = "))"
+ if not cache_hash:
+ hash_def += "):"
+ else:
+ hash_def += ", *"
+
+ hash_def += ", _cache_wrapper=__import__('attr._make')._make._CacheHashWrapper):"
+ hash_func = "_cache_wrapper(" + hash_func
+ closing_braces += ")"
+
+ method_lines = [hash_def]
+
+ def append_hash_computation_lines(prefix, indent):
+ """
+ Generate the code for actually computing the hash code.
+ Below this will either be returned directly or used to compute
+ a value which is then cached, depending on the value of cache_hash
+ """
+
+ method_lines.extend(
+ [
+ indent + prefix + hash_func,
+ indent + f" {type_hash},",
+ ]
+ )
+
+ for a in attrs:
+ if a.eq_key:
+ cmp_name = f"_{a.name}_key"
+ globs[cmp_name] = a.eq_key
+ method_lines.append(
+ indent + f" {cmp_name}(self.{a.name}),"
+ )
+ else:
+ method_lines.append(indent + f" self.{a.name},")
+
+ method_lines.append(indent + " " + closing_braces)
+
+ if cache_hash:
+ method_lines.append(tab + f"if self.{_HASH_CACHE_FIELD} is None:")
+ if frozen:
+ append_hash_computation_lines(
+ f"object.__setattr__(self, '{_HASH_CACHE_FIELD}', ", tab * 2
+ )
+ method_lines.append(tab * 2 + ")") # close __setattr__
+ else:
+ append_hash_computation_lines(
+ f"self.{_HASH_CACHE_FIELD} = ", tab * 2
+ )
+ method_lines.append(tab + f"return self.{_HASH_CACHE_FIELD}")
+ else:
+ append_hash_computation_lines("return ", tab)
+
+ script = "\n".join(method_lines)
+ return _make_method("__hash__", script, unique_filename, globs)
+
+
+def _add_hash(cls, attrs):
+ """
+ Add a hash method to *cls*.
+ """
+ cls.__hash__ = _make_hash(cls, attrs, frozen=False, cache_hash=False)
+ return cls
+
+
+def _make_ne():
+ """
+ Create __ne__ method.
+ """
+
+ def __ne__(self, other):
+ """
+ Check equality and either forward a NotImplemented or
+ return the result negated.
+ """
+ result = self.__eq__(other)
+ if result is NotImplemented:
+ return NotImplemented
+
+ return not result
+
+ return __ne__
+
+
+def _make_eq(cls, attrs):
+ """
+ Create __eq__ method for *cls* with *attrs*.
+ """
+ attrs = [a for a in attrs if a.eq]
+
+ unique_filename = _generate_unique_filename(cls, "eq")
+ lines = [
+ "def __eq__(self, other):",
+ " if other.__class__ is not self.__class__:",
+ " return NotImplemented",
+ ]
+
+ # We can't just do a big self.x = other.x and... clause due to
+ # irregularities like nan == nan is false but (nan,) == (nan,) is true.
+ globs = {}
+ if attrs:
+ lines.append(" return (")
+ for a in attrs:
+ if a.eq_key:
+ cmp_name = f"_{a.name}_key"
+ # Add the key function to the global namespace
+ # of the evaluated function.
+ globs[cmp_name] = a.eq_key
+ lines.append(
+ f" {cmp_name}(self.{a.name}) == {cmp_name}(other.{a.name})"
+ )
+ else:
+ lines.append(f" self.{a.name} == other.{a.name}")
+ if a is not attrs[-1]:
+ lines[-1] = f"{lines[-1]} and"
+ lines.append(" )")
+ else:
+ lines.append(" return True")
+
+ script = "\n".join(lines)
+
+ return _make_method("__eq__", script, unique_filename, globs)
+
+
+def _make_order(cls, attrs):
+ """
+ Create ordering methods for *cls* with *attrs*.
+ """
+ attrs = [a for a in attrs if a.order]
+
+ def attrs_to_tuple(obj):
+ """
+ Save us some typing.
+ """
+ return tuple(
+ key(value) if key else value
+ for value, key in (
+ (getattr(obj, a.name), a.order_key) for a in attrs
+ )
+ )
+
+ def __lt__(self, other):
+ """
+ Automatically created by attrs.
+ """
+ if other.__class__ is self.__class__:
+ return attrs_to_tuple(self) < attrs_to_tuple(other)
+
+ return NotImplemented
+
+ def __le__(self, other):
+ """
+ Automatically created by attrs.
+ """
+ if other.__class__ is self.__class__:
+ return attrs_to_tuple(self) <= attrs_to_tuple(other)
+
+ return NotImplemented
+
+ def __gt__(self, other):
+ """
+ Automatically created by attrs.
+ """
+ if other.__class__ is self.__class__:
+ return attrs_to_tuple(self) > attrs_to_tuple(other)
+
+ return NotImplemented
+
+ def __ge__(self, other):
+ """
+ Automatically created by attrs.
+ """
+ if other.__class__ is self.__class__:
+ return attrs_to_tuple(self) >= attrs_to_tuple(other)
+
+ return NotImplemented
+
+ return __lt__, __le__, __gt__, __ge__
+
+
+def _add_eq(cls, attrs=None):
+ """
+ Add equality methods to *cls* with *attrs*.
+ """
+ if attrs is None:
+ attrs = cls.__attrs_attrs__
+
+ cls.__eq__ = _make_eq(cls, attrs)
+ cls.__ne__ = _make_ne()
+
+ return cls
+
+
+def _make_repr(attrs, ns, cls):
+ unique_filename = _generate_unique_filename(cls, "repr")
+ # Figure out which attributes to include, and which function to use to
+ # format them. The a.repr value can be either bool or a custom
+ # callable.
+ attr_names_with_reprs = tuple(
+ (a.name, (repr if a.repr is True else a.repr), a.init)
+ for a in attrs
+ if a.repr is not False
+ )
+ globs = {
+ name + "_repr": r for name, r, _ in attr_names_with_reprs if r != repr
+ }
+ globs["_compat"] = _compat
+ globs["AttributeError"] = AttributeError
+ globs["NOTHING"] = NOTHING
+ attribute_fragments = []
+ for name, r, i in attr_names_with_reprs:
+ accessor = (
+ "self." + name if i else 'getattr(self, "' + name + '", NOTHING)'
+ )
+ fragment = (
+ "%s={%s!r}" % (name, accessor)
+ if r == repr
+ else "%s={%s_repr(%s)}" % (name, name, accessor)
+ )
+ attribute_fragments.append(fragment)
+ repr_fragment = ", ".join(attribute_fragments)
+
+ if ns is None:
+ cls_name_fragment = '{self.__class__.__qualname__.rsplit(">.", 1)[-1]}'
+ else:
+ cls_name_fragment = ns + ".{self.__class__.__name__}"
+
+ lines = [
+ "def __repr__(self):",
+ " try:",
+ " already_repring = _compat.repr_context.already_repring",
+ " except AttributeError:",
+ " already_repring = {id(self),}",
+ " _compat.repr_context.already_repring = already_repring",
+ " else:",
+ " if id(self) in already_repring:",
+ " return '...'",
+ " else:",
+ " already_repring.add(id(self))",
+ " try:",
+ f" return f'{cls_name_fragment}({repr_fragment})'",
+ " finally:",
+ " already_repring.remove(id(self))",
+ ]
+
+ return _make_method(
+ "__repr__", "\n".join(lines), unique_filename, globs=globs
+ )
+
+
+def _add_repr(cls, ns=None, attrs=None):
+ """
+ Add a repr method to *cls*.
+ """
+ if attrs is None:
+ attrs = cls.__attrs_attrs__
+
+ cls.__repr__ = _make_repr(attrs, ns, cls)
+ return cls
+
+
+def fields(cls):
+ """
+ Return the tuple of *attrs* attributes for a class.
+
+ The tuple also allows accessing the fields by their names (see below for
+ examples).
+
+ Args:
+ cls (type): Class to introspect.
+
+ Raises:
+ TypeError: If *cls* is not a class.
+
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ Returns:
+ tuple (with name accessors) of `attrs.Attribute`
+
+ .. versionchanged:: 16.2.0 Returned tuple allows accessing the fields
+ by name.
+ .. versionchanged:: 23.1.0 Add support for generic classes.
+ """
+ generic_base = get_generic_base(cls)
+
+ if generic_base is None and not isinstance(cls, type):
+ msg = "Passed object must be a class."
+ raise TypeError(msg)
+
+ attrs = getattr(cls, "__attrs_attrs__", None)
+
+ if attrs is None:
+ if generic_base is not None:
+ attrs = getattr(generic_base, "__attrs_attrs__", None)
+ if attrs is not None:
+ # Even though this is global state, stick it on here to speed
+ # it up. We rely on `cls` being cached for this to be
+ # efficient.
+ cls.__attrs_attrs__ = attrs
+ return attrs
+ msg = f"{cls!r} is not an attrs-decorated class."
+ raise NotAnAttrsClassError(msg)
+
+ return attrs
+
+
+def fields_dict(cls):
+ """
+ Return an ordered dictionary of *attrs* attributes for a class, whose keys
+ are the attribute names.
+
+ Args:
+ cls (type): Class to introspect.
+
+ Raises:
+ TypeError: If *cls* is not a class.
+
+ attrs.exceptions.NotAnAttrsClassError:
+ If *cls* is not an *attrs* class.
+
+ Returns:
+ dict[str, attrs.Attribute]: Dict of attribute name to definition
+
+ .. versionadded:: 18.1.0
+ """
+ if not isinstance(cls, type):
+ msg = "Passed object must be a class."
+ raise TypeError(msg)
+ attrs = getattr(cls, "__attrs_attrs__", None)
+ if attrs is None:
+ msg = f"{cls!r} is not an attrs-decorated class."
+ raise NotAnAttrsClassError(msg)
+ return {a.name: a for a in attrs}
+
+
+def validate(inst):
+ """
+ Validate all attributes on *inst* that have a validator.
+
+ Leaves all exceptions through.
+
+ Args:
+ inst: Instance of a class with *attrs* attributes.
+ """
+ if _config._run_validators is False:
+ return
+
+ for a in fields(inst.__class__):
+ v = a.validator
+ if v is not None:
+ v(inst, a, getattr(inst, a.name))
+
+
+def _is_slot_attr(a_name, base_attr_map):
+ """
+ Check if the attribute name comes from a slot class.
+ """
+ cls = base_attr_map.get(a_name)
+ return cls and "__slots__" in cls.__dict__
+
+
+def _make_init(
+ cls,
+ attrs,
+ pre_init,
+ pre_init_has_args,
+ post_init,
+ frozen,
+ slots,
+ cache_hash,
+ base_attr_map,
+ is_exc,
+ cls_on_setattr,
+ attrs_init,
+):
+ has_cls_on_setattr = (
+ cls_on_setattr is not None and cls_on_setattr is not setters.NO_OP
+ )
+
+ if frozen and has_cls_on_setattr:
+ msg = "Frozen classes can't use on_setattr."
+ raise ValueError(msg)
+
+ needs_cached_setattr = cache_hash or frozen
+ filtered_attrs = []
+ attr_dict = {}
+ for a in attrs:
+ if not a.init and a.default is NOTHING:
+ continue
+
+ filtered_attrs.append(a)
+ attr_dict[a.name] = a
+
+ if a.on_setattr is not None:
+ if frozen is True:
+ msg = "Frozen classes can't use on_setattr."
+ raise ValueError(msg)
+
+ needs_cached_setattr = True
+ elif has_cls_on_setattr and a.on_setattr is not setters.NO_OP:
+ needs_cached_setattr = True
+
+ unique_filename = _generate_unique_filename(cls, "init")
+
+ script, globs, annotations = _attrs_to_init_script(
+ filtered_attrs,
+ frozen,
+ slots,
+ pre_init,
+ pre_init_has_args,
+ post_init,
+ cache_hash,
+ base_attr_map,
+ is_exc,
+ needs_cached_setattr,
+ has_cls_on_setattr,
+ "__attrs_init__" if attrs_init else "__init__",
+ )
+ if cls.__module__ in sys.modules:
+ # This makes typing.get_type_hints(CLS.__init__) resolve string types.
+ globs.update(sys.modules[cls.__module__].__dict__)
+
+ globs.update({"NOTHING": NOTHING, "attr_dict": attr_dict})
+
+ if needs_cached_setattr:
+ # Save the lookup overhead in __init__ if we need to circumvent
+ # setattr hooks.
+ globs["_cached_setattr_get"] = _OBJ_SETATTR.__get__
+
+ init = _make_method(
+ "__attrs_init__" if attrs_init else "__init__",
+ script,
+ unique_filename,
+ globs,
+ )
+ init.__annotations__ = annotations
+
+ return init
+
+
+def _setattr(attr_name: str, value_var: str, has_on_setattr: bool) -> str:
+ """
+ Use the cached object.setattr to set *attr_name* to *value_var*.
+ """
+ return f"_setattr('{attr_name}', {value_var})"
+
+
+def _setattr_with_converter(
+ attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter
+) -> str:
+ """
+ Use the cached object.setattr to set *attr_name* to *value_var*, but run
+ its converter first.
+ """
+ return f"_setattr('{attr_name}', {converter._fmt_converter_call(attr_name, value_var)})"
+
+
+def _assign(attr_name: str, value: str, has_on_setattr: bool) -> str:
+ """
+ Unless *attr_name* has an on_setattr hook, use normal assignment. Otherwise
+ relegate to _setattr.
+ """
+ if has_on_setattr:
+ return _setattr(attr_name, value, True)
+
+ return f"self.{attr_name} = {value}"
+
+
+def _assign_with_converter(
+ attr_name: str, value_var: str, has_on_setattr: bool, converter: Converter
+) -> str:
+ """
+ Unless *attr_name* has an on_setattr hook, use normal assignment after
+ conversion. Otherwise relegate to _setattr_with_converter.
+ """
+ if has_on_setattr:
+ return _setattr_with_converter(attr_name, value_var, True, converter)
+
+ return f"self.{attr_name} = {converter._fmt_converter_call(attr_name, value_var)}"
+
+
+def _determine_setters(
+ frozen: bool, slots: bool, base_attr_map: dict[str, type]
+):
+ """
+ Determine the correct setter functions based on whether a class is frozen
+ and/or slotted.
+ """
+ if frozen is True:
+ if slots is True:
+ return (), _setattr, _setattr_with_converter
+
+ # Dict frozen classes assign directly to __dict__.
+ # But only if the attribute doesn't come from an ancestor slot
+ # class.
+ # Note _inst_dict will be used again below if cache_hash is True
+
+ def fmt_setter(
+ attr_name: str, value_var: str, has_on_setattr: bool
+ ) -> str:
+ if _is_slot_attr(attr_name, base_attr_map):
+ return _setattr(attr_name, value_var, has_on_setattr)
+
+ return f"_inst_dict['{attr_name}'] = {value_var}"
+
+ def fmt_setter_with_converter(
+ attr_name: str,
+ value_var: str,
+ has_on_setattr: bool,
+ converter: Converter,
+ ) -> str:
+ if has_on_setattr or _is_slot_attr(attr_name, base_attr_map):
+ return _setattr_with_converter(
+ attr_name, value_var, has_on_setattr, converter
+ )
+
+ return f"_inst_dict['{attr_name}'] = {converter._fmt_converter_call(attr_name, value_var)}"
+
+ return (
+ ("_inst_dict = self.__dict__",),
+ fmt_setter,
+ fmt_setter_with_converter,
+ )
+
+ # Not frozen -- we can just assign directly.
+ return (), _assign, _assign_with_converter
+
+
+def _attrs_to_init_script(
+ attrs: list[Attribute],
+ is_frozen: bool,
+ is_slotted: bool,
+ call_pre_init: bool,
+ pre_init_has_args: bool,
+ call_post_init: bool,
+ does_cache_hash: bool,
+ base_attr_map: dict[str, type],
+ is_exc: bool,
+ needs_cached_setattr: bool,
+ has_cls_on_setattr: bool,
+ method_name: str,
+) -> tuple[str, dict, dict]:
+ """
+ Return a script of an initializer for *attrs*, a dict of globals, and
+ annotations for the initializer.
+
+ The globals are required by the generated script.
+ """
+ lines = ["self.__attrs_pre_init__()"] if call_pre_init else []
+
+ if needs_cached_setattr:
+ lines.append(
+ # Circumvent the __setattr__ descriptor to save one lookup per
+ # assignment. Note _setattr will be used again below if
+ # does_cache_hash is True.
+ "_setattr = _cached_setattr_get(self)"
+ )
+
+ extra_lines, fmt_setter, fmt_setter_with_converter = _determine_setters(
+ is_frozen, is_slotted, base_attr_map
+ )
+ lines.extend(extra_lines)
+
+ args = []
+ kw_only_args = []
+ attrs_to_validate = []
+
+ # This is a dictionary of names to validator and converter callables.
+ # Injecting this into __init__ globals lets us avoid lookups.
+ names_for_globals = {}
+ annotations = {"return": None}
+
+ for a in attrs:
+ if a.validator:
+ attrs_to_validate.append(a)
+
+ attr_name = a.name
+ has_on_setattr = a.on_setattr is not None or (
+ a.on_setattr is not setters.NO_OP and has_cls_on_setattr
+ )
+ # a.alias is set to maybe-mangled attr_name in _ClassBuilder if not
+ # explicitly provided
+ arg_name = a.alias
+
+ has_factory = isinstance(a.default, Factory)
+ maybe_self = "self" if has_factory and a.default.takes_self else ""
+
+ if a.converter and not isinstance(a.converter, Converter):
+ converter = Converter(a.converter)
+ else:
+ converter = a.converter
+
+ if a.init is False:
+ if has_factory:
+ init_factory_name = _INIT_FACTORY_PAT % (a.name,)
+ if converter is not None:
+ lines.append(
+ fmt_setter_with_converter(
+ attr_name,
+ init_factory_name + f"({maybe_self})",
+ has_on_setattr,
+ converter,
+ )
+ )
+ names_for_globals[converter._get_global_name(a.name)] = (
+ converter.converter
+ )
+ else:
+ lines.append(
+ fmt_setter(
+ attr_name,
+ init_factory_name + f"({maybe_self})",
+ has_on_setattr,
+ )
+ )
+ names_for_globals[init_factory_name] = a.default.factory
+ elif converter is not None:
+ lines.append(
+ fmt_setter_with_converter(
+ attr_name,
+ f"attr_dict['{attr_name}'].default",
+ has_on_setattr,
+ converter,
+ )
+ )
+ names_for_globals[converter._get_global_name(a.name)] = (
+ converter.converter
+ )
+ else:
+ lines.append(
+ fmt_setter(
+ attr_name,
+ f"attr_dict['{attr_name}'].default",
+ has_on_setattr,
+ )
+ )
+ elif a.default is not NOTHING and not has_factory:
+ arg = f"{arg_name}=attr_dict['{attr_name}'].default"
+ if a.kw_only:
+ kw_only_args.append(arg)
+ else:
+ args.append(arg)
+
+ if converter is not None:
+ lines.append(
+ fmt_setter_with_converter(
+ attr_name, arg_name, has_on_setattr, converter
+ )
+ )
+ names_for_globals[converter._get_global_name(a.name)] = (
+ converter.converter
+ )
+ else:
+ lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
+
+ elif has_factory:
+ arg = f"{arg_name}=NOTHING"
+ if a.kw_only:
+ kw_only_args.append(arg)
+ else:
+ args.append(arg)
+ lines.append(f"if {arg_name} is not NOTHING:")
+
+ init_factory_name = _INIT_FACTORY_PAT % (a.name,)
+ if converter is not None:
+ lines.append(
+ " "
+ + fmt_setter_with_converter(
+ attr_name, arg_name, has_on_setattr, converter
+ )
+ )
+ lines.append("else:")
+ lines.append(
+ " "
+ + fmt_setter_with_converter(
+ attr_name,
+ init_factory_name + "(" + maybe_self + ")",
+ has_on_setattr,
+ converter,
+ )
+ )
+ names_for_globals[converter._get_global_name(a.name)] = (
+ converter.converter
+ )
+ else:
+ lines.append(
+ " " + fmt_setter(attr_name, arg_name, has_on_setattr)
+ )
+ lines.append("else:")
+ lines.append(
+ " "
+ + fmt_setter(
+ attr_name,
+ init_factory_name + "(" + maybe_self + ")",
+ has_on_setattr,
+ )
+ )
+ names_for_globals[init_factory_name] = a.default.factory
+ else:
+ if a.kw_only:
+ kw_only_args.append(arg_name)
+ else:
+ args.append(arg_name)
+
+ if converter is not None:
+ lines.append(
+ fmt_setter_with_converter(
+ attr_name, arg_name, has_on_setattr, converter
+ )
+ )
+ names_for_globals[converter._get_global_name(a.name)] = (
+ converter.converter
+ )
+ else:
+ lines.append(fmt_setter(attr_name, arg_name, has_on_setattr))
+
+ if a.init is True:
+ if a.type is not None and converter is None:
+ annotations[arg_name] = a.type
+ elif converter is not None and converter._first_param_type:
+ # Use the type from the converter if present.
+ annotations[arg_name] = converter._first_param_type
+
+ if attrs_to_validate: # we can skip this if there are no validators.
+ names_for_globals["_config"] = _config
+ lines.append("if _config._run_validators is True:")
+ for a in attrs_to_validate:
+ val_name = "__attr_validator_" + a.name
+ attr_name = "__attr_" + a.name
+ lines.append(f" {val_name}(self, {attr_name}, self.{a.name})")
+ names_for_globals[val_name] = a.validator
+ names_for_globals[attr_name] = a
+
+ if call_post_init:
+ lines.append("self.__attrs_post_init__()")
+
+ # Because this is set only after __attrs_post_init__ is called, a crash
+ # will result if post-init tries to access the hash code. This seemed
+ # preferable to setting this beforehand, in which case alteration to field
+ # values during post-init combined with post-init accessing the hash code
+ # would result in silent bugs.
+ if does_cache_hash:
+ if is_frozen:
+ if is_slotted:
+ init_hash_cache = f"_setattr('{_HASH_CACHE_FIELD}', None)"
+ else:
+ init_hash_cache = f"_inst_dict['{_HASH_CACHE_FIELD}'] = None"
+ else:
+ init_hash_cache = f"self.{_HASH_CACHE_FIELD} = None"
+ lines.append(init_hash_cache)
+
+ # For exceptions we rely on BaseException.__init__ for proper
+ # initialization.
+ if is_exc:
+ vals = ",".join(f"self.{a.name}" for a in attrs if a.init)
+
+ lines.append(f"BaseException.__init__(self, {vals})")
+
+ args = ", ".join(args)
+ pre_init_args = args
+ if kw_only_args:
+ # leading comma & kw_only args
+ args += f"{', ' if args else ''}*, {', '.join(kw_only_args)}"
+ pre_init_kw_only_args = ", ".join(
+ [
+ f"{kw_arg_name}={kw_arg_name}"
+ # We need to remove the defaults from the kw_only_args.
+ for kw_arg_name in (kwa.split("=")[0] for kwa in kw_only_args)
+ ]
+ )
+ pre_init_args += ", " if pre_init_args else ""
+ pre_init_args += pre_init_kw_only_args
+
+ if call_pre_init and pre_init_has_args:
+ # If pre init method has arguments, pass same arguments as `__init__`.
+ lines[0] = f"self.__attrs_pre_init__({pre_init_args})"
+
+ # Python 3.7 doesn't allow backslashes in f strings.
+ NL = "\n "
+ return (
+ f"""def {method_name}(self, {args}):
+ {NL.join(lines) if lines else 'pass'}
+""",
+ names_for_globals,
+ annotations,
+ )
+
+
+def _default_init_alias_for(name: str) -> str:
+ """
+ The default __init__ parameter name for a field.
+
+ This performs private-name adjustment via leading-unscore stripping,
+ and is the default value of Attribute.alias if not provided.
+ """
+
+ return name.lstrip("_")
+
+
+class Attribute:
+ """
+ *Read-only* representation of an attribute.
+
+ .. warning::
+
+ You should never instantiate this class yourself.
+
+ The class has *all* arguments of `attr.ib` (except for ``factory`` which is
+ only syntactic sugar for ``default=Factory(...)`` plus the following:
+
+ - ``name`` (`str`): The name of the attribute.
+ - ``alias`` (`str`): The __init__ parameter name of the attribute, after
+ any explicit overrides and default private-attribute-name handling.
+ - ``inherited`` (`bool`): Whether or not that attribute has been inherited
+ from a base class.
+ - ``eq_key`` and ``order_key`` (`typing.Callable` or `None`): The
+ callables that are used for comparing and ordering objects by this
+ attribute, respectively. These are set by passing a callable to
+ `attr.ib`'s ``eq``, ``order``, or ``cmp`` arguments. See also
+ :ref:`comparison customization `.
+
+ Instances of this class are frequently used for introspection purposes
+ like:
+
+ - `fields` returns a tuple of them.
+ - Validators get them passed as the first argument.
+ - The :ref:`field transformer ` hook receives a list of
+ them.
+ - The ``alias`` property exposes the __init__ parameter name of the field,
+ with any overrides and default private-attribute handling applied.
+
+
+ .. versionadded:: 20.1.0 *inherited*
+ .. versionadded:: 20.1.0 *on_setattr*
+ .. versionchanged:: 20.2.0 *inherited* is not taken into account for
+ equality checks and hashing anymore.
+ .. versionadded:: 21.1.0 *eq_key* and *order_key*
+ .. versionadded:: 22.2.0 *alias*
+
+ For the full version history of the fields, see `attr.ib`.
+ """
+
+ __slots__ = (
+ "name",
+ "default",
+ "validator",
+ "repr",
+ "eq",
+ "eq_key",
+ "order",
+ "order_key",
+ "hash",
+ "init",
+ "metadata",
+ "type",
+ "converter",
+ "kw_only",
+ "inherited",
+ "on_setattr",
+ "alias",
+ )
+
+ def __init__(
+ self,
+ name,
+ default,
+ validator,
+ repr,
+ cmp, # XXX: unused, remove along with other cmp code.
+ hash,
+ init,
+ inherited,
+ metadata=None,
+ type=None,
+ converter=None,
+ kw_only=False,
+ eq=None,
+ eq_key=None,
+ order=None,
+ order_key=None,
+ on_setattr=None,
+ alias=None,
+ ):
+ eq, eq_key, order, order_key = _determine_attrib_eq_order(
+ cmp, eq_key or eq, order_key or order, True
+ )
+
+ # Cache this descriptor here to speed things up later.
+ bound_setattr = _OBJ_SETATTR.__get__(self)
+
+ # Despite the big red warning, people *do* instantiate `Attribute`
+ # themselves.
+ bound_setattr("name", name)
+ bound_setattr("default", default)
+ bound_setattr("validator", validator)
+ bound_setattr("repr", repr)
+ bound_setattr("eq", eq)
+ bound_setattr("eq_key", eq_key)
+ bound_setattr("order", order)
+ bound_setattr("order_key", order_key)
+ bound_setattr("hash", hash)
+ bound_setattr("init", init)
+ bound_setattr("converter", converter)
+ bound_setattr(
+ "metadata",
+ (
+ types.MappingProxyType(dict(metadata)) # Shallow copy
+ if metadata
+ else _EMPTY_METADATA_SINGLETON
+ ),
+ )
+ bound_setattr("type", type)
+ bound_setattr("kw_only", kw_only)
+ bound_setattr("inherited", inherited)
+ bound_setattr("on_setattr", on_setattr)
+ bound_setattr("alias", alias)
+
+ def __setattr__(self, name, value):
+ raise FrozenInstanceError()
+
+ @classmethod
+ def from_counting_attr(cls, name, ca, type=None):
+ # type holds the annotated value. deal with conflicts:
+ if type is None:
+ type = ca.type
+ elif ca.type is not None:
+ msg = "Type annotation and type argument cannot both be present"
+ raise ValueError(msg)
+ inst_dict = {
+ k: getattr(ca, k)
+ for k in Attribute.__slots__
+ if k
+ not in (
+ "name",
+ "validator",
+ "default",
+ "type",
+ "inherited",
+ ) # exclude methods and deprecated alias
+ }
+ return cls(
+ name=name,
+ validator=ca._validator,
+ default=ca._default,
+ type=type,
+ cmp=None,
+ inherited=False,
+ **inst_dict,
+ )
+
+ # Don't use attrs.evolve since fields(Attribute) doesn't work
+ def evolve(self, **changes):
+ """
+ Copy *self* and apply *changes*.
+
+ This works similarly to `attrs.evolve` but that function does not work
+ with {class}`Attribute`.
+
+ It is mainly meant to be used for `transform-fields`.
+
+ .. versionadded:: 20.3.0
+ """
+ new = copy.copy(self)
+
+ new._setattrs(changes.items())
+
+ return new
+
+ # Don't use _add_pickle since fields(Attribute) doesn't work
+ def __getstate__(self):
+ """
+ Play nice with pickle.
+ """
+ return tuple(
+ getattr(self, name) if name != "metadata" else dict(self.metadata)
+ for name in self.__slots__
+ )
+
+ def __setstate__(self, state):
+ """
+ Play nice with pickle.
+ """
+ self._setattrs(zip(self.__slots__, state))
+
+ def _setattrs(self, name_values_pairs):
+ bound_setattr = _OBJ_SETATTR.__get__(self)
+ for name, value in name_values_pairs:
+ if name != "metadata":
+ bound_setattr(name, value)
+ else:
+ bound_setattr(
+ name,
+ (
+ types.MappingProxyType(dict(value))
+ if value
+ else _EMPTY_METADATA_SINGLETON
+ ),
+ )
+
+
+_a = [
+ Attribute(
+ name=name,
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ eq=True,
+ order=False,
+ hash=(name != "metadata"),
+ init=True,
+ inherited=False,
+ alias=_default_init_alias_for(name),
+ )
+ for name in Attribute.__slots__
+]
+
+Attribute = _add_hash(
+ _add_eq(
+ _add_repr(Attribute, attrs=_a),
+ attrs=[a for a in _a if a.name != "inherited"],
+ ),
+ attrs=[a for a in _a if a.hash and a.name != "inherited"],
+)
+
+
+class _CountingAttr:
+ """
+ Intermediate representation of attributes that uses a counter to preserve
+ the order in which the attributes have been defined.
+
+ *Internal* data structure of the attrs library. Running into is most
+ likely the result of a bug like a forgotten `@attr.s` decorator.
+ """
+
+ __slots__ = (
+ "counter",
+ "_default",
+ "repr",
+ "eq",
+ "eq_key",
+ "order",
+ "order_key",
+ "hash",
+ "init",
+ "metadata",
+ "_validator",
+ "converter",
+ "type",
+ "kw_only",
+ "on_setattr",
+ "alias",
+ )
+ __attrs_attrs__ = (
+ *tuple(
+ Attribute(
+ name=name,
+ alias=_default_init_alias_for(name),
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ hash=True,
+ init=True,
+ kw_only=False,
+ eq=True,
+ eq_key=None,
+ order=False,
+ order_key=None,
+ inherited=False,
+ on_setattr=None,
+ )
+ for name in (
+ "counter",
+ "_default",
+ "repr",
+ "eq",
+ "order",
+ "hash",
+ "init",
+ "on_setattr",
+ "alias",
+ )
+ ),
+ Attribute(
+ name="metadata",
+ alias="metadata",
+ default=None,
+ validator=None,
+ repr=True,
+ cmp=None,
+ hash=False,
+ init=True,
+ kw_only=False,
+ eq=True,
+ eq_key=None,
+ order=False,
+ order_key=None,
+ inherited=False,
+ on_setattr=None,
+ ),
+ )
+ cls_counter = 0
+
+ def __init__(
+ self,
+ default,
+ validator,
+ repr,
+ cmp,
+ hash,
+ init,
+ converter,
+ metadata,
+ type,
+ kw_only,
+ eq,
+ eq_key,
+ order,
+ order_key,
+ on_setattr,
+ alias,
+ ):
+ _CountingAttr.cls_counter += 1
+ self.counter = _CountingAttr.cls_counter
+ self._default = default
+ self._validator = validator
+ self.converter = converter
+ self.repr = repr
+ self.eq = eq
+ self.eq_key = eq_key
+ self.order = order
+ self.order_key = order_key
+ self.hash = hash
+ self.init = init
+ self.metadata = metadata
+ self.type = type
+ self.kw_only = kw_only
+ self.on_setattr = on_setattr
+ self.alias = alias
+
+ def validator(self, meth):
+ """
+ Decorator that adds *meth* to the list of validators.
+
+ Returns *meth* unchanged.
+
+ .. versionadded:: 17.1.0
+ """
+ if self._validator is None:
+ self._validator = meth
+ else:
+ self._validator = and_(self._validator, meth)
+ return meth
+
+ def default(self, meth):
+ """
+ Decorator that allows to set the default for an attribute.
+
+ Returns *meth* unchanged.
+
+ Raises:
+ DefaultAlreadySetError: If default has been set before.
+
+ .. versionadded:: 17.1.0
+ """
+ if self._default is not NOTHING:
+ raise DefaultAlreadySetError()
+
+ self._default = Factory(meth, takes_self=True)
+
+ return meth
+
+
+_CountingAttr = _add_eq(_add_repr(_CountingAttr))
+
+
+class Factory:
+ """
+ Stores a factory callable.
+
+ If passed as the default value to `attrs.field`, the factory is used to
+ generate a new value.
+
+ Args:
+ factory (typing.Callable):
+ A callable that takes either none or exactly one mandatory
+ positional argument depending on *takes_self*.
+
+ takes_self (bool):
+ Pass the partially initialized instance that is being initialized
+ as a positional argument.
+
+ .. versionadded:: 17.1.0 *takes_self*
+ """
+
+ __slots__ = ("factory", "takes_self")
+
+ def __init__(self, factory, takes_self=False):
+ self.factory = factory
+ self.takes_self = takes_self
+
+ def __getstate__(self):
+ """
+ Play nice with pickle.
+ """
+ return tuple(getattr(self, name) for name in self.__slots__)
+
+ def __setstate__(self, state):
+ """
+ Play nice with pickle.
+ """
+ for name, value in zip(self.__slots__, state):
+ setattr(self, name, value)
+
+
+_f = [
+ Attribute(
+ name=name,
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ eq=True,
+ order=False,
+ hash=True,
+ init=True,
+ inherited=False,
+ )
+ for name in Factory.__slots__
+]
+
+Factory = _add_hash(_add_eq(_add_repr(Factory, attrs=_f), attrs=_f), attrs=_f)
+
+
+class Converter:
+ """
+ Stores a converter callable.
+
+ Allows for the wrapped converter to take additional arguments. The
+ arguments are passed in the order they are documented.
+
+ Args:
+ converter (Callable): A callable that converts the passed value.
+
+ takes_self (bool):
+ Pass the partially initialized instance that is being initialized
+ as a positional argument. (default: `False`)
+
+ takes_field (bool):
+ Pass the field definition (an :class:`Attribute`) into the
+ converter as a positional argument. (default: `False`)
+
+ .. versionadded:: 24.1.0
+ """
+
+ __slots__ = (
+ "converter",
+ "takes_self",
+ "takes_field",
+ "_first_param_type",
+ "_global_name",
+ "__call__",
+ )
+
+ def __init__(self, converter, *, takes_self=False, takes_field=False):
+ self.converter = converter
+ self.takes_self = takes_self
+ self.takes_field = takes_field
+
+ ex = _AnnotationExtractor(converter)
+ self._first_param_type = ex.get_first_param_type()
+
+ if not (self.takes_self or self.takes_field):
+ self.__call__ = lambda value, _, __: self.converter(value)
+ elif self.takes_self and not self.takes_field:
+ self.__call__ = lambda value, instance, __: self.converter(
+ value, instance
+ )
+ elif not self.takes_self and self.takes_field:
+ self.__call__ = lambda value, __, field: self.converter(
+ value, field
+ )
+ else:
+ self.__call__ = lambda value, instance, field: self.converter(
+ value, instance, field
+ )
+
+ rt = ex.get_return_type()
+ if rt is not None:
+ self.__call__.__annotations__["return"] = rt
+
+ @staticmethod
+ def _get_global_name(attr_name: str) -> str:
+ """
+ Return the name that a converter for an attribute name *attr_name*
+ would have.
+ """
+ return f"__attr_converter_{attr_name}"
+
+ def _fmt_converter_call(self, attr_name: str, value_var: str) -> str:
+ """
+ Return a string that calls the converter for an attribute name
+ *attr_name* and the value in variable named *value_var* according to
+ `self.takes_self` and `self.takes_field`.
+ """
+ if not (self.takes_self or self.takes_field):
+ return f"{self._get_global_name(attr_name)}({value_var})"
+
+ if self.takes_self and self.takes_field:
+ return f"{self._get_global_name(attr_name)}({value_var}, self, attr_dict['{attr_name}'])"
+
+ if self.takes_self:
+ return f"{self._get_global_name(attr_name)}({value_var}, self)"
+
+ return f"{self._get_global_name(attr_name)}({value_var}, attr_dict['{attr_name}'])"
+
+ def __getstate__(self):
+ """
+ Return a dict containing only converter and takes_self -- the rest gets
+ computed when loading.
+ """
+ return {
+ "converter": self.converter,
+ "takes_self": self.takes_self,
+ "takes_field": self.takes_field,
+ }
+
+ def __setstate__(self, state):
+ """
+ Load instance from state.
+ """
+ self.__init__(**state)
+
+
+_f = [
+ Attribute(
+ name=name,
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ cmp=None,
+ eq=True,
+ order=False,
+ hash=True,
+ init=True,
+ inherited=False,
+ )
+ for name in ("converter", "takes_self", "takes_field")
+]
+
+Converter = _add_hash(
+ _add_eq(_add_repr(Converter, attrs=_f), attrs=_f), attrs=_f
+)
+
+
+def make_class(
+ name, attrs, bases=(object,), class_body=None, **attributes_arguments
+):
+ r"""
+ A quick way to create a new class called *name* with *attrs*.
+
+ Args:
+ name (str): The name for the new class.
+
+ attrs( list | dict):
+ A list of names or a dictionary of mappings of names to `attr.ib`\
+ s / `attrs.field`\ s.
+
+ The order is deduced from the order of the names or attributes
+ inside *attrs*. Otherwise the order of the definition of the
+ attributes is used.
+
+ bases (tuple[type, ...]): Classes that the new class will subclass.
+
+ class_body (dict):
+ An optional dictionary of class attributes for the new class.
+
+ attributes_arguments: Passed unmodified to `attr.s`.
+
+ Returns:
+ type: A new class with *attrs*.
+
+ .. versionadded:: 17.1.0 *bases*
+ .. versionchanged:: 18.1.0 If *attrs* is ordered, the order is retained.
+ .. versionchanged:: 23.2.0 *class_body*
+ """
+ if isinstance(attrs, dict):
+ cls_dict = attrs
+ elif isinstance(attrs, (list, tuple)):
+ cls_dict = {a: attrib() for a in attrs}
+ else:
+ msg = "attrs argument must be a dict or a list."
+ raise TypeError(msg)
+
+ pre_init = cls_dict.pop("__attrs_pre_init__", None)
+ post_init = cls_dict.pop("__attrs_post_init__", None)
+ user_init = cls_dict.pop("__init__", None)
+
+ body = {}
+ if class_body is not None:
+ body.update(class_body)
+ if pre_init is not None:
+ body["__attrs_pre_init__"] = pre_init
+ if post_init is not None:
+ body["__attrs_post_init__"] = post_init
+ if user_init is not None:
+ body["__init__"] = user_init
+
+ type_ = types.new_class(name, bases, {}, lambda ns: ns.update(body))
+
+ # For pickling to work, the __module__ variable needs to be set to the
+ # frame where the class is created. Bypass this step in environments where
+ # sys._getframe is not defined (Jython for example) or sys._getframe is not
+ # defined for arguments greater than 0 (IronPython).
+ with contextlib.suppress(AttributeError, ValueError):
+ type_.__module__ = sys._getframe(1).f_globals.get(
+ "__name__", "__main__"
+ )
+
+ # We do it here for proper warnings with meaningful stacklevel.
+ cmp = attributes_arguments.pop("cmp", None)
+ (
+ attributes_arguments["eq"],
+ attributes_arguments["order"],
+ ) = _determine_attrs_eq_order(
+ cmp,
+ attributes_arguments.get("eq"),
+ attributes_arguments.get("order"),
+ True,
+ )
+
+ cls = _attrs(these=cls_dict, **attributes_arguments)(type_)
+ # Only add type annotations now or "_attrs()" will complain:
+ cls.__annotations__ = {
+ k: v.type for k, v in cls_dict.items() if v.type is not None
+ }
+ return cls
+
+
+# These are required by within this module so we define them here and merely
+# import into .validators / .converters.
+
+
+@attrs(slots=True, unsafe_hash=True)
+class _AndValidator:
+ """
+ Compose many validators to a single one.
+ """
+
+ _validators = attrib()
+
+ def __call__(self, inst, attr, value):
+ for v in self._validators:
+ v(inst, attr, value)
+
+
+def and_(*validators):
+ """
+ A validator that composes multiple validators into one.
+
+ When called on a value, it runs all wrapped validators.
+
+ Args:
+ validators (~collections.abc.Iterable[typing.Callable]):
+ Arbitrary number of validators.
+
+ .. versionadded:: 17.1.0
+ """
+ vals = []
+ for validator in validators:
+ vals.extend(
+ validator._validators
+ if isinstance(validator, _AndValidator)
+ else [validator]
+ )
+
+ return _AndValidator(tuple(vals))
+
+
+def pipe(*converters):
+ """
+ A converter that composes multiple converters into one.
+
+ When called on a value, it runs all wrapped converters, returning the
+ *last* value.
+
+ Type annotations will be inferred from the wrapped converters', if they
+ have any.
+
+ converters (~collections.abc.Iterable[typing.Callable]):
+ Arbitrary number of converters.
+
+ .. versionadded:: 20.1.0
+ """
+
+ def pipe_converter(val, inst, field):
+ for c in converters:
+ val = c(val, inst, field) if isinstance(c, Converter) else c(val)
+
+ return val
+
+ if not converters:
+ # If the converter list is empty, pipe_converter is the identity.
+ A = typing.TypeVar("A")
+ pipe_converter.__annotations__.update({"val": A, "return": A})
+ else:
+ # Get parameter type from first converter.
+ t = _AnnotationExtractor(converters[0]).get_first_param_type()
+ if t:
+ pipe_converter.__annotations__["val"] = t
+
+ last = converters[-1]
+ if not PY_3_11_PLUS and isinstance(last, Converter):
+ last = last.__call__
+
+ # Get return type from last converter.
+ rt = _AnnotationExtractor(last).get_return_type()
+ if rt:
+ pipe_converter.__annotations__["return"] = rt
+
+ return Converter(pipe_converter, takes_self=True, takes_field=True)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_next_gen.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_next_gen.py
new file mode 100644
index 0000000..dbb65cc
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_next_gen.py
@@ -0,0 +1,631 @@
+# SPDX-License-Identifier: MIT
+
+"""
+These are keyword-only APIs that call `attr.s` and `attr.ib` with different
+default values.
+"""
+
+
+from functools import partial
+
+from . import setters
+from ._funcs import asdict as _asdict
+from ._funcs import astuple as _astuple
+from ._make import (
+ _DEFAULT_ON_SETATTR,
+ NOTHING,
+ _frozen_setattrs,
+ attrib,
+ attrs,
+)
+from .exceptions import UnannotatedAttributeError
+
+
+def define(
+ maybe_cls=None,
+ *,
+ these=None,
+ repr=None,
+ unsafe_hash=None,
+ hash=None,
+ init=None,
+ slots=True,
+ frozen=False,
+ weakref_slot=True,
+ str=False,
+ auto_attribs=None,
+ kw_only=False,
+ cache_hash=False,
+ auto_exc=True,
+ eq=None,
+ order=False,
+ auto_detect=True,
+ getstate_setstate=None,
+ on_setattr=None,
+ field_transformer=None,
+ match_args=True,
+):
+ r"""
+ A class decorator that adds :term:`dunder methods` according to
+ :term:`fields ` specified using :doc:`type annotations `,
+ `field()` calls, or the *these* argument.
+
+ Since *attrs* patches or replaces an existing class, you cannot use
+ `object.__init_subclass__` with *attrs* classes, because it runs too early.
+ As a replacement, you can define ``__attrs_init_subclass__`` on your class.
+ It will be called by *attrs* classes that subclass it after they're
+ created. See also :ref:`init-subclass`.
+
+ Args:
+ slots (bool):
+ Create a :term:`slotted class ` that's more
+ memory-efficient. Slotted classes are generally superior to the
+ default dict classes, but have some gotchas you should know about,
+ so we encourage you to read the :term:`glossary entry `.
+
+ auto_detect (bool):
+ Instead of setting the *init*, *repr*, *eq*, and *hash* arguments
+ explicitly, assume they are set to True **unless any** of the
+ involved methods for one of the arguments is implemented in the
+ *current* class (meaning, it is *not* inherited from some base
+ class).
+
+ So, for example by implementing ``__eq__`` on a class yourself,
+ *attrs* will deduce ``eq=False`` and will create *neither*
+ ``__eq__`` *nor* ``__ne__`` (but Python classes come with a
+ sensible ``__ne__`` by default, so it *should* be enough to only
+ implement ``__eq__`` in most cases).
+
+ Passing True or False` to *init*, *repr*, *eq*, *cmp*, or *hash*
+ overrides whatever *auto_detect* would determine.
+
+ auto_exc (bool):
+ If the class subclasses `BaseException` (which implicitly includes
+ any subclass of any exception), the following happens to behave
+ like a well-behaved Python exception class:
+
+ - the values for *eq*, *order*, and *hash* are ignored and the
+ instances compare and hash by the instance's ids [#]_ ,
+ - all attributes that are either passed into ``__init__`` or have a
+ default value are additionally available as a tuple in the
+ ``args`` attribute,
+ - the value of *str* is ignored leaving ``__str__`` to base
+ classes.
+
+ .. [#]
+ Note that *attrs* will *not* remove existing implementations of
+ ``__hash__`` or the equality methods. It just won't add own
+ ones.
+
+ on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]):
+ A callable that is run whenever the user attempts to set an
+ attribute (either by assignment like ``i.x = 42`` or by using
+ `setattr` like ``setattr(i, "x", 42)``). It receives the same
+ arguments as validators: the instance, the attribute that is being
+ modified, and the new value.
+
+ If no exception is raised, the attribute is set to the return value
+ of the callable.
+
+ If a list of callables is passed, they're automatically wrapped in
+ an `attrs.setters.pipe`.
+
+ If left None, the default behavior is to run converters and
+ validators whenever an attribute is set.
+
+ init (bool):
+ Create a ``__init__`` method that initializes the *attrs*
+ attributes. Leading underscores are stripped for the argument name,
+ unless an alias is set on the attribute.
+
+ .. seealso::
+ `init` shows advanced ways to customize the generated
+ ``__init__`` method, including executing code before and after.
+
+ repr(bool):
+ Create a ``__repr__`` method with a human readable representation
+ of *attrs* attributes.
+
+ str (bool):
+ Create a ``__str__`` method that is identical to ``__repr__``. This
+ is usually not necessary except for `Exception`\ s.
+
+ eq (bool | None):
+ If True or None (default), add ``__eq__`` and ``__ne__`` methods
+ that check two instances for equality.
+
+ .. seealso::
+ `comparison` describes how to customize the comparison behavior
+ going as far comparing NumPy arrays.
+
+ order (bool | None):
+ If True, add ``__lt__``, ``__le__``, ``__gt__``, and ``__ge__``
+ methods that behave like *eq* above and allow instances to be
+ ordered.
+
+ They compare the instances as if they were tuples of their *attrs*
+ attributes if and only if the types of both classes are
+ *identical*.
+
+ If `None` mirror value of *eq*.
+
+ .. seealso:: `comparison`
+
+ cmp (bool | None):
+ Setting *cmp* is equivalent to setting *eq* and *order* to the same
+ value. Must not be mixed with *eq* or *order*.
+
+ unsafe_hash (bool | None):
+ If None (default), the ``__hash__`` method is generated according
+ how *eq* and *frozen* are set.
+
+ 1. If *both* are True, *attrs* will generate a ``__hash__`` for
+ you.
+ 2. If *eq* is True and *frozen* is False, ``__hash__`` will be set
+ to None, marking it unhashable (which it is).
+ 3. If *eq* is False, ``__hash__`` will be left untouched meaning
+ the ``__hash__`` method of the base class will be used. If the
+ base class is `object`, this means it will fall back to id-based
+ hashing.
+
+ Although not recommended, you can decide for yourself and force
+ *attrs* to create one (for example, if the class is immutable even
+ though you didn't freeze it programmatically) by passing True or
+ not. Both of these cases are rather special and should be used
+ carefully.
+
+ .. seealso::
+
+ - Our documentation on `hashing`,
+ - Python's documentation on `object.__hash__`,
+ - and the `GitHub issue that led to the default \ behavior
+ `_ for more
+ details.
+
+ hash (bool | None):
+ Deprecated alias for *unsafe_hash*. *unsafe_hash* takes precedence.
+
+ cache_hash (bool):
+ Ensure that the object's hash code is computed only once and stored
+ on the object. If this is set to True, hashing must be either
+ explicitly or implicitly enabled for this class. If the hash code
+ is cached, avoid any reassignments of fields involved in hash code
+ computation or mutations of the objects those fields point to after
+ object creation. If such changes occur, the behavior of the
+ object's hash code is undefined.
+
+ frozen (bool):
+ Make instances immutable after initialization. If someone attempts
+ to modify a frozen instance, `attrs.exceptions.FrozenInstanceError`
+ is raised.
+
+ .. note::
+
+ 1. This is achieved by installing a custom ``__setattr__``
+ method on your class, so you can't implement your own.
+
+ 2. True immutability is impossible in Python.
+
+ 3. This *does* have a minor a runtime performance `impact
+ ` when initializing new instances. In other
+ words: ``__init__`` is slightly slower with ``frozen=True``.
+
+ 4. If a class is frozen, you cannot modify ``self`` in
+ ``__attrs_post_init__`` or a self-written ``__init__``. You
+ can circumvent that limitation by using
+ ``object.__setattr__(self, "attribute_name", value)``.
+
+ 5. Subclasses of a frozen class are frozen too.
+
+ kw_only (bool):
+ Make all attributes keyword-only in the generated ``__init__`` (if
+ *init* is False, this parameter is ignored).
+
+ weakref_slot (bool):
+ Make instances weak-referenceable. This has no effect unless
+ *slots* is True.
+
+ field_transformer (~typing.Callable | None):
+ A function that is called with the original class object and all
+ fields right before *attrs* finalizes the class. You can use this,
+ for example, to automatically add converters or validators to
+ fields based on their types.
+
+ .. seealso:: `transform-fields`
+
+ match_args (bool):
+ If True (default), set ``__match_args__`` on the class to support
+ :pep:`634` (*Structural Pattern Matching*). It is a tuple of all
+ non-keyword-only ``__init__`` parameter names on Python 3.10 and
+ later. Ignored on older Python versions.
+
+ collect_by_mro (bool):
+ If True, *attrs* collects attributes from base classes correctly
+ according to the `method resolution order
+ `_. If False, *attrs*
+ will mimic the (wrong) behavior of `dataclasses` and :pep:`681`.
+
+ See also `issue #428
+ `_.
+
+ getstate_setstate (bool | None):
+ .. note::
+
+ This is usually only interesting for slotted classes and you
+ should probably just set *auto_detect* to True.
+
+ If True, ``__getstate__`` and ``__setstate__`` are generated and
+ attached to the class. This is necessary for slotted classes to be
+ pickleable. If left None, it's True by default for slotted classes
+ and False for dict classes.
+
+ If *auto_detect* is True, and *getstate_setstate* is left None, and
+ **either** ``__getstate__`` or ``__setstate__`` is detected
+ directly on the class (meaning: not inherited), it is set to False
+ (this is usually what you want).
+
+ auto_attribs (bool | None):
+ If True, look at type annotations to determine which attributes to
+ use, like `dataclasses`. If False, it will only look for explicit
+ :func:`field` class attributes, like classic *attrs*.
+
+ If left None, it will guess:
+
+ 1. If any attributes are annotated and no unannotated
+ `attrs.field`\ s are found, it assumes *auto_attribs=True*.
+ 2. Otherwise it assumes *auto_attribs=False* and tries to collect
+ `attrs.field`\ s.
+
+ If *attrs* decides to look at type annotations, **all** fields
+ **must** be annotated. If *attrs* encounters a field that is set to
+ a :func:`field` / `attr.ib` but lacks a type annotation, an
+ `attrs.exceptions.UnannotatedAttributeError` is raised. Use
+ ``field_name: typing.Any = field(...)`` if you don't want to set a
+ type.
+
+ .. warning::
+
+ For features that use the attribute name to create decorators
+ (for example, :ref:`validators `), you still *must*
+ assign :func:`field` / `attr.ib` to them. Otherwise Python will
+ either not find the name or try to use the default value to
+ call, for example, ``validator`` on it.
+
+ Attributes annotated as `typing.ClassVar`, and attributes that are
+ neither annotated nor set to an `field()` are **ignored**.
+
+ these (dict[str, object]):
+ A dictionary of name to the (private) return value of `field()`
+ mappings. This is useful to avoid the definition of your attributes
+ within the class body because you can't (for example, if you want
+ to add ``__repr__`` methods to Django models) or don't want to.
+
+ If *these* is not `None`, *attrs* will *not* search the class body
+ for attributes and will *not* remove any attributes from it.
+
+ The order is deduced from the order of the attributes inside
+ *these*.
+
+ Arguably, this is a rather obscure feature.
+
+ .. versionadded:: 20.1.0
+ .. versionchanged:: 21.3.0 Converters are also run ``on_setattr``.
+ .. versionadded:: 22.2.0
+ *unsafe_hash* as an alias for *hash* (for :pep:`681` compliance).
+ .. versionchanged:: 24.1.0
+ Instances are not compared as tuples of attributes anymore, but using a
+ big ``and`` condition. This is faster and has more correct behavior for
+ uncomparable values like `math.nan`.
+ .. versionadded:: 24.1.0
+ If a class has an *inherited* classmethod called
+ ``__attrs_init_subclass__``, it is executed after the class is created.
+ .. deprecated:: 24.1.0 *hash* is deprecated in favor of *unsafe_hash*.
+
+ .. note::
+
+ The main differences to the classic `attr.s` are:
+
+ - Automatically detect whether or not *auto_attribs* should be `True`
+ (c.f. *auto_attribs* parameter).
+ - Converters and validators run when attributes are set by default --
+ if *frozen* is `False`.
+ - *slots=True*
+
+ Usually, this has only upsides and few visible effects in everyday
+ programming. But it *can* lead to some surprising behaviors, so
+ please make sure to read :term:`slotted classes`.
+
+ - *auto_exc=True*
+ - *auto_detect=True*
+ - *order=False*
+ - Some options that were only relevant on Python 2 or were kept around
+ for backwards-compatibility have been removed.
+
+ """
+
+ def do_it(cls, auto_attribs):
+ return attrs(
+ maybe_cls=cls,
+ these=these,
+ repr=repr,
+ hash=hash,
+ unsafe_hash=unsafe_hash,
+ init=init,
+ slots=slots,
+ frozen=frozen,
+ weakref_slot=weakref_slot,
+ str=str,
+ auto_attribs=auto_attribs,
+ kw_only=kw_only,
+ cache_hash=cache_hash,
+ auto_exc=auto_exc,
+ eq=eq,
+ order=order,
+ auto_detect=auto_detect,
+ collect_by_mro=True,
+ getstate_setstate=getstate_setstate,
+ on_setattr=on_setattr,
+ field_transformer=field_transformer,
+ match_args=match_args,
+ )
+
+ def wrap(cls):
+ """
+ Making this a wrapper ensures this code runs during class creation.
+
+ We also ensure that frozen-ness of classes is inherited.
+ """
+ nonlocal frozen, on_setattr
+
+ had_on_setattr = on_setattr not in (None, setters.NO_OP)
+
+ # By default, mutable classes convert & validate on setattr.
+ if frozen is False and on_setattr is None:
+ on_setattr = _DEFAULT_ON_SETATTR
+
+ # However, if we subclass a frozen class, we inherit the immutability
+ # and disable on_setattr.
+ for base_cls in cls.__bases__:
+ if base_cls.__setattr__ is _frozen_setattrs:
+ if had_on_setattr:
+ msg = "Frozen classes can't use on_setattr (frozen-ness was inherited)."
+ raise ValueError(msg)
+
+ on_setattr = setters.NO_OP
+ break
+
+ if auto_attribs is not None:
+ return do_it(cls, auto_attribs)
+
+ try:
+ return do_it(cls, True)
+ except UnannotatedAttributeError:
+ return do_it(cls, False)
+
+ # maybe_cls's type depends on the usage of the decorator. It's a class
+ # if it's used as `@attrs` but `None` if used as `@attrs()`.
+ if maybe_cls is None:
+ return wrap
+
+ return wrap(maybe_cls)
+
+
+mutable = define
+frozen = partial(define, frozen=True, on_setattr=None)
+
+
+def field(
+ *,
+ default=NOTHING,
+ validator=None,
+ repr=True,
+ hash=None,
+ init=True,
+ metadata=None,
+ type=None,
+ converter=None,
+ factory=None,
+ kw_only=False,
+ eq=None,
+ order=None,
+ on_setattr=None,
+ alias=None,
+):
+ """
+ Create a new :term:`field` / :term:`attribute` on a class.
+
+ .. warning::
+
+ Does **nothing** unless the class is also decorated with
+ `attrs.define` (or similar)!
+
+ Args:
+ default:
+ A value that is used if an *attrs*-generated ``__init__`` is used
+ and no value is passed while instantiating or the attribute is
+ excluded using ``init=False``.
+
+ If the value is an instance of `attrs.Factory`, its callable will
+ be used to construct a new value (useful for mutable data types
+ like lists or dicts).
+
+ If a default is not set (or set manually to `attrs.NOTHING`), a
+ value *must* be supplied when instantiating; otherwise a
+ `TypeError` will be raised.
+
+ .. seealso:: `defaults`
+
+ factory (~typing.Callable):
+ Syntactic sugar for ``default=attr.Factory(factory)``.
+
+ validator (~typing.Callable | list[~typing.Callable]):
+ Callable that is called by *attrs*-generated ``__init__`` methods
+ after the instance has been initialized. They receive the
+ initialized instance, the :func:`~attrs.Attribute`, and the passed
+ value.
+
+ The return value is *not* inspected so the validator has to throw
+ an exception itself.
+
+ If a `list` is passed, its items are treated as validators and must
+ all pass.
+
+ Validators can be globally disabled and re-enabled using
+ `attrs.validators.get_disabled` / `attrs.validators.set_disabled`.
+
+ The validator can also be set using decorator notation as shown
+ below.
+
+ .. seealso:: :ref:`validators`
+
+ repr (bool | ~typing.Callable):
+ Include this attribute in the generated ``__repr__`` method. If
+ True, include the attribute; if False, omit it. By default, the
+ built-in ``repr()`` function is used. To override how the attribute
+ value is formatted, pass a ``callable`` that takes a single value
+ and returns a string. Note that the resulting string is used as-is,
+ which means it will be used directly *instead* of calling
+ ``repr()`` (the default).
+
+ eq (bool | ~typing.Callable):
+ If True (default), include this attribute in the generated
+ ``__eq__`` and ``__ne__`` methods that check two instances for
+ equality. To override how the attribute value is compared, pass a
+ callable that takes a single value and returns the value to be
+ compared.
+
+ .. seealso:: `comparison`
+
+ order (bool | ~typing.Callable):
+ If True (default), include this attributes in the generated
+ ``__lt__``, ``__le__``, ``__gt__`` and ``__ge__`` methods. To
+ override how the attribute value is ordered, pass a callable that
+ takes a single value and returns the value to be ordered.
+
+ .. seealso:: `comparison`
+
+ cmp(bool | ~typing.Callable):
+ Setting *cmp* is equivalent to setting *eq* and *order* to the same
+ value. Must not be mixed with *eq* or *order*.
+
+ .. seealso:: `comparison`
+
+ hash (bool | None):
+ Include this attribute in the generated ``__hash__`` method. If
+ None (default), mirror *eq*'s value. This is the correct behavior
+ according the Python spec. Setting this value to anything else
+ than None is *discouraged*.
+
+ .. seealso:: `hashing`
+
+ init (bool):
+ Include this attribute in the generated ``__init__`` method.
+
+ It is possible to set this to False and set a default value. In
+ that case this attributed is unconditionally initialized with the
+ specified default value or factory.
+
+ .. seealso:: `init`
+
+ converter (typing.Callable | Converter):
+ A callable that is called by *attrs*-generated ``__init__`` methods
+ to convert attribute's value to the desired format.
+
+ If a vanilla callable is passed, it is given the passed-in value as
+ the only positional argument. It is possible to receive additional
+ arguments by wrapping the callable in a `Converter`.
+
+ Either way, the returned value will be used as the new value of the
+ attribute. The value is converted before being passed to the
+ validator, if any.
+
+ .. seealso:: :ref:`converters`
+
+ metadata (dict | None):
+ An arbitrary mapping, to be used by third-party code.
+
+ .. seealso:: `extending-metadata`.
+
+ type (type):
+ The type of the attribute. Nowadays, the preferred method to
+ specify the type is using a variable annotation (see :pep:`526`).
+ This argument is provided for backwards-compatibility and for usage
+ with `make_class`. Regardless of the approach used, the type will
+ be stored on ``Attribute.type``.
+
+ Please note that *attrs* doesn't do anything with this metadata by
+ itself. You can use it as part of your own code or for `static type
+ checking `.
+
+ kw_only (bool):
+ Make this attribute keyword-only in the generated ``__init__`` (if
+ ``init`` is False, this parameter is ignored).
+
+ on_setattr (~typing.Callable | list[~typing.Callable] | None | ~typing.Literal[attrs.setters.NO_OP]):
+ Allows to overwrite the *on_setattr* setting from `attr.s`. If left
+ None, the *on_setattr* value from `attr.s` is used. Set to
+ `attrs.setters.NO_OP` to run **no** `setattr` hooks for this
+ attribute -- regardless of the setting in `define()`.
+
+ alias (str | None):
+ Override this attribute's parameter name in the generated
+ ``__init__`` method. If left None, default to ``name`` stripped
+ of leading underscores. See `private-attributes`.
+
+ .. versionadded:: 20.1.0
+ .. versionchanged:: 21.1.0
+ *eq*, *order*, and *cmp* also accept a custom callable
+ .. versionadded:: 22.2.0 *alias*
+ .. versionadded:: 23.1.0
+ The *type* parameter has been re-added; mostly for `attrs.make_class`.
+ Please note that type checkers ignore this metadata.
+
+ .. seealso::
+
+ `attr.ib`
+ """
+ return attrib(
+ default=default,
+ validator=validator,
+ repr=repr,
+ hash=hash,
+ init=init,
+ metadata=metadata,
+ type=type,
+ converter=converter,
+ factory=factory,
+ kw_only=kw_only,
+ eq=eq,
+ order=order,
+ on_setattr=on_setattr,
+ alias=alias,
+ )
+
+
+def asdict(inst, *, recurse=True, filter=None, value_serializer=None):
+ """
+ Same as `attr.asdict`, except that collections types are always retained
+ and dict is always used as *dict_factory*.
+
+ .. versionadded:: 21.3.0
+ """
+ return _asdict(
+ inst=inst,
+ recurse=recurse,
+ filter=filter,
+ value_serializer=value_serializer,
+ retain_collection_types=True,
+ )
+
+
+def astuple(inst, *, recurse=True, filter=None):
+ """
+ Same as `attr.astuple`, except that collections types are always retained
+ and `tuple` is always used as the *tuple_factory*.
+
+ .. versionadded:: 21.3.0
+ """
+ return _astuple(
+ inst=inst, recurse=recurse, filter=filter, retain_collection_types=True
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_typing_compat.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/_typing_compat.pyi
new file mode 100644
index 0000000..ca7b71e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_typing_compat.pyi
@@ -0,0 +1,15 @@
+from typing import Any, ClassVar, Protocol
+
+# MYPY is a special constant in mypy which works the same way as `TYPE_CHECKING`.
+MYPY = False
+
+if MYPY:
+ # A protocol to be able to statically accept an attrs class.
+ class AttrsInstance_(Protocol):
+ __attrs_attrs__: ClassVar[Any]
+
+else:
+ # For type checkers without plug-in support use an empty protocol that
+ # will (hopefully) be combined into a union.
+ class AttrsInstance_(Protocol):
+ pass
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.py b/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.py
new file mode 100644
index 0000000..51a1312
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.py
@@ -0,0 +1,86 @@
+# SPDX-License-Identifier: MIT
+
+
+from functools import total_ordering
+
+from ._funcs import astuple
+from ._make import attrib, attrs
+
+
+@total_ordering
+@attrs(eq=False, order=False, slots=True, frozen=True)
+class VersionInfo:
+ """
+ A version object that can be compared to tuple of length 1--4:
+
+ >>> attr.VersionInfo(19, 1, 0, "final") <= (19, 2)
+ True
+ >>> attr.VersionInfo(19, 1, 0, "final") < (19, 1, 1)
+ True
+ >>> vi = attr.VersionInfo(19, 2, 0, "final")
+ >>> vi < (19, 1, 1)
+ False
+ >>> vi < (19,)
+ False
+ >>> vi == (19, 2,)
+ True
+ >>> vi == (19, 2, 1)
+ False
+
+ .. versionadded:: 19.2
+ """
+
+ year = attrib(type=int)
+ minor = attrib(type=int)
+ micro = attrib(type=int)
+ releaselevel = attrib(type=str)
+
+ @classmethod
+ def _from_version_string(cls, s):
+ """
+ Parse *s* and return a _VersionInfo.
+ """
+ v = s.split(".")
+ if len(v) == 3:
+ v.append("final")
+
+ return cls(
+ year=int(v[0]), minor=int(v[1]), micro=int(v[2]), releaselevel=v[3]
+ )
+
+ def _ensure_tuple(self, other):
+ """
+ Ensure *other* is a tuple of a valid length.
+
+ Returns a possibly transformed *other* and ourselves as a tuple of
+ the same length as *other*.
+ """
+
+ if self.__class__ is other.__class__:
+ other = astuple(other)
+
+ if not isinstance(other, tuple):
+ raise NotImplementedError
+
+ if not (1 <= len(other) <= 4):
+ raise NotImplementedError
+
+ return astuple(self)[: len(other)], other
+
+ def __eq__(self, other):
+ try:
+ us, them = self._ensure_tuple(other)
+ except NotImplementedError:
+ return NotImplemented
+
+ return us == them
+
+ def __lt__(self, other):
+ try:
+ us, them = self._ensure_tuple(other)
+ except NotImplementedError:
+ return NotImplemented
+
+ # Since alphabetically "dev0" < "final" < "post1" < "post2", we don't
+ # have to do anything special with releaselevel for now.
+ return us < them
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.pyi
new file mode 100644
index 0000000..45ced08
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/_version_info.pyi
@@ -0,0 +1,9 @@
+class VersionInfo:
+ @property
+ def year(self) -> int: ...
+ @property
+ def minor(self) -> int: ...
+ @property
+ def micro(self) -> int: ...
+ @property
+ def releaselevel(self) -> str: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/converters.py b/lambdas/aws-dd-forwarder-3.127.0/attr/converters.py
new file mode 100644
index 0000000..9238311
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/converters.py
@@ -0,0 +1,151 @@
+# SPDX-License-Identifier: MIT
+
+"""
+Commonly useful converters.
+"""
+
+
+import typing
+
+from ._compat import _AnnotationExtractor
+from ._make import NOTHING, Factory, pipe
+
+
+__all__ = [
+ "default_if_none",
+ "optional",
+ "pipe",
+ "to_bool",
+]
+
+
+def optional(converter):
+ """
+ A converter that allows an attribute to be optional. An optional attribute
+ is one which can be set to `None`.
+
+ Type annotations will be inferred from the wrapped converter's, if it has
+ any.
+
+ Args:
+ converter (typing.Callable):
+ the converter that is used for non-`None` values.
+
+ .. versionadded:: 17.1.0
+ """
+
+ def optional_converter(val):
+ if val is None:
+ return None
+ return converter(val)
+
+ xtr = _AnnotationExtractor(converter)
+
+ t = xtr.get_first_param_type()
+ if t:
+ optional_converter.__annotations__["val"] = typing.Optional[t]
+
+ rt = xtr.get_return_type()
+ if rt:
+ optional_converter.__annotations__["return"] = typing.Optional[rt]
+
+ return optional_converter
+
+
+def default_if_none(default=NOTHING, factory=None):
+ """
+ A converter that allows to replace `None` values by *default* or the result
+ of *factory*.
+
+ Args:
+ default:
+ Value to be used if `None` is passed. Passing an instance of
+ `attrs.Factory` is supported, however the ``takes_self`` option is
+ *not*.
+
+ factory (typing.Callable):
+ A callable that takes no parameters whose result is used if `None`
+ is passed.
+
+ Raises:
+ TypeError: If **neither** *default* or *factory* is passed.
+
+ TypeError: If **both** *default* and *factory* are passed.
+
+ ValueError:
+ If an instance of `attrs.Factory` is passed with
+ ``takes_self=True``.
+
+ .. versionadded:: 18.2.0
+ """
+ if default is NOTHING and factory is None:
+ msg = "Must pass either `default` or `factory`."
+ raise TypeError(msg)
+
+ if default is not NOTHING and factory is not None:
+ msg = "Must pass either `default` or `factory` but not both."
+ raise TypeError(msg)
+
+ if factory is not None:
+ default = Factory(factory)
+
+ if isinstance(default, Factory):
+ if default.takes_self:
+ msg = "`takes_self` is not supported by default_if_none."
+ raise ValueError(msg)
+
+ def default_if_none_converter(val):
+ if val is not None:
+ return val
+
+ return default.factory()
+
+ else:
+
+ def default_if_none_converter(val):
+ if val is not None:
+ return val
+
+ return default
+
+ return default_if_none_converter
+
+
+def to_bool(val):
+ """
+ Convert "boolean" strings (for example, from environment variables) to real
+ booleans.
+
+ Values mapping to `True`:
+
+ - ``True``
+ - ``"true"`` / ``"t"``
+ - ``"yes"`` / ``"y"``
+ - ``"on"``
+ - ``"1"``
+ - ``1``
+
+ Values mapping to `False`:
+
+ - ``False``
+ - ``"false"`` / ``"f"``
+ - ``"no"`` / ``"n"``
+ - ``"off"``
+ - ``"0"``
+ - ``0``
+
+ Raises:
+ ValueError: For any other value.
+
+ .. versionadded:: 21.3.0
+ """
+ if isinstance(val, str):
+ val = val.lower()
+
+ if val in (True, "true", "t", "yes", "y", "on", "1", 1):
+ return True
+ if val in (False, "false", "f", "no", "n", "off", "0", 0):
+ return False
+
+ msg = f"Cannot convert value to bool: {val!r}"
+ raise ValueError(msg)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/converters.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/converters.pyi
new file mode 100644
index 0000000..9ef478f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/converters.pyi
@@ -0,0 +1,13 @@
+from typing import Callable, TypeVar, overload
+
+from attrs import _ConverterType
+
+_T = TypeVar("_T")
+
+def pipe(*validators: _ConverterType) -> _ConverterType: ...
+def optional(converter: _ConverterType) -> _ConverterType: ...
+@overload
+def default_if_none(default: _T) -> _ConverterType: ...
+@overload
+def default_if_none(*, factory: Callable[[], _T]) -> _ConverterType: ...
+def to_bool(val: str) -> bool: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.py b/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.py
new file mode 100644
index 0000000..3b7abb8
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.py
@@ -0,0 +1,95 @@
+# SPDX-License-Identifier: MIT
+
+from __future__ import annotations
+
+from typing import ClassVar
+
+
+class FrozenError(AttributeError):
+ """
+ A frozen/immutable instance or attribute have been attempted to be
+ modified.
+
+ It mirrors the behavior of ``namedtuples`` by using the same error message
+ and subclassing `AttributeError`.
+
+ .. versionadded:: 20.1.0
+ """
+
+ msg = "can't set attribute"
+ args: ClassVar[tuple[str]] = [msg]
+
+
+class FrozenInstanceError(FrozenError):
+ """
+ A frozen instance has been attempted to be modified.
+
+ .. versionadded:: 16.1.0
+ """
+
+
+class FrozenAttributeError(FrozenError):
+ """
+ A frozen attribute has been attempted to be modified.
+
+ .. versionadded:: 20.1.0
+ """
+
+
+class AttrsAttributeNotFoundError(ValueError):
+ """
+ An *attrs* function couldn't find an attribute that the user asked for.
+
+ .. versionadded:: 16.2.0
+ """
+
+
+class NotAnAttrsClassError(ValueError):
+ """
+ A non-*attrs* class has been passed into an *attrs* function.
+
+ .. versionadded:: 16.2.0
+ """
+
+
+class DefaultAlreadySetError(RuntimeError):
+ """
+ A default has been set when defining the field and is attempted to be reset
+ using the decorator.
+
+ .. versionadded:: 17.1.0
+ """
+
+
+class UnannotatedAttributeError(RuntimeError):
+ """
+ A class with ``auto_attribs=True`` has a field without a type annotation.
+
+ .. versionadded:: 17.3.0
+ """
+
+
+class PythonTooOldError(RuntimeError):
+ """
+ It was attempted to use an *attrs* feature that requires a newer Python
+ version.
+
+ .. versionadded:: 18.2.0
+ """
+
+
+class NotCallableError(TypeError):
+ """
+ A field requiring a callable has been set with a value that is not
+ callable.
+
+ .. versionadded:: 19.2.0
+ """
+
+ def __init__(self, msg, value):
+ super(TypeError, self).__init__(msg, value)
+ self.msg = msg
+ self.value = value
+
+ def __str__(self):
+ return str(self.msg)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.pyi
new file mode 100644
index 0000000..f268011
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/exceptions.pyi
@@ -0,0 +1,17 @@
+from typing import Any
+
+class FrozenError(AttributeError):
+ msg: str = ...
+
+class FrozenInstanceError(FrozenError): ...
+class FrozenAttributeError(FrozenError): ...
+class AttrsAttributeNotFoundError(ValueError): ...
+class NotAnAttrsClassError(ValueError): ...
+class DefaultAlreadySetError(RuntimeError): ...
+class UnannotatedAttributeError(RuntimeError): ...
+class PythonTooOldError(RuntimeError): ...
+
+class NotCallableError(TypeError):
+ msg: str = ...
+ value: Any = ...
+ def __init__(self, msg: str, value: Any) -> None: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/filters.py b/lambdas/aws-dd-forwarder-3.127.0/attr/filters.py
new file mode 100644
index 0000000..689b170
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/filters.py
@@ -0,0 +1,72 @@
+# SPDX-License-Identifier: MIT
+
+"""
+Commonly useful filters for `attrs.asdict` and `attrs.astuple`.
+"""
+
+from ._make import Attribute
+
+
+def _split_what(what):
+ """
+ Returns a tuple of `frozenset`s of classes and attributes.
+ """
+ return (
+ frozenset(cls for cls in what if isinstance(cls, type)),
+ frozenset(cls for cls in what if isinstance(cls, str)),
+ frozenset(cls for cls in what if isinstance(cls, Attribute)),
+ )
+
+
+def include(*what):
+ """
+ Create a filter that only allows *what*.
+
+ Args:
+ what (list[type, str, attrs.Attribute]):
+ What to include. Can be a type, a name, or an attribute.
+
+ Returns:
+ Callable:
+ A callable that can be passed to `attrs.asdict`'s and
+ `attrs.astuple`'s *filter* argument.
+
+ .. versionchanged:: 23.1.0 Accept strings with field names.
+ """
+ cls, names, attrs = _split_what(what)
+
+ def include_(attribute, value):
+ return (
+ value.__class__ in cls
+ or attribute.name in names
+ or attribute in attrs
+ )
+
+ return include_
+
+
+def exclude(*what):
+ """
+ Create a filter that does **not** allow *what*.
+
+ Args:
+ what (list[type, str, attrs.Attribute]):
+ What to exclude. Can be a type, a name, or an attribute.
+
+ Returns:
+ Callable:
+ A callable that can be passed to `attrs.asdict`'s and
+ `attrs.astuple`'s *filter* argument.
+
+ .. versionchanged:: 23.3.0 Accept field name string as input argument
+ """
+ cls, names, attrs = _split_what(what)
+
+ def exclude_(attribute, value):
+ return not (
+ value.__class__ in cls
+ or attribute.name in names
+ or attribute in attrs
+ )
+
+ return exclude_
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/filters.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/filters.pyi
new file mode 100644
index 0000000..974abdc
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/filters.pyi
@@ -0,0 +1,6 @@
+from typing import Any
+
+from . import Attribute, _FilterType
+
+def include(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ...
+def exclude(*what: type | str | Attribute[Any]) -> _FilterType[Any]: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/py.typed b/lambdas/aws-dd-forwarder-3.127.0/attr/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/setters.py b/lambdas/aws-dd-forwarder-3.127.0/attr/setters.py
new file mode 100644
index 0000000..a9ce016
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/setters.py
@@ -0,0 +1,79 @@
+# SPDX-License-Identifier: MIT
+
+"""
+Commonly used hooks for on_setattr.
+"""
+
+from . import _config
+from .exceptions import FrozenAttributeError
+
+
+def pipe(*setters):
+ """
+ Run all *setters* and return the return value of the last one.
+
+ .. versionadded:: 20.1.0
+ """
+
+ def wrapped_pipe(instance, attrib, new_value):
+ rv = new_value
+
+ for setter in setters:
+ rv = setter(instance, attrib, rv)
+
+ return rv
+
+ return wrapped_pipe
+
+
+def frozen(_, __, ___):
+ """
+ Prevent an attribute to be modified.
+
+ .. versionadded:: 20.1.0
+ """
+ raise FrozenAttributeError()
+
+
+def validate(instance, attrib, new_value):
+ """
+ Run *attrib*'s validator on *new_value* if it has one.
+
+ .. versionadded:: 20.1.0
+ """
+ if _config._run_validators is False:
+ return new_value
+
+ v = attrib.validator
+ if not v:
+ return new_value
+
+ v(instance, attrib, new_value)
+
+ return new_value
+
+
+def convert(instance, attrib, new_value):
+ """
+ Run *attrib*'s converter -- if it has one -- on *new_value* and return the
+ result.
+
+ .. versionadded:: 20.1.0
+ """
+ c = attrib.converter
+ if c:
+ # This can be removed once we drop 3.8 and use attrs.Converter instead.
+ from ._make import Converter
+
+ if not isinstance(c, Converter):
+ return c(new_value)
+
+ return c(new_value, instance, attrib)
+
+ return new_value
+
+
+# Sentinel for disabling class-wide *on_setattr* hooks for certain attributes.
+# Sphinx's autodata stopped working, so the docstring is inlined in the API
+# docs.
+NO_OP = object()
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/setters.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/setters.pyi
new file mode 100644
index 0000000..73abf36
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/setters.pyi
@@ -0,0 +1,20 @@
+from typing import Any, NewType, NoReturn, TypeVar
+
+from . import Attribute
+from attrs import _OnSetAttrType
+
+_T = TypeVar("_T")
+
+def frozen(
+ instance: Any, attribute: Attribute[Any], new_value: Any
+) -> NoReturn: ...
+def pipe(*setters: _OnSetAttrType) -> _OnSetAttrType: ...
+def validate(instance: Any, attribute: Attribute[_T], new_value: _T) -> _T: ...
+
+# convert is allowed to return Any, because they can be chained using pipe.
+def convert(
+ instance: Any, attribute: Attribute[Any], new_value: Any
+) -> Any: ...
+
+_NoOpType = NewType("_NoOpType", object)
+NO_OP: _NoOpType
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/validators.py b/lambdas/aws-dd-forwarder-3.127.0/attr/validators.py
new file mode 100644
index 0000000..8a56717
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/validators.py
@@ -0,0 +1,711 @@
+# SPDX-License-Identifier: MIT
+
+"""
+Commonly useful validators.
+"""
+
+
+import operator
+import re
+
+from contextlib import contextmanager
+from re import Pattern
+
+from ._config import get_run_validators, set_run_validators
+from ._make import _AndValidator, and_, attrib, attrs
+from .converters import default_if_none
+from .exceptions import NotCallableError
+
+
+__all__ = [
+ "and_",
+ "deep_iterable",
+ "deep_mapping",
+ "disabled",
+ "ge",
+ "get_disabled",
+ "gt",
+ "in_",
+ "instance_of",
+ "is_callable",
+ "le",
+ "lt",
+ "matches_re",
+ "max_len",
+ "min_len",
+ "not_",
+ "optional",
+ "or_",
+ "set_disabled",
+]
+
+
+def set_disabled(disabled):
+ """
+ Globally disable or enable running validators.
+
+ By default, they are run.
+
+ Args:
+ disabled (bool): If `True`, disable running all validators.
+
+ .. warning::
+
+ This function is not thread-safe!
+
+ .. versionadded:: 21.3.0
+ """
+ set_run_validators(not disabled)
+
+
+def get_disabled():
+ """
+ Return a bool indicating whether validators are currently disabled or not.
+
+ Returns:
+ bool:`True` if validators are currently disabled.
+
+ .. versionadded:: 21.3.0
+ """
+ return not get_run_validators()
+
+
+@contextmanager
+def disabled():
+ """
+ Context manager that disables running validators within its context.
+
+ .. warning::
+
+ This context manager is not thread-safe!
+
+ .. versionadded:: 21.3.0
+ """
+ set_run_validators(False)
+ try:
+ yield
+ finally:
+ set_run_validators(True)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _InstanceOfValidator:
+ type = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if not isinstance(value, self.type):
+ msg = f"'{attr.name}' must be {self.type!r} (got {value!r} that is a {value.__class__!r})."
+ raise TypeError(
+ msg,
+ attr,
+ self.type,
+ value,
+ )
+
+ def __repr__(self):
+ return f""
+
+
+def instance_of(type):
+ """
+ A validator that raises a `TypeError` if the initializer is called with a
+ wrong type for this particular attribute (checks are performed using
+ `isinstance` therefore it's also valid to pass a tuple of types).
+
+ Args:
+ type (type | tuple[type]): The type to check for.
+
+ Raises:
+ TypeError:
+ With a human readable error message, the attribute (of type
+ `attrs.Attribute`), the expected type, and the value it got.
+ """
+ return _InstanceOfValidator(type)
+
+
+@attrs(repr=False, frozen=True, slots=True)
+class _MatchesReValidator:
+ pattern = attrib()
+ match_func = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if not self.match_func(value):
+ msg = f"'{attr.name}' must match regex {self.pattern.pattern!r} ({value!r} doesn't)"
+ raise ValueError(
+ msg,
+ attr,
+ self.pattern,
+ value,
+ )
+
+ def __repr__(self):
+ return f""
+
+
+def matches_re(regex, flags=0, func=None):
+ r"""
+ A validator that raises `ValueError` if the initializer is called with a
+ string that doesn't match *regex*.
+
+ Args:
+ regex (str, re.Pattern):
+ A regex string or precompiled pattern to match against
+
+ flags (int):
+ Flags that will be passed to the underlying re function (default 0)
+
+ func (typing.Callable):
+ Which underlying `re` function to call. Valid options are
+ `re.fullmatch`, `re.search`, and `re.match`; the default `None`
+ means `re.fullmatch`. For performance reasons, the pattern is
+ always precompiled using `re.compile`.
+
+ .. versionadded:: 19.2.0
+ .. versionchanged:: 21.3.0 *regex* can be a pre-compiled pattern.
+ """
+ valid_funcs = (re.fullmatch, None, re.search, re.match)
+ if func not in valid_funcs:
+ msg = "'func' must be one of {}.".format(
+ ", ".join(
+ sorted(e and e.__name__ or "None" for e in set(valid_funcs))
+ )
+ )
+ raise ValueError(msg)
+
+ if isinstance(regex, Pattern):
+ if flags:
+ msg = "'flags' can only be used with a string pattern; pass flags to re.compile() instead"
+ raise TypeError(msg)
+ pattern = regex
+ else:
+ pattern = re.compile(regex, flags)
+
+ if func is re.match:
+ match_func = pattern.match
+ elif func is re.search:
+ match_func = pattern.search
+ else:
+ match_func = pattern.fullmatch
+
+ return _MatchesReValidator(pattern, match_func)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _OptionalValidator:
+ validator = attrib()
+
+ def __call__(self, inst, attr, value):
+ if value is None:
+ return
+
+ self.validator(inst, attr, value)
+
+ def __repr__(self):
+ return f""
+
+
+def optional(validator):
+ """
+ A validator that makes an attribute optional. An optional attribute is one
+ which can be set to `None` in addition to satisfying the requirements of
+ the sub-validator.
+
+ Args:
+ validator
+ (typing.Callable | tuple[typing.Callable] | list[typing.Callable]):
+ A validator (or validators) that is used for non-`None` values.
+
+ .. versionadded:: 15.1.0
+ .. versionchanged:: 17.1.0 *validator* can be a list of validators.
+ .. versionchanged:: 23.1.0 *validator* can also be a tuple of validators.
+ """
+ if isinstance(validator, (list, tuple)):
+ return _OptionalValidator(_AndValidator(validator))
+
+ return _OptionalValidator(validator)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _InValidator:
+ options = attrib()
+ _original_options = attrib(hash=False)
+
+ def __call__(self, inst, attr, value):
+ try:
+ in_options = value in self.options
+ except TypeError: # e.g. `1 in "abc"`
+ in_options = False
+
+ if not in_options:
+ msg = f"'{attr.name}' must be in {self._original_options!r} (got {value!r})"
+ raise ValueError(
+ msg,
+ attr,
+ self._original_options,
+ value,
+ )
+
+ def __repr__(self):
+ return f""
+
+
+def in_(options):
+ """
+ A validator that raises a `ValueError` if the initializer is called with a
+ value that does not belong in the *options* provided.
+
+ The check is performed using ``value in options``, so *options* has to
+ support that operation.
+
+ To keep the validator hashable, dicts, lists, and sets are transparently
+ transformed into a `tuple`.
+
+ Args:
+ options: Allowed options.
+
+ Raises:
+ ValueError:
+ With a human readable error message, the attribute (of type
+ `attrs.Attribute`), the expected options, and the value it got.
+
+ .. versionadded:: 17.1.0
+ .. versionchanged:: 22.1.0
+ The ValueError was incomplete until now and only contained the human
+ readable error message. Now it contains all the information that has
+ been promised since 17.1.0.
+ .. versionchanged:: 24.1.0
+ *options* that are a list, dict, or a set are now transformed into a
+ tuple to keep the validator hashable.
+ """
+ repr_options = options
+ if isinstance(options, (list, dict, set)):
+ options = tuple(options)
+
+ return _InValidator(options, repr_options)
+
+
+@attrs(repr=False, slots=False, unsafe_hash=True)
+class _IsCallableValidator:
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if not callable(value):
+ message = (
+ "'{name}' must be callable "
+ "(got {value!r} that is a {actual!r})."
+ )
+ raise NotCallableError(
+ msg=message.format(
+ name=attr.name, value=value, actual=value.__class__
+ ),
+ value=value,
+ )
+
+ def __repr__(self):
+ return ""
+
+
+def is_callable():
+ """
+ A validator that raises a `attrs.exceptions.NotCallableError` if the
+ initializer is called with a value for this particular attribute that is
+ not callable.
+
+ .. versionadded:: 19.1.0
+
+ Raises:
+ attrs.exceptions.NotCallableError:
+ With a human readable error message containing the attribute
+ (`attrs.Attribute`) name, and the value it got.
+ """
+ return _IsCallableValidator()
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _DeepIterable:
+ member_validator = attrib(validator=is_callable())
+ iterable_validator = attrib(
+ default=None, validator=optional(is_callable())
+ )
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if self.iterable_validator is not None:
+ self.iterable_validator(inst, attr, value)
+
+ for member in value:
+ self.member_validator(inst, attr, member)
+
+ def __repr__(self):
+ iterable_identifier = (
+ ""
+ if self.iterable_validator is None
+ else f" {self.iterable_validator!r}"
+ )
+ return (
+ f""
+ )
+
+
+def deep_iterable(member_validator, iterable_validator=None):
+ """
+ A validator that performs deep validation of an iterable.
+
+ Args:
+ member_validator: Validator to apply to iterable members.
+
+ iterable_validator:
+ Validator to apply to iterable itself (optional).
+
+ Raises
+ TypeError: if any sub-validators fail
+
+ .. versionadded:: 19.1.0
+ """
+ if isinstance(member_validator, (list, tuple)):
+ member_validator = and_(*member_validator)
+ return _DeepIterable(member_validator, iterable_validator)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _DeepMapping:
+ key_validator = attrib(validator=is_callable())
+ value_validator = attrib(validator=is_callable())
+ mapping_validator = attrib(default=None, validator=optional(is_callable()))
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if self.mapping_validator is not None:
+ self.mapping_validator(inst, attr, value)
+
+ for key in value:
+ self.key_validator(inst, attr, key)
+ self.value_validator(inst, attr, value[key])
+
+ def __repr__(self):
+ return f""
+
+
+def deep_mapping(key_validator, value_validator, mapping_validator=None):
+ """
+ A validator that performs deep validation of a dictionary.
+
+ Args:
+ key_validator: Validator to apply to dictionary keys.
+
+ value_validator: Validator to apply to dictionary values.
+
+ mapping_validator:
+ Validator to apply to top-level mapping attribute (optional).
+
+ .. versionadded:: 19.1.0
+
+ Raises:
+ TypeError: if any sub-validators fail
+ """
+ return _DeepMapping(key_validator, value_validator, mapping_validator)
+
+
+@attrs(repr=False, frozen=True, slots=True)
+class _NumberValidator:
+ bound = attrib()
+ compare_op = attrib()
+ compare_func = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if not self.compare_func(value, self.bound):
+ msg = f"'{attr.name}' must be {self.compare_op} {self.bound}: {value}"
+ raise ValueError(msg)
+
+ def __repr__(self):
+ return f""
+
+
+def lt(val):
+ """
+ A validator that raises `ValueError` if the initializer is called with a
+ number larger or equal to *val*.
+
+ The validator uses `operator.lt` to compare the values.
+
+ Args:
+ val: Exclusive upper bound for values.
+
+ .. versionadded:: 21.3.0
+ """
+ return _NumberValidator(val, "<", operator.lt)
+
+
+def le(val):
+ """
+ A validator that raises `ValueError` if the initializer is called with a
+ number greater than *val*.
+
+ The validator uses `operator.le` to compare the values.
+
+ Args:
+ val: Inclusive upper bound for values.
+
+ .. versionadded:: 21.3.0
+ """
+ return _NumberValidator(val, "<=", operator.le)
+
+
+def ge(val):
+ """
+ A validator that raises `ValueError` if the initializer is called with a
+ number smaller than *val*.
+
+ The validator uses `operator.ge` to compare the values.
+
+ Args:
+ val: Inclusive lower bound for values
+
+ .. versionadded:: 21.3.0
+ """
+ return _NumberValidator(val, ">=", operator.ge)
+
+
+def gt(val):
+ """
+ A validator that raises `ValueError` if the initializer is called with a
+ number smaller or equal to *val*.
+
+ The validator uses `operator.ge` to compare the values.
+
+ Args:
+ val: Exclusive lower bound for values
+
+ .. versionadded:: 21.3.0
+ """
+ return _NumberValidator(val, ">", operator.gt)
+
+
+@attrs(repr=False, frozen=True, slots=True)
+class _MaxLengthValidator:
+ max_length = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if len(value) > self.max_length:
+ msg = f"Length of '{attr.name}' must be <= {self.max_length}: {len(value)}"
+ raise ValueError(msg)
+
+ def __repr__(self):
+ return f""
+
+
+def max_len(length):
+ """
+ A validator that raises `ValueError` if the initializer is called
+ with a string or iterable that is longer than *length*.
+
+ Args:
+ length (int): Maximum length of the string or iterable
+
+ .. versionadded:: 21.3.0
+ """
+ return _MaxLengthValidator(length)
+
+
+@attrs(repr=False, frozen=True, slots=True)
+class _MinLengthValidator:
+ min_length = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if len(value) < self.min_length:
+ msg = f"Length of '{attr.name}' must be >= {self.min_length}: {len(value)}"
+ raise ValueError(msg)
+
+ def __repr__(self):
+ return f""
+
+
+def min_len(length):
+ """
+ A validator that raises `ValueError` if the initializer is called
+ with a string or iterable that is shorter than *length*.
+
+ Args:
+ length (int): Minimum length of the string or iterable
+
+ .. versionadded:: 22.1.0
+ """
+ return _MinLengthValidator(length)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _SubclassOfValidator:
+ type = attrib()
+
+ def __call__(self, inst, attr, value):
+ """
+ We use a callable class to be able to change the ``__repr__``.
+ """
+ if not issubclass(value, self.type):
+ msg = f"'{attr.name}' must be a subclass of {self.type!r} (got {value!r})."
+ raise TypeError(
+ msg,
+ attr,
+ self.type,
+ value,
+ )
+
+ def __repr__(self):
+ return f""
+
+
+def _subclass_of(type):
+ """
+ A validator that raises a `TypeError` if the initializer is called with a
+ wrong type for this particular attribute (checks are performed using
+ `issubclass` therefore it's also valid to pass a tuple of types).
+
+ Args:
+ type (type | tuple[type, ...]): The type(s) to check for.
+
+ Raises:
+ TypeError:
+ With a human readable error message, the attribute (of type
+ `attrs.Attribute`), the expected type, and the value it got.
+ """
+ return _SubclassOfValidator(type)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _NotValidator:
+ validator = attrib()
+ msg = attrib(
+ converter=default_if_none(
+ "not_ validator child '{validator!r}' "
+ "did not raise a captured error"
+ )
+ )
+ exc_types = attrib(
+ validator=deep_iterable(
+ member_validator=_subclass_of(Exception),
+ iterable_validator=instance_of(tuple),
+ ),
+ )
+
+ def __call__(self, inst, attr, value):
+ try:
+ self.validator(inst, attr, value)
+ except self.exc_types:
+ pass # suppress error to invert validity
+ else:
+ raise ValueError(
+ self.msg.format(
+ validator=self.validator,
+ exc_types=self.exc_types,
+ ),
+ attr,
+ self.validator,
+ value,
+ self.exc_types,
+ )
+
+ def __repr__(self):
+ return f""
+
+
+def not_(validator, *, msg=None, exc_types=(ValueError, TypeError)):
+ """
+ A validator that wraps and logically 'inverts' the validator passed to it.
+ It will raise a `ValueError` if the provided validator *doesn't* raise a
+ `ValueError` or `TypeError` (by default), and will suppress the exception
+ if the provided validator *does*.
+
+ Intended to be used with existing validators to compose logic without
+ needing to create inverted variants, for example, ``not_(in_(...))``.
+
+ Args:
+ validator: A validator to be logically inverted.
+
+ msg (str):
+ Message to raise if validator fails. Formatted with keys
+ ``exc_types`` and ``validator``.
+
+ exc_types (tuple[type, ...]):
+ Exception type(s) to capture. Other types raised by child
+ validators will not be intercepted and pass through.
+
+ Raises:
+ ValueError:
+ With a human readable error message, the attribute (of type
+ `attrs.Attribute`), the validator that failed to raise an
+ exception, the value it got, and the expected exception types.
+
+ .. versionadded:: 22.2.0
+ """
+ try:
+ exc_types = tuple(exc_types)
+ except TypeError:
+ exc_types = (exc_types,)
+ return _NotValidator(validator, msg, exc_types)
+
+
+@attrs(repr=False, slots=True, unsafe_hash=True)
+class _OrValidator:
+ validators = attrib()
+
+ def __call__(self, inst, attr, value):
+ for v in self.validators:
+ try:
+ v(inst, attr, value)
+ except Exception: # noqa: BLE001, PERF203, S112
+ continue
+ else:
+ return
+
+ msg = f"None of {self.validators!r} satisfied for value {value!r}"
+ raise ValueError(msg)
+
+ def __repr__(self):
+ return f""
+
+
+def or_(*validators):
+ """
+ A validator that composes multiple validators into one.
+
+ When called on a value, it runs all wrapped validators until one of them is
+ satisfied.
+
+ Args:
+ validators (~collections.abc.Iterable[typing.Callable]):
+ Arbitrary number of validators.
+
+ Raises:
+ ValueError:
+ If no validator is satisfied. Raised with a human-readable error
+ message listing all the wrapped validators and the value that
+ failed all of them.
+
+ .. versionadded:: 24.1.0
+ """
+ vals = []
+ for v in validators:
+ vals.extend(v.validators if isinstance(v, _OrValidator) else [v])
+
+ return _OrValidator(tuple(vals))
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attr/validators.pyi b/lambdas/aws-dd-forwarder-3.127.0/attr/validators.pyi
new file mode 100644
index 0000000..a314110
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attr/validators.pyi
@@ -0,0 +1,83 @@
+from typing import (
+ Any,
+ AnyStr,
+ Callable,
+ Container,
+ ContextManager,
+ Iterable,
+ Mapping,
+ Match,
+ Pattern,
+ TypeVar,
+ overload,
+)
+
+from attrs import _ValidatorType
+from attrs import _ValidatorArgType
+
+_T = TypeVar("_T")
+_T1 = TypeVar("_T1")
+_T2 = TypeVar("_T2")
+_T3 = TypeVar("_T3")
+_I = TypeVar("_I", bound=Iterable)
+_K = TypeVar("_K")
+_V = TypeVar("_V")
+_M = TypeVar("_M", bound=Mapping)
+
+def set_disabled(run: bool) -> None: ...
+def get_disabled() -> bool: ...
+def disabled() -> ContextManager[None]: ...
+
+# To be more precise on instance_of use some overloads.
+# If there are more than 3 items in the tuple then we fall back to Any
+@overload
+def instance_of(type: type[_T]) -> _ValidatorType[_T]: ...
+@overload
+def instance_of(type: tuple[type[_T]]) -> _ValidatorType[_T]: ...
+@overload
+def instance_of(
+ type: tuple[type[_T1], type[_T2]]
+) -> _ValidatorType[_T1 | _T2]: ...
+@overload
+def instance_of(
+ type: tuple[type[_T1], type[_T2], type[_T3]]
+) -> _ValidatorType[_T1 | _T2 | _T3]: ...
+@overload
+def instance_of(type: tuple[type, ...]) -> _ValidatorType[Any]: ...
+def optional(
+ validator: (
+ _ValidatorType[_T]
+ | list[_ValidatorType[_T]]
+ | tuple[_ValidatorType[_T]]
+ ),
+) -> _ValidatorType[_T | None]: ...
+def in_(options: Container[_T]) -> _ValidatorType[_T]: ...
+def and_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
+def matches_re(
+ regex: Pattern[AnyStr] | AnyStr,
+ flags: int = ...,
+ func: Callable[[AnyStr, AnyStr, int], Match[AnyStr] | None] | None = ...,
+) -> _ValidatorType[AnyStr]: ...
+def deep_iterable(
+ member_validator: _ValidatorArgType[_T],
+ iterable_validator: _ValidatorType[_I] | None = ...,
+) -> _ValidatorType[_I]: ...
+def deep_mapping(
+ key_validator: _ValidatorType[_K],
+ value_validator: _ValidatorType[_V],
+ mapping_validator: _ValidatorType[_M] | None = ...,
+) -> _ValidatorType[_M]: ...
+def is_callable() -> _ValidatorType[_T]: ...
+def lt(val: _T) -> _ValidatorType[_T]: ...
+def le(val: _T) -> _ValidatorType[_T]: ...
+def ge(val: _T) -> _ValidatorType[_T]: ...
+def gt(val: _T) -> _ValidatorType[_T]: ...
+def max_len(length: int) -> _ValidatorType[_T]: ...
+def min_len(length: int) -> _ValidatorType[_T]: ...
+def not_(
+ validator: _ValidatorType[_T],
+ *,
+ msg: str | None = None,
+ exc_types: type[Exception] | Iterable[type[Exception]] = ...,
+) -> _ValidatorType[_T]: ...
+def or_(*validators: _ValidatorType[_T]) -> _ValidatorType[_T]: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/METADATA
new file mode 100644
index 0000000..a85b378
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/METADATA
@@ -0,0 +1,242 @@
+Metadata-Version: 2.3
+Name: attrs
+Version: 24.2.0
+Summary: Classes Without Boilerplate
+Project-URL: Documentation, https://www.attrs.org/
+Project-URL: Changelog, https://www.attrs.org/en/stable/changelog.html
+Project-URL: GitHub, https://github.com/python-attrs/attrs
+Project-URL: Funding, https://github.com/sponsors/hynek
+Project-URL: Tidelift, https://tidelift.com/subscription/pkg/pypi-attrs?utm_source=pypi-attrs&utm_medium=pypi
+Author-email: Hynek Schlawack
+License-Expression: MIT
+License-File: LICENSE
+Keywords: attribute,boilerplate,class
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: MIT License
+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 :: 3.13
+Classifier: Programming Language :: Python :: Implementation :: CPython
+Classifier: Programming Language :: Python :: Implementation :: PyPy
+Classifier: Typing :: Typed
+Requires-Python: >=3.7
+Requires-Dist: importlib-metadata; python_version < '3.8'
+Provides-Extra: benchmark
+Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'benchmark'
+Requires-Dist: hypothesis; extra == 'benchmark'
+Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.9') and extra == 'benchmark'
+Requires-Dist: pympler; extra == 'benchmark'
+Requires-Dist: pytest-codspeed; extra == 'benchmark'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.9' and python_version < '3.13') and extra == 'benchmark'
+Requires-Dist: pytest-xdist[psutil]; extra == 'benchmark'
+Requires-Dist: pytest>=4.3.0; extra == 'benchmark'
+Provides-Extra: cov
+Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'cov'
+Requires-Dist: coverage[toml]>=5.3; extra == 'cov'
+Requires-Dist: hypothesis; extra == 'cov'
+Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.9') and extra == 'cov'
+Requires-Dist: pympler; extra == 'cov'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.9' and python_version < '3.13') and extra == 'cov'
+Requires-Dist: pytest-xdist[psutil]; extra == 'cov'
+Requires-Dist: pytest>=4.3.0; extra == 'cov'
+Provides-Extra: dev
+Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'dev'
+Requires-Dist: hypothesis; extra == 'dev'
+Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.9') and extra == 'dev'
+Requires-Dist: pre-commit; extra == 'dev'
+Requires-Dist: pympler; extra == 'dev'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.9' and python_version < '3.13') and extra == 'dev'
+Requires-Dist: pytest-xdist[psutil]; extra == 'dev'
+Requires-Dist: pytest>=4.3.0; extra == 'dev'
+Provides-Extra: docs
+Requires-Dist: cogapp; extra == 'docs'
+Requires-Dist: furo; extra == 'docs'
+Requires-Dist: myst-parser; extra == 'docs'
+Requires-Dist: sphinx; extra == 'docs'
+Requires-Dist: sphinx-notfound-page; extra == 'docs'
+Requires-Dist: sphinxcontrib-towncrier; extra == 'docs'
+Requires-Dist: towncrier<24.7; extra == 'docs'
+Provides-Extra: tests
+Requires-Dist: cloudpickle; (platform_python_implementation == 'CPython') and extra == 'tests'
+Requires-Dist: hypothesis; extra == 'tests'
+Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.9') and extra == 'tests'
+Requires-Dist: pympler; extra == 'tests'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.9' and python_version < '3.13') and extra == 'tests'
+Requires-Dist: pytest-xdist[psutil]; extra == 'tests'
+Requires-Dist: pytest>=4.3.0; extra == 'tests'
+Provides-Extra: tests-mypy
+Requires-Dist: mypy>=1.11.1; (platform_python_implementation == 'CPython' and python_version >= '3.9') and extra == 'tests-mypy'
+Requires-Dist: pytest-mypy-plugins; (platform_python_implementation == 'CPython' and python_version >= '3.9' and python_version < '3.13') and extra == 'tests-mypy'
+Description-Content-Type: text/markdown
+
+
+
+
+
+
+
+
+*attrs* is the Python package that will bring back the **joy** of **writing classes** by relieving you from the drudgery of implementing object protocols (aka [dunder methods](https://www.attrs.org/en/latest/glossary.html#term-dunder-methods)).
+[Trusted by NASA](https://docs.github.com/en/account-and-profile/setting-up-and-managing-your-github-profile/customizing-your-profile/personalizing-your-profile#list-of-qualifying-repositories-for-mars-2020-helicopter-contributor-achievement) for Mars missions since 2020!
+
+Its main goal is to help you to write **concise** and **correct** software without slowing down your code.
+
+
+## Sponsors
+
+*attrs* would not be possible without our [amazing sponsors](https://github.com/sponsors/hynek).
+Especially those generously supporting us at the *The Organization* tier and higher:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Please consider joining them to help make attrs’s maintenance more sustainable!
+
+
+
+
+## Example
+
+*attrs* gives you a class decorator and a way to declaratively define the attributes on that class:
+
+
+
+```pycon
+>>> from attrs import asdict, define, make_class, Factory
+
+>>> @define
+... class SomeClass:
+... a_number: int = 42
+... list_of_numbers: list[int] = Factory(list)
+...
+... def hard_math(self, another_number):
+... return self.a_number + sum(self.list_of_numbers) * another_number
+
+
+>>> sc = SomeClass(1, [1, 2, 3])
+>>> sc
+SomeClass(a_number=1, list_of_numbers=[1, 2, 3])
+
+>>> sc.hard_math(3)
+19
+>>> sc == SomeClass(1, [1, 2, 3])
+True
+>>> sc != SomeClass(2, [3, 2, 1])
+True
+
+>>> asdict(sc)
+{'a_number': 1, 'list_of_numbers': [1, 2, 3]}
+
+>>> SomeClass()
+SomeClass(a_number=42, list_of_numbers=[])
+
+>>> C = make_class("C", ["a", "b"])
+>>> C("foo", "bar")
+C(a='foo', b='bar')
+```
+
+After *declaring* your attributes, *attrs* gives you:
+
+- a concise and explicit overview of the class's attributes,
+- a nice human-readable `__repr__`,
+- equality-checking methods,
+- an initializer,
+- and much more,
+
+*without* writing dull boilerplate code again and again and *without* runtime performance penalties.
+
+---
+
+This example uses *attrs*'s modern APIs that have been introduced in version 20.1.0, and the *attrs* package import name that has been added in version 21.3.0.
+The classic APIs (`@attr.s`, `attr.ib`, plus their serious-business aliases) and the `attr` package import name will remain **indefinitely**.
+
+Check out [*On The Core API Names*](https://www.attrs.org/en/latest/names.html) for an in-depth explanation!
+
+
+### Hate Type Annotations!?
+
+No problem!
+Types are entirely **optional** with *attrs*.
+Simply assign `attrs.field()` to the attributes instead of annotating them with types:
+
+```python
+from attrs import define, field
+
+@define
+class SomeClass:
+ a_number = field(default=42)
+ list_of_numbers = field(factory=list)
+```
+
+
+## Data Classes
+
+On the tin, *attrs* might remind you of `dataclasses` (and indeed, `dataclasses` [are a descendant](https://hynek.me/articles/import-attrs/) of *attrs*).
+In practice it does a lot more and is more flexible.
+For instance, it allows you to define [special handling of NumPy arrays for equality checks](https://www.attrs.org/en/stable/comparison.html#customization), allows more ways to [plug into the initialization process](https://www.attrs.org/en/stable/init.html#hooking-yourself-into-initialization), has a replacement for `__init_subclass__`, and allows for stepping through the generated methods using a debugger.
+
+For more details, please refer to our [comparison page](https://www.attrs.org/en/stable/why.html#data-classes), but generally speaking, we are more likely to commit crimes against nature to make things work that one would expect to work, but that are quite complicated in practice.
+
+
+## Project Information
+
+- [**Changelog**](https://www.attrs.org/en/stable/changelog.html)
+- [**Documentation**](https://www.attrs.org/)
+- [**PyPI**](https://pypi.org/project/attrs/)
+- [**Source Code**](https://github.com/python-attrs/attrs)
+- [**Contributing**](https://github.com/python-attrs/attrs/blob/main/.github/CONTRIBUTING.md)
+- [**Third-party Extensions**](https://github.com/python-attrs/attrs/wiki/Extensions-to-attrs)
+- **Get Help**: use the `python-attrs` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/python-attrs)
+
+
+### *attrs* for Enterprise
+
+Available as part of the Tidelift Subscription.
+
+The maintainers of *attrs* and thousands of other packages are working with Tidelift to deliver commercial support and maintenance for the open source packages you use to build your applications.
+Save time, reduce risk, and improve code health, while paying the maintainers of the exact packages you use.
+[Learn more](https://tidelift.com/?utm_source=lifter&utm_medium=referral&utm_campaign=hynek).
+
+## Release Information
+
+### Deprecations
+
+- Given the amount of warnings raised in the broader ecosystem, we've decided to only soft-deprecate the *hash* argument to `@define` / `@attr.s`.
+ Please don't use it in new code, but we don't intend to remove it anymore.
+ [#1330](https://github.com/python-attrs/attrs/issues/1330)
+
+
+### Changes
+
+- `attrs.converters.pipe()` (and its syntactic sugar of passing a list for `attrs.field()`'s / `attr.ib()`'s *converter* argument) works again when passing `attrs.setters.convert` to *on_setattr* (which is default for `attrs.define`).
+ [#1328](https://github.com/python-attrs/attrs/issues/1328)
+- Restored support for PEP [649](https://peps.python.org/pep-0649/) / [749](https://peps.python.org/pep-0749/)-implementing Pythons -- currently 3.14-dev.
+ [#1329](https://github.com/python-attrs/attrs/issues/1329)
+
+
+
+---
+
+[Full changelog →](https://www.attrs.org/en/stable/changelog.html)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/RECORD
new file mode 100644
index 0000000..2a91231
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/RECORD
@@ -0,0 +1,56 @@
+attr/__init__.py,sha256=l8Ewh5KZE7CCY0i1iDfSCnFiUTIkBVoqsXjX9EZnIVA,2087
+attr/__init__.pyi,sha256=aTVHBPX6krCGvbQvOl_UKqEzmi2HFsaIVm2WKmAiqVs,11434
+attr/__pycache__/__init__.cpython-311.pyc,,
+attr/__pycache__/_cmp.cpython-311.pyc,,
+attr/__pycache__/_compat.cpython-311.pyc,,
+attr/__pycache__/_config.cpython-311.pyc,,
+attr/__pycache__/_funcs.cpython-311.pyc,,
+attr/__pycache__/_make.cpython-311.pyc,,
+attr/__pycache__/_next_gen.cpython-311.pyc,,
+attr/__pycache__/_version_info.cpython-311.pyc,,
+attr/__pycache__/converters.cpython-311.pyc,,
+attr/__pycache__/exceptions.cpython-311.pyc,,
+attr/__pycache__/filters.cpython-311.pyc,,
+attr/__pycache__/setters.cpython-311.pyc,,
+attr/__pycache__/validators.cpython-311.pyc,,
+attr/_cmp.py,sha256=3umHiBtgsEYtvNP_8XrQwTCdFoZIX4DEur76N-2a3X8,4123
+attr/_cmp.pyi,sha256=U-_RU_UZOyPUEQzXE6RMYQQcjkZRY25wTH99sN0s7MM,368
+attr/_compat.py,sha256=n2Uk3c-ywv0PkFfGlvqR7SzDXp4NOhWmNV_ZK6YfWoM,2958
+attr/_config.py,sha256=z81Vt-GeT_2taxs1XZfmHx9TWlSxjPb6eZH1LTGsS54,843
+attr/_funcs.py,sha256=SGDmNlED1TM3tgO9Ap2mfRfVI24XEAcrNQs7o2eBXHQ,17386
+attr/_make.py,sha256=BjENJz5eJoojJVbCoupWjXLLEZJ7VID89lisLbQUlmQ,91479
+attr/_next_gen.py,sha256=dhGb96VFg4kXBkS9Zdz1A2uxVJ99q_RT1hw3kLA9-uI,24630
+attr/_typing_compat.pyi,sha256=XDP54TUn-ZKhD62TOQebmzrwFyomhUCoGRpclb6alRA,469
+attr/_version_info.py,sha256=exSqb3b5E-fMSsgZAlEw9XcLpEgobPORCZpcaEglAM4,2121
+attr/_version_info.pyi,sha256=x_M3L3WuB7r_ULXAWjx959udKQ4HLB8l-hsc1FDGNvk,209
+attr/converters.py,sha256=vNa58pZi9V6uxBzl4t1QrHbQfkT4iRFAodyXe7lcgg0,3506
+attr/converters.pyi,sha256=mpDoVFO3Cpx8xYSSV0iZFl7IAHuoNBglxKfxHvLj_sY,410
+attr/exceptions.py,sha256=HRFq4iybmv7-DcZwyjl6M1euM2YeJVK_hFxuaBGAngI,1977
+attr/exceptions.pyi,sha256=zZq8bCUnKAy9mDtBEw42ZhPhAUIHoTKedDQInJD883M,539
+attr/filters.py,sha256=ZBiKWLp3R0LfCZsq7X11pn9WX8NslS2wXM4jsnLOGc8,1795
+attr/filters.pyi,sha256=3J5BG-dTxltBk1_-RuNRUHrv2qu1v8v4aDNAQ7_mifA,208
+attr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+attr/setters.py,sha256=faMQeiBo_nbXYnPaQ1pq8PXeA7Zr-uNsVsPMiKCmxhc,1619
+attr/setters.pyi,sha256=NnVkaFU1BB4JB8E4JuXyrzTUgvtMpj8p3wBdJY7uix4,584
+attr/validators.py,sha256=985eTP6RHyon61YEauMJgyNy1rEOhJWiSXMJgRxPtrQ,20045
+attr/validators.pyi,sha256=LjKf7AoXZfvGSfT3LRs61Qfln94konYyMUPoJJjOxK4,2502
+attrs-24.2.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+attrs-24.2.0.dist-info/METADATA,sha256=3Jgk4lr9Y1SAqAcwOLPN_mpW0wc6VOGm-yHt1LsPIHw,11524
+attrs-24.2.0.dist-info/RECORD,,
+attrs-24.2.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+attrs-24.2.0.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
+attrs-24.2.0.dist-info/licenses/LICENSE,sha256=iCEVyV38KvHutnFPjsbVy8q_Znyv-HKfQkINpj9xTp8,1109
+attrs/__init__.py,sha256=5FHo-EMFOX-g4ialSK4fwOjuoHzLISJDZCwoOl02Ty8,1071
+attrs/__init__.pyi,sha256=o3l92VsD9kHz8sldEtb_tllBTs3TeL-vIBMTxo2Zc_4,7703
+attrs/__pycache__/__init__.cpython-311.pyc,,
+attrs/__pycache__/converters.cpython-311.pyc,,
+attrs/__pycache__/exceptions.cpython-311.pyc,,
+attrs/__pycache__/filters.cpython-311.pyc,,
+attrs/__pycache__/setters.cpython-311.pyc,,
+attrs/__pycache__/validators.cpython-311.pyc,,
+attrs/converters.py,sha256=8kQljrVwfSTRu8INwEk8SI0eGrzmWftsT7rM0EqyohM,76
+attrs/exceptions.py,sha256=ACCCmg19-vDFaDPY9vFl199SPXCQMN_bENs4DALjzms,76
+attrs/filters.py,sha256=VOUMZug9uEU6dUuA0dF1jInUK0PL3fLgP0VBS5d-CDE,73
+attrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+attrs/setters.py,sha256=eL1YidYQV3T2h9_SYIZSZR1FAcHGb1TuCTy0E0Lv2SU,73
+attrs/validators.py,sha256=xcy6wD5TtTkdCG1f4XWbocPSO0faBjk5IfVJfP6SUj0,76
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/WHEEL
new file mode 100644
index 0000000..cdd68a4
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.25.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/licenses/LICENSE b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/licenses/LICENSE
new file mode 100644
index 0000000..2bd6453
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs-24.2.0.dist-info/licenses/LICENSE
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2015 Hynek Schlawack and the attrs 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/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.py
new file mode 100644
index 0000000..963b197
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.py
@@ -0,0 +1,67 @@
+# SPDX-License-Identifier: MIT
+
+from attr import (
+ NOTHING,
+ Attribute,
+ AttrsInstance,
+ Converter,
+ Factory,
+ _make_getattr,
+ assoc,
+ cmp_using,
+ define,
+ evolve,
+ field,
+ fields,
+ fields_dict,
+ frozen,
+ has,
+ make_class,
+ mutable,
+ resolve_types,
+ validate,
+)
+from attr._next_gen import asdict, astuple
+
+from . import converters, exceptions, filters, setters, validators
+
+
+__all__ = [
+ "__author__",
+ "__copyright__",
+ "__description__",
+ "__doc__",
+ "__email__",
+ "__license__",
+ "__title__",
+ "__url__",
+ "__version__",
+ "__version_info__",
+ "asdict",
+ "assoc",
+ "astuple",
+ "Attribute",
+ "AttrsInstance",
+ "cmp_using",
+ "Converter",
+ "converters",
+ "define",
+ "evolve",
+ "exceptions",
+ "Factory",
+ "field",
+ "fields_dict",
+ "fields",
+ "filters",
+ "frozen",
+ "has",
+ "make_class",
+ "mutable",
+ "NOTHING",
+ "resolve_types",
+ "setters",
+ "validate",
+ "validators",
+]
+
+__getattr__ = _make_getattr(__name__)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.pyi b/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.pyi
new file mode 100644
index 0000000..b2670de
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/__init__.pyi
@@ -0,0 +1,252 @@
+import sys
+
+from typing import (
+ Any,
+ Callable,
+ Mapping,
+ Sequence,
+ overload,
+ TypeVar,
+)
+
+# Because we need to type our own stuff, we have to make everything from
+# attr explicitly public too.
+from attr import __author__ as __author__
+from attr import __copyright__ as __copyright__
+from attr import __description__ as __description__
+from attr import __email__ as __email__
+from attr import __license__ as __license__
+from attr import __title__ as __title__
+from attr import __url__ as __url__
+from attr import __version__ as __version__
+from attr import __version_info__ as __version_info__
+from attr import assoc as assoc
+from attr import Attribute as Attribute
+from attr import AttrsInstance as AttrsInstance
+from attr import cmp_using as cmp_using
+from attr import converters as converters
+from attr import Converter as Converter
+from attr import evolve as evolve
+from attr import exceptions as exceptions
+from attr import Factory as Factory
+from attr import fields as fields
+from attr import fields_dict as fields_dict
+from attr import filters as filters
+from attr import has as has
+from attr import make_class as make_class
+from attr import NOTHING as NOTHING
+from attr import resolve_types as resolve_types
+from attr import setters as setters
+from attr import validate as validate
+from attr import validators as validators
+from attr import attrib, asdict as asdict, astuple as astuple
+
+if sys.version_info >= (3, 11):
+ from typing import dataclass_transform
+else:
+ from typing_extensions import dataclass_transform
+
+_T = TypeVar("_T")
+_C = TypeVar("_C", bound=type)
+
+_EqOrderType = bool | Callable[[Any], Any]
+_ValidatorType = Callable[[Any, "Attribute[_T]", _T], Any]
+_ConverterType = Callable[[Any], Any]
+_ReprType = Callable[[Any], str]
+_ReprArgType = bool | _ReprType
+_OnSetAttrType = Callable[[Any, "Attribute[Any]", Any], Any]
+_OnSetAttrArgType = _OnSetAttrType | list[_OnSetAttrType] | setters._NoOpType
+_FieldTransformer = Callable[
+ [type, list["Attribute[Any]"]], list["Attribute[Any]"]
+]
+# FIXME: in reality, if multiple validators are passed they must be in a list
+# or tuple, but those are invariant and so would prevent subtypes of
+# _ValidatorType from working when passed in a list or tuple.
+_ValidatorArgType = _ValidatorType[_T] | Sequence[_ValidatorType[_T]]
+
+@overload
+def field(
+ *,
+ default: None = ...,
+ validator: None = ...,
+ repr: _ReprArgType = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ converter: None = ...,
+ factory: None = ...,
+ kw_only: bool = ...,
+ eq: bool | None = ...,
+ order: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+ type: type | None = ...,
+) -> Any: ...
+
+# This form catches an explicit None or no default and infers the type from the
+# other arguments.
+@overload
+def field(
+ *,
+ default: None = ...,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+ type: type | None = ...,
+) -> _T: ...
+
+# This form catches an explicit default argument.
+@overload
+def field(
+ *,
+ default: _T,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+ type: type | None = ...,
+) -> _T: ...
+
+# This form covers type=non-Type: e.g. forward references (str), Any
+@overload
+def field(
+ *,
+ default: _T | None = ...,
+ validator: _ValidatorArgType[_T] | None = ...,
+ repr: _ReprArgType = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ metadata: Mapping[Any, Any] | None = ...,
+ converter: _ConverterType | Converter[Any, _T] | None = ...,
+ factory: Callable[[], _T] | None = ...,
+ kw_only: bool = ...,
+ eq: _EqOrderType | None = ...,
+ order: _EqOrderType | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ alias: str | None = ...,
+ type: type | None = ...,
+) -> Any: ...
+@overload
+@dataclass_transform(field_specifiers=(attrib, field))
+def define(
+ maybe_cls: _C,
+ *,
+ these: dict[str, Any] | None = ...,
+ repr: bool = ...,
+ unsafe_hash: bool | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: bool | None = ...,
+ order: bool | None = ...,
+ auto_detect: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+) -> _C: ...
+@overload
+@dataclass_transform(field_specifiers=(attrib, field))
+def define(
+ maybe_cls: None = ...,
+ *,
+ these: dict[str, Any] | None = ...,
+ repr: bool = ...,
+ unsafe_hash: bool | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: bool | None = ...,
+ order: bool | None = ...,
+ auto_detect: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+) -> Callable[[_C], _C]: ...
+
+mutable = define
+
+@overload
+@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field))
+def frozen(
+ maybe_cls: _C,
+ *,
+ these: dict[str, Any] | None = ...,
+ repr: bool = ...,
+ unsafe_hash: bool | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: bool | None = ...,
+ order: bool | None = ...,
+ auto_detect: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+) -> _C: ...
+@overload
+@dataclass_transform(frozen_default=True, field_specifiers=(attrib, field))
+def frozen(
+ maybe_cls: None = ...,
+ *,
+ these: dict[str, Any] | None = ...,
+ repr: bool = ...,
+ unsafe_hash: bool | None = ...,
+ hash: bool | None = ...,
+ init: bool = ...,
+ slots: bool = ...,
+ frozen: bool = ...,
+ weakref_slot: bool = ...,
+ str: bool = ...,
+ auto_attribs: bool = ...,
+ kw_only: bool = ...,
+ cache_hash: bool = ...,
+ auto_exc: bool = ...,
+ eq: bool | None = ...,
+ order: bool | None = ...,
+ auto_detect: bool = ...,
+ getstate_setstate: bool | None = ...,
+ on_setattr: _OnSetAttrArgType | None = ...,
+ field_transformer: _FieldTransformer | None = ...,
+ match_args: bool = ...,
+) -> Callable[[_C], _C]: ...
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/converters.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/converters.py
new file mode 100644
index 0000000..7821f6c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/converters.py
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+from attr.converters import * # noqa: F403
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/exceptions.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/exceptions.py
new file mode 100644
index 0000000..3323f9d
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/exceptions.py
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+from attr.exceptions import * # noqa: F403
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/filters.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/filters.py
new file mode 100644
index 0000000..3080f48
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/filters.py
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+from attr.filters import * # noqa: F403
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/py.typed b/lambdas/aws-dd-forwarder-3.127.0/attrs/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/setters.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/setters.py
new file mode 100644
index 0000000..f3d73bb
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/setters.py
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+from attr.setters import * # noqa: F403
diff --git a/lambdas/aws-dd-forwarder-3.127.0/attrs/validators.py b/lambdas/aws-dd-forwarder-3.127.0/attrs/validators.py
new file mode 100644
index 0000000..037e124
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/attrs/validators.py
@@ -0,0 +1,3 @@
+# SPDX-License-Identifier: MIT
+
+from attr.validators import * # noqa: F403
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/ddtrace-run b/lambdas/aws-dd-forwarder-3.127.0/bin/ddtrace-run
new file mode 100755
index 0000000..0cc0787
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/ddtrace-run
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- coding: utf-8 -*-
+import re
+import sys
+from ddtrace.commands.ddtrace_run import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/dog b/lambdas/aws-dd-forwarder-3.127.0/bin/dog
new file mode 100755
index 0000000..7111893
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/dog
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- coding: utf-8 -*-
+import re
+import sys
+from datadog.dogshell import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/dogshell b/lambdas/aws-dd-forwarder-3.127.0/bin/dogshell
new file mode 100755
index 0000000..7111893
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/dogshell
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- coding: utf-8 -*-
+import re
+import sys
+from datadog.dogshell import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/dogshellwrap b/lambdas/aws-dd-forwarder-3.127.0/bin/dogshellwrap
new file mode 100755
index 0000000..5be900e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/dogshellwrap
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- coding: utf-8 -*-
+import re
+import sys
+from datadog.dogshell.wrap import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/dogwrap b/lambdas/aws-dd-forwarder-3.127.0/bin/dogwrap
new file mode 100755
index 0000000..5be900e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/dogwrap
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- coding: utf-8 -*-
+import re
+import sys
+from datadog.dogshell.wrap import main
+if __name__ == '__main__':
+ sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
+ sys.exit(main())
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bin/normalizer b/lambdas/aws-dd-forwarder-3.127.0/bin/normalizer
new file mode 100755
index 0000000..aae4757
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bin/normalizer
@@ -0,0 +1,8 @@
+#!/usr/local/bin/python3.11
+# -*- 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/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/COPYING b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/COPYING
new file mode 100644
index 0000000..ba5a523
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/COPYING
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+Copyright Contributors to the bytecode project.
+
+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/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/METADATA
new file mode 100644
index 0000000..19faf45
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/METADATA
@@ -0,0 +1,102 @@
+Metadata-Version: 2.1
+Name: bytecode
+Version: 0.15.1
+Summary: Python module to generate and modify bytecode
+Author-email: Victor Stinner
+Maintainer-email: "Matthieu C. Dartiailh"
+License: The MIT License (MIT)
+ Copyright Contributors to the bytecode project.
+
+ 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.
+
+Project-URL: homepage, https://github.com/MatthieuDartiailh/bytecode
+Project-URL: documentation, https://bytecode.readthedocs.io/en/latest/
+Project-URL: repository, https://github.com/MatthieuDartiailh/bytecode
+Project-URL: changelog, https://github.com/MatthieuDartiailh/bytecode/blob/main/doc/changelog.rst
+Classifier: Development Status :: 4 - Beta
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+Classifier: Natural Language :: English
+Classifier: Operating System :: OS Independent
+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 :: Software Development :: Libraries :: Python Modules
+Requires-Python: >=3.8
+Description-Content-Type: text/x-rst
+License-File: COPYING
+Requires-Dist: typing-extensions ; python_version < "3.10"
+
+********
+bytecode
+********
+
+.. image:: https://img.shields.io/pypi/v/bytecode.svg
+ :alt: Latest release on the Python Cheeseshop (PyPI)
+ :target: https://pypi.python.org/pypi/bytecode
+
+.. image:: https://github.com/MatthieuDartiailh/bytecode/workflows/Continuous%20Integration/badge.svg
+ :target: https://github.com/MatthieuDartiailh/bytecode/actions
+ :alt: Continuous integration
+
+.. image:: https://github.com/MatthieuDartiailh/bytecode/workflows/Documentation%20building/badge.svg
+ :target: https://github.com/MatthieuDartiailh/bytecode/actions
+ :alt: Documentation building
+
+.. image:: https://img.shields.io/codecov/c/github/MatthieuDartiailh/bytecode/master.svg
+ :alt: Code coverage of bytecode on codecov.io
+ :target: https://codecov.io/github/MatthieuDartiailh/bytecode
+
+.. image:: https://img.shields.io/badge/code%20style-black-000000.svg
+ :alt: Code formatted using Black
+ :target: https://github.com/psf/black
+
+``bytecode`` is a Python module to generate and modify bytecode.
+
+* `bytecode project homepage at GitHub
+ `_ (code, bugs)
+* `bytecode documentation
+ `_
+* `Download latest bytecode release at the Python Cheeseshop (PyPI)
+ `_
+
+Install bytecode: ``python3 -m pip install bytecode``. It requires Python 3.8
+or newer. The latest release that supports Python 3.7 and 3.6 is 0.13.0.
+The latest release that supports Python 3.5 is 0.12.0. For Python 2.7 support,
+have a look at `dead-bytecode `_
+instead.
+
+Example executing ``print('Hello World!')``:
+
+.. code:: python
+
+ from bytecode import Instr, Bytecode
+
+ bytecode = Bytecode([Instr("LOAD_NAME", 'print'),
+ Instr("LOAD_CONST", 'Hello World!'),
+ Instr("CALL_FUNCTION", 1),
+ Instr("POP_TOP"),
+ Instr("LOAD_CONST", None),
+ Instr("RETURN_VALUE")])
+ code = bytecode.to_code()
+ exec(code)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/RECORD
new file mode 100644
index 0000000..49b55cf
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/RECORD
@@ -0,0 +1,22 @@
+bytecode-0.15.1.dist-info/COPYING,sha256=15CDvwHVcioF_s6S_mWdkWdw96tvB21WZKc8jvc8N5M,1094
+bytecode-0.15.1.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+bytecode-0.15.1.dist-info/METADATA,sha256=btrMOPa27_H0V6neBiLPJiunLrto9ukEE-PWoTtFGvM,4627
+bytecode-0.15.1.dist-info/RECORD,,
+bytecode-0.15.1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+bytecode-0.15.1.dist-info/WHEEL,sha256=yQN5g4mg4AybRjkgi-9yy4iQEFibGQmlz78Pik5Or-A,92
+bytecode-0.15.1.dist-info/top_level.txt,sha256=9BhdB7HqYZ-PvHNoWX6ilwLYWQqcgEOLwdb3aXm5Gys,9
+bytecode/__init__.py,sha256=lsE6qqd_1wYjGq6s3q1Rhz1AyAjf98F4iJSrfg01F3k,6919
+bytecode/__pycache__/__init__.cpython-311.pyc,,
+bytecode/__pycache__/bytecode.cpython-311.pyc,,
+bytecode/__pycache__/cfg.cpython-311.pyc,,
+bytecode/__pycache__/concrete.cpython-311.pyc,,
+bytecode/__pycache__/flags.cpython-311.pyc,,
+bytecode/__pycache__/instr.cpython-311.pyc,,
+bytecode/__pycache__/version.cpython-311.pyc,,
+bytecode/bytecode.py,sha256=6oveflTRGnrzTQEP9Z0tp6ySwmXQ_DXIibdAGOZt5lY,11126
+bytecode/cfg.py,sha256=J0FOZD1n-LbPLGmPRggmj_1SxWZvcQQbuXeUDskRDv8,41785
+bytecode/concrete.py,sha256=NVsAef1Ya5MvhZfx0xKclP4eearg7vAixY2RpHtQFhk,52168
+bytecode/flags.py,sha256=eY4nrTIDkOBYswI-wXQ-p3mKfriH7pUNYaDien4OI6g,6189
+bytecode/instr.py,sha256=2fynmuZq46eXDyzIMS1e3wzGpXnm7BuY7rHGSsFkh7U,26777
+bytecode/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+bytecode/version.py,sha256=kz4YxQj6evqzVm2eaPEN9t8SwhJI1_YkLx-G2dMjhoI,519
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/WHEEL
new file mode 100644
index 0000000..7e68873
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: bdist_wheel (0.41.2)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/top_level.txt b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/top_level.txt
new file mode 100644
index 0000000..b37707e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode-0.15.1.dist-info/top_level.txt
@@ -0,0 +1 @@
+bytecode
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/__init__.py
new file mode 100644
index 0000000..11eb7d6
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/__init__.py
@@ -0,0 +1,218 @@
+__all__ = [
+ "Label",
+ "Instr",
+ "SetLineno",
+ "Bytecode",
+ "ConcreteInstr",
+ "ConcreteBytecode",
+ "ControlFlowGraph",
+ "CompilerFlags",
+ "Compare",
+ "BinaryOp",
+ "__version__",
+]
+
+from io import StringIO
+from typing import List, Union
+
+# import needed to use it in bytecode.py
+from bytecode.bytecode import ( # noqa
+ BaseBytecode,
+ Bytecode,
+ _BaseBytecodeList,
+ _InstrList,
+)
+
+# import needed to use it in bytecode.py
+from bytecode.cfg import BasicBlock, ControlFlowGraph # noqa
+
+# import needed to use it in bytecode.py
+from bytecode.concrete import _ConvertBytecodeToConcrete # noqa
+from bytecode.concrete import ConcreteBytecode, ConcreteInstr
+from bytecode.flags import CompilerFlags
+
+# import needed to use it in bytecode.py
+from bytecode.instr import ( # noqa
+ UNSET,
+ BinaryOp,
+ CellVar,
+ Compare,
+ FreeVar,
+ Instr,
+ Intrinsic1Op,
+ Intrinsic2Op,
+ Label,
+ SetLineno,
+ TryBegin,
+ TryEnd,
+)
+from bytecode.version import __version__
+
+
+def format_bytecode(
+ bytecode: Union[Bytecode, ConcreteBytecode, ControlFlowGraph],
+ *,
+ lineno: bool = False,
+) -> str:
+ try_begins: List[TryBegin] = []
+
+ def format_line(index, line):
+ nonlocal cur_lineno, prev_lineno
+ if lineno:
+ if cur_lineno != prev_lineno:
+ line = "L.% 3s % 3s: %s" % (cur_lineno, index, line)
+ prev_lineno = cur_lineno
+ else:
+ line = " % 3s: %s" % (index, line)
+ else:
+ line = line
+ return line
+
+ def format_instr(instr, labels=None):
+ text = instr.name
+ arg = instr._arg
+ if arg is not UNSET:
+ if isinstance(arg, Label):
+ try:
+ arg = "<%s>" % labels[arg]
+ except KeyError:
+ arg = ""
+ elif isinstance(arg, BasicBlock):
+ try:
+ arg = "<%s>" % labels[id(arg)]
+ except KeyError:
+ arg = ""
+ else:
+ arg = repr(arg)
+ text = "%s %s" % (text, arg)
+ return text
+
+ def format_try_begin(instr: TryBegin, labels: dict) -> str:
+ if isinstance(instr.target, Label):
+ try:
+ arg = "<%s>" % labels[instr.target]
+ except KeyError:
+ arg = ""
+ else:
+ try:
+ arg = "<%s>" % labels[id(instr.target)]
+ except KeyError:
+ arg = ""
+ line = "TryBegin %s -> %s [%s]" % (
+ len(try_begins),
+ arg,
+ instr.stack_depth,
+ ) + (" last_i" if instr.push_lasti else "")
+
+ # Track the seen try begin
+ try_begins.append(instr)
+
+ return line
+
+ def format_try_end(instr: TryEnd) -> str:
+ i = try_begins.index(instr.entry) if instr.entry in try_begins else ""
+ return "TryEnd (%s)" % i
+
+ buffer = StringIO()
+
+ indent = " " * 4
+
+ cur_lineno = bytecode.first_lineno
+ prev_lineno = None
+
+ if isinstance(bytecode, ConcreteBytecode):
+ offset = 0
+ for c_instr in bytecode:
+ fields = []
+ if c_instr.lineno is not None:
+ cur_lineno = c_instr.lineno
+ if lineno:
+ fields.append(format_instr(c_instr))
+ line = "".join(fields)
+ line = format_line(offset, line)
+ else:
+ fields.append("% 3s %s" % (offset, format_instr(c_instr)))
+ line = "".join(fields)
+ buffer.write(line + "\n")
+
+ if isinstance(c_instr, ConcreteInstr):
+ offset += c_instr.size
+
+ if bytecode.exception_table:
+ buffer.write("\n")
+ buffer.write("Exception table:\n")
+ for entry in bytecode.exception_table:
+ buffer.write(
+ f"{entry.start_offset} to {entry.stop_offset} -> "
+ f"{entry.target} [{entry.stack_depth}]"
+ + (" lasti" if entry.push_lasti else "")
+ + "\n"
+ )
+
+ elif isinstance(bytecode, Bytecode):
+ labels: dict[Label, str] = {}
+ for index, instr in enumerate(bytecode):
+ if isinstance(instr, Label):
+ labels[instr] = "label_instr%s" % index
+
+ for index, instr in enumerate(bytecode):
+ if isinstance(instr, Label):
+ label = labels[instr]
+ line = "%s:" % label
+ if index != 0:
+ buffer.write("\n")
+ elif isinstance(instr, TryBegin):
+ line = indent + format_line(index, format_try_begin(instr, labels))
+ indent += " "
+ elif isinstance(instr, TryEnd):
+ indent = indent[:-2]
+ line = indent + format_line(index, format_try_end(instr))
+ else:
+ if instr.lineno is not None:
+ cur_lineno = instr.lineno
+ line = format_instr(instr, labels)
+ line = indent + format_line(index, line)
+ buffer.write(line + "\n")
+ buffer.write("\n")
+
+ elif isinstance(bytecode, ControlFlowGraph):
+ cfg_labels = {}
+ for block_index, block in enumerate(bytecode, 1):
+ cfg_labels[id(block)] = "block%s" % block_index
+
+ for block_index, block in enumerate(bytecode, 1):
+ buffer.write("%s:\n" % cfg_labels[id(block)])
+ seen_instr = False
+ for index, instr in enumerate(block):
+ if isinstance(instr, TryBegin):
+ line = indent + format_line(
+ index, format_try_begin(instr, cfg_labels)
+ )
+ indent += " "
+ elif isinstance(instr, TryEnd):
+ if seen_instr:
+ indent = indent[:-2]
+ line = indent + format_line(index, format_try_end(instr))
+ else:
+ if isinstance(instr, Instr):
+ seen_instr = True
+ if instr.lineno is not None:
+ cur_lineno = instr.lineno
+ line = format_instr(instr, cfg_labels)
+ line = indent + format_line(index, line)
+ buffer.write(line + "\n")
+ if block.next_block is not None:
+ buffer.write(indent + "-> %s\n" % cfg_labels[id(block.next_block)])
+ buffer.write("\n")
+ else:
+ raise TypeError("unknown bytecode class")
+
+ return buffer.getvalue()[:-1]
+
+
+def dump_bytecode(
+ bytecode: Union[Bytecode, ConcreteBytecode, ControlFlowGraph],
+ *,
+ lineno: bool = False,
+) -> None:
+ print(format_bytecode(bytecode, lineno=lineno))
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/bytecode.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/bytecode.py
new file mode 100644
index 0000000..149bb37
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/bytecode.py
@@ -0,0 +1,330 @@
+# alias to keep the 'bytecode' variable free
+import sys
+import types
+from abc import abstractmethod
+from typing import (
+ Any,
+ Dict,
+ Generic,
+ Iterator,
+ List,
+ Optional,
+ Sequence,
+ SupportsIndex,
+ TypeVar,
+ Union,
+ overload,
+)
+
+import bytecode as _bytecode
+from bytecode.flags import CompilerFlags, infer_flags
+from bytecode.instr import (
+ _UNSET,
+ UNSET,
+ BaseInstr,
+ Instr,
+ Label,
+ SetLineno,
+ TryBegin,
+ TryEnd,
+)
+
+
+class BaseBytecode:
+ def __init__(self) -> None:
+ self.argcount = 0
+ self.posonlyargcount = 0
+ self.kwonlyargcount = 0
+ self.first_lineno = 1
+ self.name = ""
+ self.qualname = self.name
+ self.filename = ""
+ self.docstring: Union[str, None, _UNSET] = UNSET
+ # We cannot recreate cellvars/freevars from instructions because of super()
+ # special-case, which involves an implicit __class__ cell/free variable
+ # We could try to detect it.
+ # CPython itself breaks if one aliases super so we could maybe make it work
+ # but it will require careful design and will be done later in the future.
+ self.cellvars: List[str] = []
+ self.freevars: List[str] = []
+ self._flags: CompilerFlags = CompilerFlags(0)
+
+ def _copy_attr_from(self, bytecode: "BaseBytecode") -> None:
+ self.argcount = bytecode.argcount
+ self.posonlyargcount = bytecode.posonlyargcount
+ self.kwonlyargcount = bytecode.kwonlyargcount
+ self.flags = bytecode.flags
+ self.first_lineno = bytecode.first_lineno
+ self.name = bytecode.name
+ self.qualname = bytecode.qualname
+ self.filename = bytecode.filename
+ self.docstring = bytecode.docstring
+ self.cellvars = list(bytecode.cellvars)
+ self.freevars = list(bytecode.freevars)
+
+ def __eq__(self, other: Any) -> bool:
+ if type(self) is not type(other):
+ return False
+
+ if self.argcount != other.argcount:
+ return False
+ if self.posonlyargcount != other.posonlyargcount:
+ return False
+ if self.kwonlyargcount != other.kwonlyargcount:
+ return False
+ if self.flags != other.flags:
+ return False
+ if self.first_lineno != other.first_lineno:
+ return False
+ if self.filename != other.filename:
+ return False
+ if self.name != other.name:
+ return False
+ if self.qualname != other.qualname:
+ return False
+ if self.docstring != other.docstring:
+ return False
+ if self.cellvars != other.cellvars:
+ return False
+ if self.freevars != other.freevars:
+ return False
+ if self.compute_stacksize() != other.compute_stacksize():
+ return False
+
+ return True
+
+ @property
+ def flags(self) -> CompilerFlags:
+ return self._flags
+
+ @flags.setter
+ def flags(self, value: CompilerFlags) -> None:
+ if not isinstance(value, CompilerFlags):
+ value = CompilerFlags(value)
+ self._flags = value
+
+ def update_flags(self, *, is_async: Optional[bool] = None) -> None:
+ # infer_flags reasonably only accept concrete subclasses
+ self.flags = infer_flags(self, is_async) # type: ignore
+
+ @abstractmethod
+ def compute_stacksize(self, *, check_pre_and_post: bool = True) -> int:
+ raise NotImplementedError
+
+
+T = TypeVar("T", bound="_BaseBytecodeList")
+U = TypeVar("U")
+
+
+class _BaseBytecodeList(BaseBytecode, list, Generic[U]):
+ """List subclass providing type stable slicing and copying."""
+
+ @overload
+ def __getitem__(self, index: SupportsIndex) -> U:
+ ...
+
+ @overload
+ def __getitem__(self: T, index: slice) -> T:
+ ...
+
+ def __getitem__(self, index):
+ value = super().__getitem__(index)
+ if isinstance(index, slice):
+ value = type(self)(value)
+ value._copy_attr_from(self)
+
+ return value
+
+ def copy(self: T) -> T:
+ # This is a list subclass and works
+ new = type(self)(super().copy()) # type: ignore
+ new._copy_attr_from(self)
+ return new
+
+ def legalize(self) -> None:
+ """Check that all the element of the list are valid and remove SetLineno."""
+ lineno_pos = []
+ set_lineno = None
+ current_lineno = self.first_lineno
+
+ for pos, instr in enumerate(self):
+ if isinstance(instr, SetLineno):
+ set_lineno = instr.lineno
+ lineno_pos.append(pos)
+ continue
+ # Filter out other pseudo instructions
+ if not isinstance(instr, BaseInstr):
+ continue
+ if set_lineno is not None:
+ instr.lineno = set_lineno
+ elif instr.lineno is UNSET:
+ instr.lineno = current_lineno
+ elif instr.lineno is not None:
+ current_lineno = instr.lineno
+
+ for i in reversed(lineno_pos):
+ del self[i]
+
+ def __iter__(self) -> Iterator[U]:
+ instructions = super().__iter__()
+ for instr in instructions:
+ self._check_instr(instr)
+ yield instr
+
+ def _check_instr(self, instr):
+ raise NotImplementedError()
+
+
+V = TypeVar("V")
+
+
+class _InstrList(List[V]):
+ # Providing a stricter typing for this helper whose use is limited to the __eq__
+ # implementation is more effort than it is worth.
+ def _flat(self) -> List:
+ instructions: List = []
+ labels = {}
+ jumps = []
+ try_begins: Dict[TryBegin, int] = {}
+ try_jumps = []
+
+ offset = 0
+ instr: Any
+ for index, instr in enumerate(self):
+ if isinstance(instr, Label):
+ instructions.append("label_instr%s" % index)
+ labels[instr] = offset
+ elif isinstance(instr, TryBegin):
+ try_begins.setdefault(instr, len(try_begins))
+ assert isinstance(instr.target, Label)
+ try_jumps.append((instr.target, len(instructions)))
+ instructions.append(instr)
+ elif isinstance(instr, TryEnd):
+ instructions.append(("TryEnd", try_begins[instr.entry]))
+ else:
+ if isinstance(instr, Instr) and isinstance(instr.arg, Label):
+ target_label = instr.arg
+ instr = _bytecode.ConcreteInstr(
+ instr.name, 0, location=instr.location
+ )
+ jumps.append((target_label, instr))
+ instructions.append(instr)
+ offset += 1
+
+ for target_label, instr in jumps:
+ instr.arg = labels[target_label]
+
+ for target_label, index in try_jumps:
+ instr = instructions[index]
+ assert isinstance(instr, TryBegin)
+ instructions[index] = (
+ "TryBegin",
+ try_begins[instr],
+ labels[target_label],
+ instr.push_lasti,
+ )
+
+ return instructions
+
+ def __eq__(self, other: Any) -> bool:
+ if not isinstance(other, _InstrList):
+ other = _InstrList(other)
+
+ return self._flat() == other._flat()
+
+
+class Bytecode(
+ _InstrList[Union[Instr, Label, TryBegin, TryEnd, SetLineno]],
+ _BaseBytecodeList[Union[Instr, Label, TryBegin, TryEnd, SetLineno]],
+):
+ def __init__(
+ self,
+ instructions: Sequence[Union[Instr, Label, TryBegin, TryEnd, SetLineno]] = (),
+ ) -> None:
+ BaseBytecode.__init__(self)
+ self.argnames: List[str] = []
+ for instr in instructions:
+ self._check_instr(instr)
+ self.extend(instructions)
+
+ def __iter__(self) -> Iterator[Union[Instr, Label, TryBegin, TryEnd, SetLineno]]:
+ instructions = super().__iter__()
+ seen_try_begin = False
+ for instr in instructions:
+ self._check_instr(instr)
+ if isinstance(instr, TryBegin):
+ if seen_try_begin:
+ raise RuntimeError("TryBegin pseudo instructions cannot be nested.")
+ seen_try_begin = True
+ elif isinstance(instr, TryEnd):
+ seen_try_begin = False
+ yield instr
+
+ def _check_instr(self, instr: Any) -> None:
+ if not isinstance(instr, (Label, SetLineno, Instr, TryBegin, TryEnd)):
+ raise ValueError(
+ "Bytecode must only contain Label, "
+ "SetLineno, and Instr objects, "
+ "but %s was found" % type(instr).__name__
+ )
+
+ def _copy_attr_from(self, bytecode: BaseBytecode) -> None:
+ super()._copy_attr_from(bytecode)
+ if isinstance(bytecode, Bytecode):
+ self.argnames = bytecode.argnames
+
+ @staticmethod
+ def from_code(
+ code: types.CodeType,
+ prune_caches: bool = True,
+ conserve_exception_block_stackdepth: bool = False,
+ ) -> "Bytecode":
+ concrete = _bytecode.ConcreteBytecode.from_code(code)
+ return concrete.to_bytecode(
+ prune_caches=prune_caches,
+ conserve_exception_block_stackdepth=conserve_exception_block_stackdepth,
+ )
+
+ def compute_stacksize(self, *, check_pre_and_post: bool = True) -> int:
+ cfg = _bytecode.ControlFlowGraph.from_bytecode(self)
+ return cfg.compute_stacksize(check_pre_and_post=check_pre_and_post)
+
+ def to_code(
+ self,
+ compute_jumps_passes: Optional[int] = None,
+ stacksize: Optional[int] = None,
+ *,
+ check_pre_and_post: bool = True,
+ compute_exception_stack_depths: bool = True,
+ ) -> types.CodeType:
+ # Prevent reconverting the concrete bytecode to bytecode and cfg to do the
+ # calculation if we need to do it.
+ if stacksize is None or (
+ sys.version_info >= (3, 11) and compute_exception_stack_depths
+ ):
+ cfg = _bytecode.ControlFlowGraph.from_bytecode(self)
+ stacksize = cfg.compute_stacksize(
+ check_pre_and_post=check_pre_and_post,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
+ self = cfg.to_bytecode()
+ compute_exception_stack_depths = False # avoid redoing everything
+ bc = self.to_concrete_bytecode(
+ compute_jumps_passes=compute_jumps_passes,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
+ return bc.to_code(
+ stacksize=stacksize,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
+
+ def to_concrete_bytecode(
+ self,
+ compute_jumps_passes: Optional[int] = None,
+ compute_exception_stack_depths: bool = True,
+ ) -> "_bytecode.ConcreteBytecode":
+ converter = _bytecode._ConvertBytecodeToConcrete(self)
+ return converter.to_concrete_bytecode(
+ compute_jumps_passes=compute_jumps_passes,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/cfg.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/cfg.py
new file mode 100644
index 0000000..7f554fa
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/cfg.py
@@ -0,0 +1,1061 @@
+import sys
+import types
+from collections import defaultdict
+from dataclasses import dataclass
+from typing import (
+ Any,
+ Dict,
+ Generator,
+ Iterable,
+ Iterator,
+ List,
+ Optional,
+ Set,
+ SupportsIndex,
+ Tuple,
+ TypeVar,
+ Union,
+ overload,
+)
+
+# alias to keep the 'bytecode' variable free
+import bytecode as _bytecode
+from bytecode.concrete import ConcreteInstr
+from bytecode.flags import CompilerFlags
+from bytecode.instr import UNSET, Instr, Label, SetLineno, TryBegin, TryEnd
+
+T = TypeVar("T", bound="BasicBlock")
+U = TypeVar("U", bound="ControlFlowGraph")
+
+
+class BasicBlock(_bytecode._InstrList[Union[Instr, SetLineno, TryBegin, TryEnd]]):
+ def __init__(
+ self,
+ instructions: Optional[
+ Iterable[Union[Instr, SetLineno, TryBegin, TryEnd]]
+ ] = None,
+ ) -> None:
+ # a BasicBlock object, or None
+ self.next_block: Optional["BasicBlock"] = None
+ if instructions:
+ super().__init__(instructions)
+
+ def __iter__(self) -> Iterator[Union[Instr, SetLineno, TryBegin, TryEnd]]:
+ index = 0
+ while index < len(self):
+ instr = self[index]
+ index += 1
+
+ if not isinstance(instr, (SetLineno, Instr, TryBegin, TryEnd)):
+ raise ValueError(
+ "BasicBlock must only contain SetLineno and Instr objects, "
+ "but %s was found" % instr.__class__.__name__
+ )
+
+ if isinstance(instr, Instr) and instr.has_jump():
+ if index < len(self) and any(
+ isinstance(self[i], Instr) for i in range(index, len(self))
+ ):
+ raise ValueError(
+ "Only the last instruction of a basic " "block can be a jump"
+ )
+
+ if not isinstance(instr.arg, BasicBlock):
+ raise ValueError(
+ "Jump target must a BasicBlock, got %s",
+ type(instr.arg).__name__,
+ )
+
+ if isinstance(instr, TryBegin):
+ if not isinstance(instr.target, BasicBlock):
+ raise ValueError(
+ "TryBegin target must a BasicBlock, got %s",
+ type(instr.target).__name__,
+ )
+
+ yield instr
+
+ @overload
+ def __getitem__(
+ self, index: SupportsIndex
+ ) -> Union[Instr, SetLineno, TryBegin, TryEnd]:
+ ...
+
+ @overload
+ def __getitem__(self: T, index: slice) -> T:
+ ...
+
+ def __getitem__(self, index):
+ value = super().__getitem__(index)
+ if isinstance(index, slice):
+ value = type(self)(value)
+ value.next_block = self.next_block
+
+ return value
+
+ def get_last_non_artificial_instruction(self) -> Optional[Instr]:
+ for instr in reversed(self):
+ if isinstance(instr, Instr):
+ return instr
+
+ return None
+
+ def copy(self: T) -> T:
+ new = type(self)(super().copy())
+ new.next_block = self.next_block
+ return new
+
+ def legalize(self, first_lineno: int) -> int:
+ """Check that all the element of the list are valid and remove SetLineno."""
+ lineno_pos = []
+ set_lineno = None
+ current_lineno = first_lineno
+
+ for pos, instr in enumerate(self):
+ if isinstance(instr, SetLineno):
+ set_lineno = current_lineno = instr.lineno
+ lineno_pos.append(pos)
+ continue
+ if isinstance(instr, (TryBegin, TryEnd)):
+ continue
+
+ if set_lineno is not None:
+ instr.lineno = set_lineno
+ elif instr.lineno is UNSET:
+ instr.lineno = current_lineno
+ elif instr.lineno is not None:
+ current_lineno = instr.lineno
+
+ for i in reversed(lineno_pos):
+ del self[i]
+
+ return current_lineno
+
+ def get_jump(self) -> Optional["BasicBlock"]:
+ if not self:
+ return None
+
+ last_instr = self.get_last_non_artificial_instruction()
+ if last_instr is None or not last_instr.has_jump():
+ return None
+
+ target_block = last_instr.arg
+ assert isinstance(target_block, BasicBlock)
+ return target_block
+
+ def get_trailing_try_end(self, index: int):
+ while index + 1 < len(self):
+ if isinstance(b := self[index + 1], TryEnd):
+ return b
+ index += 1
+
+ return None
+
+
+def _update_size(pre_delta, post_delta, size, maxsize, minsize):
+ size += pre_delta
+ if size < 0:
+ msg = "Failed to compute stacksize, got negative size"
+ raise RuntimeError(msg)
+ size += post_delta
+ maxsize = max(maxsize, size)
+ minsize = min(minsize, size)
+ return size, maxsize, minsize
+
+
+# We can never have nested TryBegin, so we can simply update the min stack size
+# when we encounter one and use the number we have when we encounter the TryEnd
+
+
+@dataclass
+class _StackSizeComputationStorage:
+ """Common storage shared by the computers involved in computing CFG stack usage."""
+
+ #: Should we check that all stack operation are "safe" i.e. occurs while there
+ #: is a sufficient number of items on the stack.
+ check_pre_and_post: bool
+
+ #: Id the blocks for which an analysis is under progress to avoid getting stuck
+ #: in recursions.
+ seen_blocks: Set[int]
+
+ #: Sizes and exception handling status with which the analysis of the block
+ #: has been performed. Used to avoid running multiple times equivalent analysis.
+ blocks_startsizes: Dict[int, Set[Tuple[int, Optional[bool]]]]
+
+ #: Track the encountered TryBegin pseudo-instruction to update their target
+ #: depth at the end of the calculation.
+ try_begins: List[TryBegin]
+
+ #: Stacksize that should be used for exception blocks. This is the smallest size
+ #: with which this block was reached which is the only size that can be safely
+ #: restored.
+ exception_block_startsize: Dict[int, int]
+
+ #: Largest stack size used in an exception block. We record the size corresponding
+ #: to the smallest start size for the block since the interpreter enforces that
+ #: we start with this size.
+ exception_block_maxsize: Dict[int, int]
+
+
+class _StackSizeComputer:
+ """Helper computing the stack usage for a single block."""
+
+ #: Common storage shared by all helpers involved in the stack size computation
+ common: _StackSizeComputationStorage
+
+ #: Block this helper is running the computation for.
+ block: BasicBlock
+
+ #: Current stack usage.
+ size: int
+
+ #: Maximal stack usage.
+ maxsize: int
+
+ #: Minimal stack usage. This value is only relevant in between a TryBegin/TryEnd
+ #: pair and determine the startsize for the exception handling block associated
+ #: with the try begin.
+ minsize: int
+
+ #: Flag indicating if the block analyzed is an exception handler (i.e. a target
+ #: of a TryBegin).
+ exception_handler: Optional[bool]
+
+ #: TryBegin that was encountered before jumping to this block and for which
+ #: no try end was met yet.
+ pending_try_begin: Optional[TryBegin]
+
+ def __init__(
+ self,
+ common: _StackSizeComputationStorage,
+ block: BasicBlock,
+ size: int,
+ maxsize: int,
+ minsize: int,
+ exception_handler: Optional[bool],
+ pending_try_begin: Optional[TryBegin],
+ ) -> None:
+ self.common = common
+ self.block = block
+ self.size = size
+ self.maxsize = maxsize
+ self.minsize = minsize
+ self.exception_handler = exception_handler
+ self.pending_try_begin = pending_try_begin
+ self._current_try_begin = pending_try_begin
+
+ def run(self) -> Generator[Union["_StackSizeComputer", int], int, None]:
+ """Iterate over the block instructions to compute stack usage."""
+ # Blocks are not hashable but in this particular context we know we won't be
+ # modifying blocks in place so we can safely use their id as hash rather than
+ # making them generally hashable which would be weird since they are list
+ # subclasses
+ block_id = id(self.block)
+
+ # If the block is currently being visited (seen = True) or
+ # it was visited previously with parameters that makes the computation
+ # irrelevant return the maxsize.
+ fingerprint = (self.size, self.exception_handler)
+ if id(self.block) in self.common.seen_blocks or (
+ not self._is_stacksize_computation_relevant(block_id, fingerprint)
+ ):
+ yield self.maxsize
+
+ # Prevent recursive visit of block if two blocks are nested (jump from one
+ # to the other).
+ self.common.seen_blocks.add(block_id)
+
+ # Track which size has been used to run an analysis to avoid re-running multiple
+ # times the same calculation.
+ self.common.blocks_startsizes[block_id].add(fingerprint)
+
+ # If this block is an exception handler reached through the exception table
+ # we will push some extra objects on the stack before processing start.
+ if self.exception_handler is not None:
+ self._update_size(0, 1 + self.exception_handler)
+ # True is used to indicated that push_lasti is True, leading to pushing
+ # an extra object on the stack.
+
+ for i, instr in enumerate(self.block):
+ # Ignore SetLineno
+ if isinstance(instr, (SetLineno)):
+ continue
+
+ # When we encounter a TryBegin, we:
+ # - store it as the current TryBegin (since TryBegin cannot be nested)
+ # - record its existence to remember to update its stack size when
+ # the computation ends
+ # - update the minsize to the current size value since we need to
+ # know the minimal stack usage between the TryBegin/TryEnd pair to
+ # set the startsize of the exception handling block
+ #
+ # This approach does not require any special handling for with statements.
+ if isinstance(instr, TryBegin):
+ assert self._current_try_begin is None
+ self.common.try_begins.append(instr)
+ self._current_try_begin = instr
+ self.minsize = self.size
+
+ continue
+
+ elif isinstance(instr, TryEnd):
+ # When we encounter a TryEnd we can start the computation for the
+ # exception block using the minimum stack size encountered since
+ # the TryBegin matching this TryEnd.
+
+ # TryBegin cannot be nested so a TryEnd should always match the
+ # current try begin. However inside the CFG some blocks may
+ # start with a TryEnd relevant only when reaching this block
+ # through a particular jump. So we are lenient here.
+ if instr.entry is not self._current_try_begin:
+ continue
+
+ # Compute the stack usage of the exception handler
+ assert isinstance(instr.entry.target, BasicBlock)
+ yield from self._compute_exception_handler_stack_usage(
+ instr.entry.target,
+ instr.entry.push_lasti,
+ )
+ self._current_try_begin = None
+ continue
+
+ # For instructions with a jump first compute the stacksize required when the
+ # jump is taken.
+ if instr.has_jump():
+ effect = (
+ instr.pre_and_post_stack_effect(jump=True)
+ if self.common.check_pre_and_post
+ else (instr.stack_effect(jump=True), 0)
+ )
+ taken_size, maxsize, minsize = _update_size(
+ *effect, self.size, self.maxsize, self.minsize
+ )
+
+ # Yield the parameters required to compute the stacksize required
+ # by the block to which the jump points to and resume when we now
+ # the maxsize.
+ assert isinstance(instr.arg, BasicBlock)
+ maxsize = yield _StackSizeComputer(
+ self.common,
+ instr.arg,
+ taken_size,
+ maxsize,
+ minsize,
+ None,
+ # Do not propagate the TryBegin if a final instruction is followed
+ # by a TryEnd.
+ None
+ if instr.is_final() and self.block.get_trailing_try_end(i)
+ else self._current_try_begin,
+ )
+
+ # Update the maximum used size by the usage implied by the following
+ # the jump
+ self.maxsize = max(self.maxsize, maxsize)
+
+ # For unconditional jumps abort early since the other instruction will
+ # never be seen.
+ if instr.is_uncond_jump():
+ # Check for TryEnd after the final instruction which is possible
+ # TryEnd being only pseudo instructions
+ if te := self.block.get_trailing_try_end(i):
+ # TryBegin cannot be nested
+ assert te.entry is self._current_try_begin
+
+ assert isinstance(te.entry.target, BasicBlock)
+ yield from self._compute_exception_handler_stack_usage(
+ te.entry.target,
+ te.entry.push_lasti,
+ )
+
+ self.common.seen_blocks.remove(id(self.block))
+ yield self.maxsize
+
+ # jump=False: non-taken path of jumps, or any non-jump
+ effect = (
+ instr.pre_and_post_stack_effect(jump=False)
+ if self.common.check_pre_and_post
+ else (instr.stack_effect(jump=False), 0)
+ )
+ self._update_size(*effect)
+
+ # Instruction is final (return, raise, ...) so any following instruction
+ # in the block is dead code.
+ if instr.is_final():
+ # Check for TryEnd after the final instruction which is possible
+ # TryEnd being only pseudo instructions.
+ if te := self.block.get_trailing_try_end(i):
+ assert isinstance(te.entry.target, BasicBlock)
+ yield from self._compute_exception_handler_stack_usage(
+ te.entry.target,
+ te.entry.push_lasti,
+ )
+
+ self.common.seen_blocks.remove(id(self.block))
+
+ yield self.maxsize
+
+ if self.block.next_block:
+ self.maxsize = yield _StackSizeComputer(
+ self.common,
+ self.block.next_block,
+ self.size,
+ self.maxsize,
+ self.minsize,
+ None,
+ self._current_try_begin,
+ )
+
+ self.common.seen_blocks.remove(id(self.block))
+
+ yield self.maxsize
+
+ # --- Private API
+
+ _current_try_begin: Optional[TryBegin]
+
+ def _update_size(self, pre_delta: int, post_delta: int) -> None:
+ size, maxsize, minsize = _update_size(
+ pre_delta, post_delta, self.size, self.maxsize, self.minsize
+ )
+ self.size = size
+ self.minsize = minsize
+ self.maxsize = maxsize
+
+ def _compute_exception_handler_stack_usage(
+ self, block: BasicBlock, push_lasti: bool
+ ) -> Generator[Union["_StackSizeComputer", int], int, None]:
+ b_id = id(block)
+ if self.minsize < self.common.exception_block_startsize[b_id]:
+ block_size = yield _StackSizeComputer(
+ self.common,
+ block,
+ self.minsize,
+ self.maxsize,
+ self.minsize,
+ push_lasti,
+ None,
+ )
+ # The entry cannot be smaller than abs(stc.minimal_entry_size) as otherwise
+ # we an underflow would have occured.
+ self.common.exception_block_startsize[b_id] = self.minsize
+ self.common.exception_block_maxsize[b_id] = block_size
+
+ def _is_stacksize_computation_relevant(
+ self, block_id: int, fingerprint: Tuple[int, Optional[bool]]
+ ) -> bool:
+ if sys.version_info >= (3, 11):
+ # The computation is relevant if the block was not visited previously
+ # with the same starting size and exception handler status than the
+ # one in use
+ return fingerprint not in self.common.blocks_startsizes[block_id]
+ else:
+ # The computation is relevant if the block was only visited with smaller
+ # starting sizes than the one in use
+ if sizes := self.common.blocks_startsizes[block_id]:
+ return fingerprint[0] > max(f[0] for f in sizes)
+ else:
+ return True
+
+
+class ControlFlowGraph(_bytecode.BaseBytecode):
+ def __init__(self) -> None:
+ super().__init__()
+ self._blocks: List[BasicBlock] = []
+ self._block_index: Dict[int, int] = {}
+ self.argnames: List[str] = []
+
+ self.add_block()
+
+ def legalize(self) -> None:
+ """Legalize all blocks."""
+ current_lineno = self.first_lineno
+ for block in self._blocks:
+ current_lineno = block.legalize(current_lineno)
+
+ def get_block_index(self, block: BasicBlock) -> int:
+ try:
+ return self._block_index[id(block)]
+ except KeyError:
+ raise ValueError("the block is not part of this bytecode")
+
+ def _add_block(self, block: BasicBlock) -> None:
+ block_index = len(self._blocks)
+ self._blocks.append(block)
+ self._block_index[id(block)] = block_index
+
+ def add_block(
+ self, instructions: Optional[Iterable[Union[Instr, SetLineno]]] = None
+ ) -> BasicBlock:
+ block = BasicBlock(instructions)
+ self._add_block(block)
+ return block
+
+ def compute_stacksize(
+ self,
+ *,
+ check_pre_and_post: bool = True,
+ compute_exception_stack_depths: bool = True,
+ ) -> int:
+ """Compute the stack size by iterating through the blocks
+
+ The implementation make use of a generator function to avoid issue with
+ deeply nested recursions.
+
+ """
+ # In the absence of any block return 0
+ if not self:
+ return 0
+
+ # Create the common storage for the calculation
+ common = _StackSizeComputationStorage(
+ check_pre_and_post,
+ seen_blocks=set(),
+ blocks_startsizes={id(b): set() for b in self},
+ exception_block_startsize=dict.fromkeys([id(b) for b in self], 32768),
+ exception_block_maxsize=dict.fromkeys([id(b) for b in self], -32768),
+ try_begins=[],
+ )
+
+ # Starting with Python 3.10, generator and coroutines start with one object
+ # on the stack (None, anything is an error).
+ initial_stack_size = 0
+ if sys.version_info >= (3, 10) and self.flags & (
+ CompilerFlags.GENERATOR
+ | CompilerFlags.COROUTINE
+ | CompilerFlags.ASYNC_GENERATOR
+ ):
+ initial_stack_size = 1
+
+ # Create a generator/coroutine responsible of dealing with the first block
+ coro = _StackSizeComputer(
+ common, self[0], initial_stack_size, 0, 0, None, None
+ ).run()
+
+ # Create a list of generator that have not yet been exhausted
+ coroutines: List[Generator[Union[_StackSizeComputer, int], int, None]] = []
+
+ push_coroutine = coroutines.append
+ pop_coroutine = coroutines.pop
+ args = None
+
+ try:
+ while True:
+ # Mypy does not seem to honor the fact that one must send None
+ # to a brand new generator irrespective of its send type.
+ args = coro.send(None) # type: ignore
+
+ # Consume the stored generators as long as they return a simple
+ # integer that is to be used to resume the last stored generator.
+ while isinstance(args, int):
+ coro = pop_coroutine()
+ args = coro.send(args)
+
+ # Otherwise we enter a new block and we store the generator under
+ # use and create a new one to process the new block
+ push_coroutine(coro)
+ coro = args.run()
+
+ except IndexError:
+ # The exception occurs when all the generators have been exhausted
+ # in which case the last yielded value is the stacksize.
+ assert args is not None and isinstance(args, int)
+
+ # Exception handling block size is reported separately since we need
+ # to report only the stack usage for the smallest start size for the
+ # block
+ args = max(args, *common.exception_block_maxsize.values())
+
+ # Check if there is dead code that may contain TryBegin/TryEnd pairs.
+ # For any such pair we set a huge size (the exception table format does not
+ # mandate a maximum value). We do so so that if the pair is fused with
+ # another it does not alter the computed size.
+ for block in self:
+ if not common.blocks_startsizes[id(block)]:
+ for i in block:
+ if isinstance(i, TryBegin) and i.stack_depth is UNSET:
+ i.stack_depth = 32768
+
+ # If requested update the TryBegin stack size
+ if compute_exception_stack_depths:
+ for tb in common.try_begins:
+ size = common.exception_block_startsize[id(tb.target)]
+ assert size >= 0
+ tb.stack_depth = size
+
+ return args
+
+ def __repr__(self) -> str:
+ return "" % len(self._blocks)
+
+ # Helper to obtain a flat list of instr, which does not refer to block at
+ # anymore. Used for comparison of different CFG.
+ def _get_instructions(
+ self,
+ ) -> List:
+ instructions: List = []
+ try_begins: Dict[TryBegin, int] = {}
+
+ for block in self:
+ for index, instr in enumerate(block):
+ if isinstance(instr, TryBegin):
+ assert isinstance(instr.target, BasicBlock)
+ try_begins.setdefault(instr, len(try_begins))
+ instructions.append(
+ (
+ "TryBegin",
+ try_begins[instr],
+ self.get_block_index(instr.target),
+ instr.push_lasti,
+ )
+ )
+ elif isinstance(instr, TryEnd):
+ instructions.append(("TryEnd", try_begins[instr.entry]))
+ elif isinstance(instr, Instr) and (
+ instr.has_jump() or instr.is_final()
+ ):
+ if instr.has_jump():
+ target_block = instr.arg
+ assert isinstance(target_block, BasicBlock)
+ # We use a concrete instr here to be able to use an integer as
+ # argument rather than a Label. This is fine for comparison
+ # purposes which is our sole goal here.
+ c_instr = ConcreteInstr(
+ instr.name,
+ self.get_block_index(target_block),
+ location=instr.location,
+ )
+ instructions.append(c_instr)
+ else:
+ instructions.append(instr)
+
+ if te := block.get_trailing_try_end(index):
+ instructions.append(("TryEnd", try_begins[te.entry]))
+ break
+ else:
+ instructions.append(instr)
+
+ return instructions
+
+ def __eq__(self, other: Any) -> bool:
+ if type(self) is not type(other):
+ return False
+
+ if self.argnames != other.argnames:
+ return False
+
+ instrs1 = self._get_instructions()
+ instrs2 = other._get_instructions()
+ if instrs1 != instrs2:
+ return False
+ # FIXME: compare block.next_block
+
+ return super().__eq__(other)
+
+ def __len__(self) -> int:
+ return len(self._blocks)
+
+ def __iter__(self) -> Iterator[BasicBlock]:
+ return iter(self._blocks)
+
+ @overload
+ def __getitem__(self, index: Union[int, BasicBlock]) -> BasicBlock:
+ ...
+
+ @overload
+ def __getitem__(self: U, index: slice) -> U:
+ ...
+
+ def __getitem__(self, index):
+ if isinstance(index, BasicBlock):
+ index = self.get_block_index(index)
+ return self._blocks[index]
+
+ def __delitem__(self, index: Union[int, BasicBlock]) -> None:
+ if isinstance(index, BasicBlock):
+ index = self.get_block_index(index)
+ block = self._blocks[index]
+ del self._blocks[index]
+ del self._block_index[id(block)]
+ for index in range(index, len(self)):
+ block = self._blocks[index]
+ self._block_index[id(block)] -= 1
+
+ def split_block(self, block: BasicBlock, index: int) -> BasicBlock:
+ if not isinstance(block, BasicBlock):
+ raise TypeError("expected block")
+ block_index = self.get_block_index(block)
+
+ if index < 0:
+ raise ValueError("index must be positive")
+
+ block = self._blocks[block_index]
+ if index == 0:
+ return block
+
+ if index > len(block):
+ raise ValueError("index out of the block")
+
+ instructions = block[index:]
+ if not instructions:
+ if block_index + 1 < len(self):
+ return self[block_index + 1]
+
+ del block[index:]
+
+ block2 = BasicBlock(instructions)
+ block.next_block = block2
+
+ for block in self[block_index + 1 :]:
+ self._block_index[id(block)] += 1
+
+ self._blocks.insert(block_index + 1, block2)
+ self._block_index[id(block2)] = block_index + 1
+
+ return block2
+
+ def get_dead_blocks(self) -> List[BasicBlock]:
+ if not self:
+ return []
+
+ seen_block_ids = set()
+ stack = [self[0]]
+ while stack:
+ block = stack.pop()
+ if id(block) in seen_block_ids:
+ continue
+ seen_block_ids.add(id(block))
+ for i in block:
+ if isinstance(i, Instr) and isinstance(i.arg, BasicBlock):
+ stack.append(i.arg)
+ elif isinstance(i, TryBegin):
+ assert isinstance(i.target, BasicBlock)
+ stack.append(i.target)
+
+ return [b for b in self if id(b) not in seen_block_ids]
+
+ @staticmethod
+ def from_bytecode(bytecode: _bytecode.Bytecode) -> "ControlFlowGraph":
+ # label => instruction index
+ label_to_block_index = {}
+ jumps = []
+ try_end_locations = {}
+ for index, instr in enumerate(bytecode):
+ if isinstance(instr, Label):
+ label_to_block_index[instr] = index
+ elif isinstance(instr, Instr) and isinstance(instr.arg, Label):
+ jumps.append((index, instr.arg))
+ elif isinstance(instr, TryBegin):
+ assert isinstance(instr.target, Label)
+ jumps.append((index, instr.target))
+ elif isinstance(instr, TryEnd):
+ try_end_locations[instr.entry] = index
+
+ # Figure out on which index block targeted by a label start
+ block_starts = {}
+ for target_index, target_label in jumps:
+ target_index = label_to_block_index[target_label]
+ block_starts[target_index] = target_label
+
+ bytecode_blocks = ControlFlowGraph()
+ bytecode_blocks._copy_attr_from(bytecode)
+ bytecode_blocks.argnames = list(bytecode.argnames)
+
+ # copy instructions, convert labels to block labels
+ block = bytecode_blocks[0]
+ labels = {}
+ jumping_instrs: List[Instr] = []
+ # Map input TryBegin to CFG TryBegins (split across blocks may yield multiple
+ # TryBegin from a single in the bytecode).
+ try_begins: Dict[TryBegin, list[TryBegin]] = {}
+ # Storage for TryEnds that need to be inserted at the beginning of a block.
+ # We use a list because the same block can be reached through several paths
+ # with different active TryBegins
+ add_try_end: Dict[Label, List[TryEnd]] = defaultdict(list)
+
+ # Track the currently active try begin
+ active_try_begin: Optional[TryBegin] = None
+ try_begin_inserted_in_block = False
+ last_instr: Optional[Instr] = None
+ for index, instr in enumerate(bytecode):
+ # Reference to the current block if we create a new one in the following.
+ old_block: BasicBlock | None = None
+
+ # First we determine if we need to create a new block:
+ # - by checking the current instruction index
+ if index in block_starts:
+ old_label = block_starts[index]
+ # Create a new block if the last created one is not empty
+ # (of real instructions)
+ if index != 0 and (li := block.get_last_non_artificial_instruction()):
+ old_block = block
+ new_block = bytecode_blocks.add_block()
+ # If the last non artificial instruction is not final connect
+ # this block to the next.
+ if not li.is_final():
+ block.next_block = new_block
+ block = new_block
+ if old_label is not None:
+ labels[old_label] = block
+
+ # - by inspecting the last instr
+ elif block.get_last_non_artificial_instruction() and last_instr is not None:
+ # The last instruction is final but we did not create a block
+ # -> sounds like a block of dead code but we preserve it
+ if last_instr.is_final():
+ old_block = block
+ block = bytecode_blocks.add_block()
+
+ # We are dealing with a conditional jump
+ elif last_instr.has_jump():
+ assert isinstance(last_instr.arg, Label)
+ old_block = block
+ new_block = bytecode_blocks.add_block()
+ block.next_block = new_block
+ block = new_block
+
+ # If we created a new block, we check:
+ # - if the current instruction is a TryEnd and if the last instruction
+ # is final in which case we insert the TryEnd in the old block.
+ # - if we have a currently active TryBegin for which we may need to
+ # create a TryEnd in the previous block and a new TryBegin in the
+ # new one because the blocks are not connected.
+ if old_block is not None:
+ temp = try_begin_inserted_in_block
+ try_begin_inserted_in_block = False
+
+ if old_block is not None and last_instr is not None:
+ # The last instruction is final, if the current instruction is a
+ # TryEnd insert it in the same block and move to the next instruction
+ if last_instr.is_final() and isinstance(instr, TryEnd):
+ assert active_try_begin
+ nte = instr.copy()
+ nte.entry = try_begins[active_try_begin][-1]
+ old_block.append(nte)
+ active_try_begin = None
+ continue
+
+ # If we have an active TryBegin and last_instr is:
+ elif active_try_begin is not None:
+ # - a jump whose target is beyond the TryEnd of the active
+ # TryBegin: we remember TryEnd should be prepended to the
+ # target block.
+ if (
+ last_instr.has_jump()
+ and active_try_begin in try_end_locations
+ and (
+ # last_instr is a jump so arg is a Label
+ label_to_block_index[last_instr.arg] # type: ignore
+ >= try_end_locations[active_try_begin]
+ )
+ ):
+ assert isinstance(last_instr.arg, Label)
+ add_try_end[last_instr.arg].append(
+ TryEnd(try_begins[active_try_begin][-1])
+ )
+
+ # - final and the try begin originate from the current block:
+ # we insert a TryEnd in the old block and a new TryBegin in
+ # the new one since the blocks are disconnected.
+ if last_instr.is_final() and temp:
+ old_block.append(TryEnd(try_begins[active_try_begin][-1]))
+ new_tb = TryBegin(
+ active_try_begin.target, active_try_begin.push_lasti
+ )
+ block.append(new_tb)
+ # Add this new TryBegin to the map to properly update
+ # the target.
+ try_begins[active_try_begin].append(new_tb)
+ try_begin_inserted_in_block = True
+
+ last_instr = None
+
+ if isinstance(instr, Label):
+ continue
+
+ # don't copy SetLineno objects
+ if isinstance(instr, (Instr, TryBegin, TryEnd)):
+ new = instr.copy()
+ if isinstance(instr, TryBegin):
+ assert active_try_begin is None
+ active_try_begin = instr
+ try_begin_inserted_in_block = True
+ assert isinstance(new, TryBegin)
+ try_begins[instr] = [new]
+ elif isinstance(instr, TryEnd):
+ assert isinstance(new, TryEnd)
+ new.entry = try_begins[instr.entry][-1]
+ active_try_begin = None
+ try_begin_inserted_in_block = False
+ else:
+ last_instr = instr
+ if isinstance(instr.arg, Label):
+ assert isinstance(new, Instr)
+ jumping_instrs.append(new)
+
+ instr = new
+
+ block.append(instr)
+
+ # Insert the necessary TryEnds at the beginning of block that were marked
+ # (if we did not already insert an equivalent TryEnd earlier).
+ for lab, tes in add_try_end.items():
+ block = labels[lab]
+ existing_te_entries = set()
+ index = 0
+ # We use a while loop since the block cannot yet be iterated on since
+ # jumps still use labels instead of blocks
+ while index < len(block):
+ i = block[index]
+ index += 1
+ if isinstance(i, TryEnd):
+ existing_te_entries.add(i.entry)
+ else:
+ break
+ for te in tes:
+ if te.entry not in existing_te_entries:
+ labels[lab].insert(0, te)
+ existing_te_entries.add(te.entry)
+
+ # Replace labels by block in jumping instructions
+ for instr in jumping_instrs:
+ label = instr.arg
+ assert isinstance(label, Label)
+ instr.arg = labels[label]
+
+ # Replace labels by block in TryBegin
+ for b_tb, c_tbs in try_begins.items():
+ label = b_tb.target
+ assert isinstance(label, Label)
+ for c_tb in c_tbs:
+ c_tb.target = labels[label]
+
+ return bytecode_blocks
+
+ def to_bytecode(self) -> _bytecode.Bytecode:
+ """Convert to Bytecode."""
+
+ used_blocks = set()
+ for block in self:
+ target_block = block.get_jump()
+ if target_block is not None:
+ used_blocks.add(id(target_block))
+
+ for tb in (i for i in block if isinstance(i, TryBegin)):
+ used_blocks.add(id(tb.target))
+
+ labels = {}
+ jumps = []
+ try_begins = {}
+ seen_try_end: Set[TryBegin] = set()
+ instructions: List[Union[Instr, Label, TryBegin, TryEnd, SetLineno]] = []
+
+ # Track the last seen TryBegin and TryEnd to be able to fuse adjacent
+ # TryEnd/TryBegin pair which share the same target.
+ # In each case, we store the value found in the CFG and the value
+ # inserted in the bytecode.
+ last_try_begin: tuple[TryBegin, TryBegin] | None = None
+ last_try_end: tuple[TryEnd, TryEnd] | None = None
+
+ for block in self:
+ if id(block) in used_blocks:
+ new_label = Label()
+ labels[id(block)] = new_label
+ instructions.append(new_label)
+
+ for instr in block:
+ # don't copy SetLineno objects
+ if isinstance(instr, (Instr, TryBegin, TryEnd)):
+ new = instr.copy()
+ if isinstance(instr, TryBegin):
+ # If due to jumps and split TryBegin, we encounter a TryBegin
+ # while we still have a TryBegin ensure they can be fused.
+ if last_try_begin is not None:
+ cfg_tb, byt_tb = last_try_begin
+ assert instr.target is cfg_tb.target
+ assert instr.push_lasti == cfg_tb.push_lasti
+ byt_tb.stack_depth = min(
+ byt_tb.stack_depth, instr.stack_depth
+ )
+
+ # If the TryBegin share the target and push_lasti of the
+ # entry of an adjacent TryEnd, omit the new TryBegin that
+ # was inserted to allow analysis of the CFG and remove
+ # the already inserted TryEnd.
+ if last_try_end is not None:
+ cfg_te, byt_te = last_try_end
+ entry = cfg_te.entry
+ if (
+ entry.target is instr.target
+ and entry.push_lasti == instr.push_lasti
+ ):
+ # If we did not yet compute the required stack depth
+ # keep the value as UNSET
+ if entry.stack_depth is UNSET:
+ assert instr.stack_depth is UNSET
+ byt_te.entry.stack_depth = UNSET
+ else:
+ byt_te.entry.stack_depth = min(
+ entry.stack_depth, instr.stack_depth
+ )
+ try_begins[instr] = byt_te.entry
+ instructions.remove(byt_te)
+ continue
+ assert isinstance(new, TryBegin)
+ try_begins[instr] = new
+ last_try_begin = (instr, new)
+ last_try_end = None
+ elif isinstance(instr, TryEnd):
+ # Only keep the first seen TryEnd matching a TryBegin
+ assert isinstance(new, TryEnd)
+ if instr.entry in seen_try_end:
+ continue
+ seen_try_end.add(instr.entry)
+ new.entry = try_begins[instr.entry]
+ last_try_begin = None
+ last_try_end = (instr, new)
+ elif isinstance(instr.arg, BasicBlock):
+ assert isinstance(new, Instr)
+ jumps.append(new)
+ last_try_end = None
+ else:
+ last_try_end = None
+
+ instr = new
+
+ instructions.append(instr)
+
+ # Map to new labels
+ for instr in jumps:
+ instr.arg = labels[id(instr.arg)]
+
+ for tb in set(try_begins.values()):
+ tb.target = labels[id(tb.target)]
+
+ bytecode = _bytecode.Bytecode()
+ bytecode._copy_attr_from(self)
+ bytecode.argnames = list(self.argnames)
+ bytecode[:] = instructions
+
+ return bytecode
+
+ def to_code(
+ self,
+ stacksize: Optional[int] = None,
+ *,
+ check_pre_and_post: bool = True,
+ compute_exception_stack_depths: bool = True,
+ ) -> types.CodeType:
+ """Convert to code."""
+ if stacksize is None:
+ stacksize = self.compute_stacksize(
+ check_pre_and_post=check_pre_and_post,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
+ bc = self.to_bytecode()
+ return bc.to_code(
+ stacksize=stacksize,
+ check_pre_and_post=False,
+ compute_exception_stack_depths=False,
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/concrete.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/concrete.py
new file mode 100644
index 0000000..4908e1c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/concrete.py
@@ -0,0 +1,1419 @@
+import dis
+import inspect
+import opcode as _opcode
+import struct
+import sys
+import types
+from typing import (
+ Any,
+ Dict,
+ Iterable,
+ Iterator,
+ List,
+ MutableSequence,
+ Optional,
+ Sequence,
+ Set,
+ Tuple,
+ Type,
+ TypeVar,
+ Union,
+)
+
+# alias to keep the 'bytecode' variable free
+import bytecode as _bytecode
+from bytecode.flags import CompilerFlags
+from bytecode.instr import (
+ _UNSET,
+ BITFLAG2_INSTRUCTIONS,
+ BITFLAG_INSTRUCTIONS,
+ INTRINSIC,
+ INTRINSIC_1OP,
+ INTRINSIC_2OP,
+ PLACEHOLDER_LABEL,
+ UNSET,
+ BaseInstr,
+ CellVar,
+ Compare,
+ FreeVar,
+ Instr,
+ InstrArg,
+ InstrLocation,
+ Intrinsic1Op,
+ Intrinsic2Op,
+ Label,
+ SetLineno,
+ TryBegin,
+ TryEnd,
+ _check_arg_int,
+ const_key,
+ opcode_has_argument,
+)
+
+# - jumps use instruction
+# - lineno use bytes (dis.findlinestarts(code))
+# - dis displays bytes
+OFFSET_AS_INSTRUCTION = sys.version_info >= (3, 10)
+
+
+def _set_docstring(code: _bytecode.BaseBytecode, consts: Sequence) -> None:
+ if not consts:
+ return
+ first_const = consts[0]
+ if isinstance(first_const, str) or first_const is None:
+ code.docstring = first_const
+
+
+T = TypeVar("T", bound="ConcreteInstr")
+
+
+class ConcreteInstr(BaseInstr[int]):
+ """Concrete instruction.
+
+ arg must be an integer in the range 0..2147483647.
+
+ It has a read-only size attribute.
+
+ """
+
+ # For ConcreteInstr the argument is always an integer
+ _arg: int
+
+ __slots__ = ("_size", "_extended_args")
+
+ def __init__(
+ self,
+ name: str,
+ arg: int = UNSET,
+ *,
+ lineno: Union[int, None, _UNSET] = UNSET,
+ location: Optional[InstrLocation] = None,
+ extended_args: Optional[int] = None,
+ ):
+ # Allow to remember a potentially meaningless EXTENDED_ARG emitted by
+ # Python to properly compute the size and avoid messing up the jump
+ # targets
+ self._extended_args = extended_args
+ super().__init__(name, arg, lineno=lineno, location=location)
+
+ def _check_arg(self, name: str, opcode: int, arg: int) -> None:
+ if opcode_has_argument(opcode):
+ if arg is UNSET:
+ raise ValueError("operation %s requires an argument" % name)
+
+ _check_arg_int(arg, name)
+ # opcode == 0 corresponds to CACHE instruction in 3.11+ and was unused before
+ elif opcode == 0:
+ arg = arg if arg is not UNSET else 0
+ _check_arg_int(arg, name)
+ else:
+ if arg is not UNSET:
+ raise ValueError("operation %s has no argument" % name)
+
+ def _set(
+ self,
+ name: str,
+ arg: int,
+ ) -> None:
+ super()._set(name, arg)
+ size = 2
+ if arg is not UNSET:
+ while arg > 0xFF:
+ size += 2
+ arg >>= 8
+ if self._extended_args is not None:
+ size = 2 + 2 * self._extended_args
+ self._size = size
+
+ @property
+ def size(self) -> int:
+ return self._size
+
+ def _cmp_key(self) -> Tuple[Optional[InstrLocation], str, int]:
+ return (self._location, self._name, self._arg)
+
+ def get_jump_target(self, instr_offset: int) -> Optional[int]:
+ # When a jump arg is zero the jump always points to the first non-CACHE
+ # opcode following the jump. The passed in offset is the offset at
+ # which the jump opcode starts. So to compute the target, we add to it
+ # the instruction size (accounting for extended args) and the
+ # number of caches expected to follow the jump instruction.
+ s = (
+ (self._size // 2) if OFFSET_AS_INSTRUCTION else self._size
+ ) + self.use_cache_opcodes()
+ if self.is_forward_rel_jump():
+ return instr_offset + s + self._arg
+ if self.is_backward_rel_jump():
+ return instr_offset + s - self._arg
+ if self.is_abs_jump():
+ return self._arg
+ return None
+
+ def assemble(self) -> bytes:
+ if self._arg is UNSET:
+ return bytes((self._opcode, 0))
+
+ arg = self._arg
+ b = [self._opcode, arg & 0xFF]
+ while arg > 0xFF:
+ arg >>= 8
+ b[:0] = [_opcode.EXTENDED_ARG, arg & 0xFF]
+
+ if self._extended_args:
+ while len(b) < self._size:
+ b[:0] = [_opcode.EXTENDED_ARG, 0x00]
+
+ return bytes(b)
+
+ @classmethod
+ def disassemble(cls: Type[T], lineno: Optional[int], code: bytes, offset: int) -> T:
+ index = 2 * offset if OFFSET_AS_INSTRUCTION else offset
+ op = code[index]
+ if opcode_has_argument(op):
+ arg = code[index + 1]
+ else:
+ arg = UNSET
+ name = _opcode.opname[op]
+ return cls(name, arg, lineno=lineno)
+
+ def use_cache_opcodes(self) -> int:
+ return (
+ # Not supposed to be used but we need it
+ dis._inline_cache_entries[self._opcode] # type: ignore
+ if sys.version_info >= (3, 11)
+ else 0
+ )
+
+
+class ExceptionTableEntry:
+ """Entry for a given line in the exception table.
+
+ All offset are expressed in instructions not in bytes.
+
+ """
+
+ #: Offset in instruction between the beginning of the bytecode and the beginning
+ #: of this entry.
+ start_offset: int
+
+ #: Offset in instruction between the beginning of the bytecode and the end
+ #: of this entry. This offset is inclusive meaning that the instruction it points
+ #: to is included in the try/except handling.
+ stop_offset: int
+
+ #: Offset in instruction to the first instruction of the exception handling block.
+ target: int
+
+ #: Minimal stack depth in the block delineated by start and stop
+ #: offset of the exception table entry. Used to restore the stack (by
+ #: popping items) when entering the exception handling block.
+ stack_depth: int
+
+ #: Should the offset, at which an exception was raised, be pushed on the stack
+ #: before the exception itself (which is pushed as a single value)).
+ push_lasti: bool
+
+ __slots__ = ("start_offset", "stop_offset", "target", "stack_depth", "push_lasti")
+
+ def __init__(
+ self,
+ start_offset: int,
+ stop_offset: int,
+ target: int,
+ stack_depth: int,
+ push_lasti: bool,
+ ) -> None:
+ self.start_offset = start_offset
+ self.stop_offset = stop_offset
+ self.target = target
+ self.stack_depth = stack_depth
+ self.push_lasti = push_lasti
+
+ def __repr__(self) -> str:
+ return (
+ "ExceptionTableEntry("
+ f"start_offset={self.start_offset}, "
+ f"stop_offset={self.stop_offset}, "
+ f"target={self.target}, "
+ f"stack_depth={self.stack_depth}, "
+ f"push_lasti={self.push_lasti}"
+ )
+
+
+class ConcreteBytecode(_bytecode._BaseBytecodeList[Union[ConcreteInstr, SetLineno]]):
+ #: List of "constant" objects for the bytecode
+ consts: List
+
+ #: List of names used by local variables.
+ names: List[str]
+
+ #: List of names used by input variables.
+ varnames: List[str]
+
+ #: Table describing portion of the bytecode in which exceptions are caught and
+ #: where there are handled.
+ #: Used only in Python 3.11+
+ exception_table: List[ExceptionTableEntry]
+
+ def __init__(
+ self,
+ instructions=(),
+ *,
+ consts: tuple = (),
+ names: Tuple[str, ...] = (),
+ varnames: Iterable[str] = (),
+ exception_table: Optional[List[ExceptionTableEntry]] = None,
+ ):
+ super().__init__()
+ self.consts = list(consts)
+ self.names = list(names)
+ self.varnames = list(varnames)
+ self.exception_table = exception_table or []
+ for instr in instructions:
+ self._check_instr(instr)
+ self.extend(instructions)
+
+ def __iter__(self) -> Iterator[Union[ConcreteInstr, SetLineno]]:
+ instructions = super().__iter__()
+ for instr in instructions:
+ self._check_instr(instr)
+ yield instr
+
+ def _check_instr(self, instr: Any) -> None:
+ if not isinstance(instr, (ConcreteInstr, SetLineno)):
+ raise ValueError(
+ "ConcreteBytecode must only contain "
+ "ConcreteInstr and SetLineno objects, "
+ "but %s was found" % type(instr).__name__
+ )
+
+ def _copy_attr_from(self, bytecode):
+ super()._copy_attr_from(bytecode)
+ if isinstance(bytecode, ConcreteBytecode):
+ self.consts = bytecode.consts
+ self.names = bytecode.names
+ self.varnames = bytecode.varnames
+
+ def __repr__(self) -> str:
+ return "" % len(self)
+
+ def __eq__(self, other: Any) -> bool:
+ if type(self) is not type(other):
+ return False
+
+ const_keys1 = list(map(const_key, self.consts))
+ const_keys2 = list(map(const_key, other.consts))
+ if const_keys1 != const_keys2:
+ return False
+
+ if self.names != other.names:
+ return False
+ if self.varnames != other.varnames:
+ return False
+
+ return super().__eq__(other)
+
+ @staticmethod
+ def from_code(
+ code: types.CodeType, *, extended_arg: bool = False
+ ) -> "ConcreteBytecode":
+ instructions: MutableSequence[Union[SetLineno, ConcreteInstr]]
+ # For Python 3.11+ we use dis to extract the detailed location information at
+ # reduced maintenance cost.
+ if sys.version_info >= (3, 11):
+ instructions = [
+ # dis.get_instructions automatically handle extended arg which
+ # we do not want, so we fold back arguments to be between 0 and 255
+ ConcreteInstr(
+ i.opname,
+ i.arg % 256 if i.arg is not None else UNSET,
+ location=InstrLocation.from_positions(i.positions)
+ if i.positions
+ else None,
+ )
+ for i in dis.get_instructions(code, show_caches=True)
+ ]
+ else:
+ if sys.version_info >= (3, 10):
+ line_starts = dict(
+ (offset, lineno) for offset, _, lineno in code.co_lines()
+ )
+ else:
+ line_starts = dict(dis.findlinestarts(code))
+
+ # find block starts
+ instructions = []
+ offset = 0
+ lineno: Optional[int] = code.co_firstlineno
+ while offset < (len(code.co_code) // (2 if OFFSET_AS_INSTRUCTION else 1)):
+ lineno_off = (2 * offset) if OFFSET_AS_INSTRUCTION else offset
+ if lineno_off in line_starts:
+ lineno = line_starts[lineno_off]
+
+ instr = ConcreteInstr.disassemble(lineno, code.co_code, offset)
+
+ instructions.append(instr)
+ offset += (instr.size // 2) if OFFSET_AS_INSTRUCTION else instr.size
+
+ bytecode = ConcreteBytecode()
+
+ # HINT : in some cases Python generate useless EXTENDED_ARG opcode
+ # with a value of zero. Such opcodes do not increases the size of the
+ # following opcode the way a normal EXTENDED_ARG does. As a
+ # consequence, they need to be tracked manually as otherwise the
+ # offsets in jump targets can end up being wrong.
+ if not extended_arg:
+ # The list is modified in place
+ bytecode._remove_extended_args(instructions)
+
+ bytecode.name = code.co_name
+ bytecode.filename = code.co_filename
+ bytecode.flags = CompilerFlags(code.co_flags)
+ bytecode.argcount = code.co_argcount
+ bytecode.posonlyargcount = code.co_posonlyargcount
+ bytecode.kwonlyargcount = code.co_kwonlyargcount
+ bytecode.first_lineno = code.co_firstlineno
+ bytecode.names = list(code.co_names)
+ bytecode.consts = list(code.co_consts)
+ bytecode.varnames = list(code.co_varnames)
+ bytecode.freevars = list(code.co_freevars)
+ bytecode.cellvars = list(code.co_cellvars)
+ _set_docstring(bytecode, code.co_consts)
+ if sys.version_info >= (3, 11):
+ bytecode.exception_table = bytecode._parse_exception_table(
+ code.co_exceptiontable
+ )
+ bytecode.qualname = code.co_qualname
+ else:
+ bytecode.qualname = bytecode.qualname
+
+ bytecode[:] = instructions
+ return bytecode
+
+ @staticmethod
+ def _normalize_lineno(
+ instructions: Sequence[Union[ConcreteInstr, SetLineno]], first_lineno: int
+ ) -> Iterator[Tuple[int, ConcreteInstr]]:
+ lineno = first_lineno
+ # For each instruction compute an "inherited" lineno used:
+ # - on 3.8 and 3.9 for which a lineno is mandatory
+ # - to infer a lineno on 3.10+ if no lineno was provided
+ for instr in instructions:
+ i_lineno = instr.lineno
+ # if instr.lineno is not set, it's inherited from the previous
+ # instruction, or from self.first_lineno
+ if i_lineno is not None and i_lineno is not UNSET:
+ lineno = i_lineno
+
+ if isinstance(instr, ConcreteInstr):
+ yield (lineno, instr)
+
+ def _assemble_code(
+ self,
+ ) -> Tuple[bytes, List[Tuple[int, int, int, Optional[InstrLocation]]]]:
+ offset = 0
+ code_str = []
+ linenos = []
+ for lineno, instr in self._normalize_lineno(self, self.first_lineno):
+ code_str.append(instr.assemble())
+ i_size = instr.size
+ linenos.append(
+ (
+ (offset * 2) if OFFSET_AS_INSTRUCTION else offset,
+ i_size,
+ lineno,
+ instr.location,
+ )
+ )
+ offset += (i_size // 2) if OFFSET_AS_INSTRUCTION else i_size
+
+ return (b"".join(code_str), linenos)
+
+ # Used on 3.8 and 3.9
+ @staticmethod
+ def _assemble_lnotab(
+ first_lineno: int, linenos: List[Tuple[int, int, int, Optional[InstrLocation]]]
+ ) -> bytes:
+ lnotab = []
+ old_offset = 0
+ old_lineno = first_lineno
+ for offset, _, lineno, _ in linenos:
+ dlineno = lineno - old_lineno
+ if dlineno == 0:
+ continue
+ old_lineno = lineno
+
+ doff = offset - old_offset
+ old_offset = offset
+
+ while doff > 255:
+ lnotab.append(b"\xff\x00")
+ doff -= 255
+
+ while dlineno < -128:
+ lnotab.append(struct.pack("Bb", doff, -128))
+ doff = 0
+ dlineno -= -128
+
+ while dlineno > 127:
+ lnotab.append(struct.pack("Bb", doff, 127))
+ doff = 0
+ dlineno -= 127
+
+ assert 0 <= doff <= 255
+ assert -128 <= dlineno <= 127
+
+ lnotab.append(struct.pack("Bb", doff, dlineno))
+
+ return b"".join(lnotab)
+
+ @staticmethod
+ def _pack_linetable(
+ linetable: List[bytes], doff: int, dlineno: Optional[int]
+ ) -> None:
+ if dlineno is not None:
+ # Ensure linenos are between -126 and +126, by using 127 lines jumps with
+ # a 0 byte offset
+ while dlineno < -127:
+ linetable.append(struct.pack("Bb", 0, -127))
+ dlineno -= -127
+
+ while dlineno > 127:
+ linetable.append(struct.pack("Bb", 0, 127))
+ dlineno -= 127
+
+ assert -127 <= dlineno <= 127
+ else:
+ dlineno = -128
+
+ # Ensure offsets are less than 255.
+ # If an offset is larger, we first mark the line change with an offset of 254
+ # then use as many 254 offset with no line change to reduce the offset to
+ # less than 254.
+ if doff > 254:
+ linetable.append(struct.pack("Bb", 254, dlineno))
+ doff -= 254
+
+ while doff > 254:
+ linetable.append(b"\xfe\x00")
+ doff -= 254
+ linetable.append(struct.pack("Bb", doff, 0))
+
+ else:
+ linetable.append(struct.pack("Bb", doff, dlineno))
+
+ assert 0 <= doff <= 254
+
+ # Used on 3.10
+ def _assemble_linestable(
+ self,
+ first_lineno: int,
+ linenos: Iterable[Tuple[int, int, int, Optional[InstrLocation]]],
+ ) -> bytes:
+ if not linenos:
+ return b""
+
+ linetable: List[bytes] = []
+ old_offset = 0
+
+ iter_in = iter(linenos)
+
+ offset, i_size, old_lineno, old_location = next(iter_in)
+ if old_location is not None:
+ old_dlineno = (
+ old_location.lineno - first_lineno
+ if old_location.lineno is not None
+ else None
+ )
+ else:
+ old_dlineno = old_lineno - first_lineno
+
+ for offset, i_size, lineno, location in iter_in:
+ if location is not None:
+ dlineno = (
+ location.lineno - old_lineno
+ if location.lineno is not None
+ else None
+ )
+ else:
+ dlineno = lineno - old_lineno
+
+ if dlineno == 0 or (old_dlineno is None and dlineno is None):
+ continue
+ old_lineno = lineno
+
+ doff = offset - old_offset
+ old_offset = offset
+
+ self._pack_linetable(linetable, doff, old_dlineno)
+ old_dlineno = dlineno
+
+ # Pack the line of the last instruction.
+ doff = offset + i_size - old_offset
+ self._pack_linetable(linetable, doff, old_dlineno)
+
+ return b"".join(linetable)
+
+ # The formats are describes in CPython/Objects/locations.md
+ @staticmethod
+ def _encode_location_varint(varint: int) -> bytearray:
+ encoded = bytearray()
+ # We encode on 6 bits
+ while True:
+ encoded.append(varint & 0x3F)
+ varint >>= 6
+ if varint:
+ encoded[-1] |= 0x40 # bit 6 is set except on the last entry
+ else:
+ break
+ return encoded
+
+ def _encode_location_svarint(self, svarint: int) -> bytearray:
+ if svarint < 0:
+ return self._encode_location_varint(((-svarint) << 1) | 1)
+ else:
+ return self._encode_location_varint(svarint << 1)
+
+ # Python 3.11+ location format encoding
+ @staticmethod
+ def _pack_location_header(code: int, size: int) -> int:
+ return (1 << 7) + (code << 3) + (size - 1 if size <= 8 else 7)
+
+ def _pack_location(
+ self, size: int, lineno: int, location: Optional[InstrLocation]
+ ) -> bytearray:
+ packed = bytearray()
+
+ l_lineno: Optional[int]
+ # The location was not set so we infer a line.
+ if location is None:
+ l_lineno, end_lineno, col_offset, end_col_offset = (
+ lineno,
+ None,
+ None,
+ None,
+ )
+ else:
+ l_lineno, end_lineno, col_offset, end_col_offset = (
+ location.lineno,
+ location.end_lineno,
+ location.col_offset,
+ location.end_col_offset,
+ )
+
+ # We have no location information so the code is 15
+ if l_lineno is None:
+ packed.append(self._pack_location_header(15, size))
+
+ # No column info, code 13
+ elif col_offset is None:
+ if end_lineno is not None and end_lineno != l_lineno:
+ raise ValueError(
+ "An instruction cannot have no column offset and span "
+ f"multiple lines (lineno: {l_lineno}, end lineno: {end_lineno}"
+ )
+ packed.extend(
+ (
+ self._pack_location_header(13, size),
+ *self._encode_location_svarint(l_lineno - lineno),
+ )
+ )
+
+ # We enforce the end_lineno to be defined
+ else:
+ assert end_lineno is not None
+ assert end_col_offset is not None
+
+ # Short forms
+ if (
+ end_lineno == l_lineno
+ and l_lineno - lineno == 0
+ and col_offset < 72
+ and (end_col_offset - col_offset) <= 15
+ ):
+ packed.extend(
+ (
+ self._pack_location_header(col_offset // 8, size),
+ ((col_offset % 8) << 4) + (end_col_offset - col_offset),
+ )
+ )
+
+ # One line form
+ elif (
+ end_lineno == l_lineno
+ and l_lineno - lineno in (1, 2)
+ and col_offset < 256
+ and end_col_offset < 256
+ ):
+ packed.extend(
+ (
+ self._pack_location_header(10 + l_lineno - lineno, size),
+ col_offset,
+ end_col_offset,
+ )
+ )
+
+ # Long form
+ else:
+ packed.extend(
+ (
+ self._pack_location_header(14, size),
+ *self._encode_location_svarint(l_lineno - lineno),
+ *self._encode_location_varint(end_lineno - l_lineno),
+ # When decoding in codeobject.c::advance_with_locations
+ # we remove 1 from the offset ...
+ *self._encode_location_varint(col_offset + 1),
+ *self._encode_location_varint(end_col_offset + 1),
+ )
+ )
+
+ return packed
+
+ def _push_locations(
+ self,
+ locations: List[bytearray],
+ size: int,
+ lineno: int,
+ location: InstrLocation,
+ ) -> int:
+ # We need the size in instruction not in bytes
+ size //= 2
+
+ # Repeatedly add element since we cannot cover more than 8 code
+ # elements. We recompute each time since in practice we will
+ # rarely loop.
+ while True:
+ locations.append(self._pack_location(size, lineno, location))
+ # Update the lineno since if we need more than one entry the
+ # reference for the delta of the lineno change
+ lineno = location.lineno if location.lineno is not None else lineno
+ size -= 8
+ if size < 1:
+ break
+
+ return lineno
+
+ def _assemble_locations(
+ self,
+ first_lineno: int,
+ linenos: Iterable[Tuple[int, int, int, Optional[InstrLocation]]],
+ ) -> bytes:
+ if not linenos:
+ return b""
+
+ locations: List[bytearray] = []
+
+ iter_in = iter(linenos)
+
+ _, size, lineno, old_location = next(iter_in)
+ # Infer the line if location is None
+ old_location = old_location or InstrLocation(lineno, None, None, None)
+ lineno = first_lineno
+
+ # We track the last set lineno to be able to compute deltas
+ for _, i_size, new_lineno, location in iter_in:
+ # Infer the line if location is None
+ location = location or InstrLocation(new_lineno, None, None, None)
+
+ # Group together instruction with equivalent locations
+ if old_location.lineno and old_location == location:
+ size += i_size
+ continue
+
+ lineno = self._push_locations(locations, size, lineno, old_location)
+
+ size = i_size
+ old_location = location
+
+ # Pack the line of the last instruction.
+ self._push_locations(locations, size, lineno, old_location)
+
+ return b"".join(locations)
+
+ @staticmethod
+ def _remove_extended_args(
+ instructions: MutableSequence[Union[SetLineno, ConcreteInstr]]
+ ) -> None:
+ # replace jump targets with blocks
+ # HINT : in some cases Python generate useless EXTENDED_ARG opcode
+ # with a value of zero. Such opcodes do not increases the size of the
+ # following opcode the way a normal EXTENDED_ARG does. As a
+ # consequence, they need to be tracked manually as otherwise the
+ # offsets in jump targets can end up being wrong.
+ nb_extended_args = 0
+ extended_arg = None
+ index = 0
+ while index < len(instructions):
+ instr = instructions[index]
+
+ # Skip SetLineno meta instruction
+ if isinstance(instr, SetLineno):
+ index += 1
+ continue
+
+ if instr.name == "EXTENDED_ARG":
+ nb_extended_args += 1
+ if extended_arg is not None:
+ extended_arg = (extended_arg << 8) + instr.arg
+ else:
+ extended_arg = instr.arg
+
+ del instructions[index]
+ continue
+
+ if extended_arg is not None:
+ arg = UNSET if instr.name == "NOP" else (extended_arg << 8) + instr.arg
+ extended_arg = None
+
+ instr = ConcreteInstr(
+ instr.name,
+ arg,
+ location=instr.location,
+ extended_args=nb_extended_args,
+ )
+ instructions[index] = instr
+ nb_extended_args = 0
+
+ index += 1
+
+ if extended_arg is not None:
+ raise ValueError("EXTENDED_ARG at the end of the code")
+
+ # Taken and adapted from exception_handling_notes.txt in cpython/Objects
+ @staticmethod
+ def _parse_varint(except_table_iterator: Iterator[int]) -> int:
+ b = next(except_table_iterator)
+ val = b & 63
+ while b & 64:
+ val <<= 6
+ b = next(except_table_iterator)
+ val |= b & 63
+ return val
+
+ def _parse_exception_table(
+ self, exception_table: bytes
+ ) -> List[ExceptionTableEntry]:
+ assert sys.version_info >= (3, 11)
+ table = []
+ iterator = iter(exception_table)
+ try:
+ while True:
+ start = self._parse_varint(iterator)
+ length = self._parse_varint(iterator)
+ end = start + length - 1 # Present as inclusive
+ target = self._parse_varint(iterator)
+ dl = self._parse_varint(iterator)
+ depth = dl >> 1
+ lasti = bool(dl & 1)
+ table.append(ExceptionTableEntry(start, end, target, depth, lasti))
+ except StopIteration:
+ return table
+
+ @staticmethod
+ def _encode_varint(value: int, set_begin_marker: bool = False) -> Iterator[int]:
+ # Encode value as a varint on 7 bits (MSB should come first) and set
+ # the begin marker if requested.
+ temp: List[int] = []
+ assert value >= 0
+ while value:
+ temp.append(value & 63 | (64 if temp else 0))
+ value >>= 6
+ temp = temp or [0]
+ if set_begin_marker:
+ temp[-1] |= 128
+ return reversed(temp)
+
+ def _assemble_exception_table(self) -> bytes:
+ table = bytearray()
+ for entry in self.exception_table or []:
+ size = entry.stop_offset - entry.start_offset + 1
+ depth = (entry.stack_depth << 1) + entry.push_lasti
+ table.extend(self._encode_varint(entry.start_offset, True))
+ table.extend(self._encode_varint(size))
+ table.extend(self._encode_varint(entry.target))
+ table.extend(self._encode_varint(depth))
+
+ return bytes(table)
+
+ def compute_stacksize(self, *, check_pre_and_post: bool = True) -> int:
+ bytecode = self.to_bytecode()
+ cfg = _bytecode.ControlFlowGraph.from_bytecode(bytecode)
+ return cfg.compute_stacksize(check_pre_and_post=check_pre_and_post)
+
+ def to_code(
+ self,
+ stacksize: Optional[int] = None,
+ *,
+ check_pre_and_post: bool = True,
+ compute_exception_stack_depths: bool = True,
+ ) -> types.CodeType:
+ # Prevent reconverting the concrete bytecode to bytecode and cfg to do the
+ # calculation if we need to do it.
+ if stacksize is None or (
+ sys.version_info >= (3, 11) and compute_exception_stack_depths
+ ):
+ cfg = _bytecode.ControlFlowGraph.from_bytecode(self.to_bytecode())
+ stacksize = cfg.compute_stacksize(
+ check_pre_and_post=check_pre_and_post,
+ compute_exception_stack_depths=compute_exception_stack_depths,
+ )
+ self = cfg.to_bytecode().to_concrete_bytecode(
+ compute_exception_stack_depths=False
+ )
+
+ # Assemble the code string after round tripping to CFG if necessary.
+ code_str, linenos = self._assemble_code()
+
+ lnotab = (
+ self._assemble_locations(self.first_lineno, linenos)
+ if sys.version_info >= (3, 11)
+ else (
+ self._assemble_linestable(self.first_lineno, linenos)
+ if sys.version_info >= (3, 10)
+ else self._assemble_lnotab(self.first_lineno, linenos)
+ )
+ )
+ nlocals = len(self.varnames)
+
+ if sys.version_info >= (3, 11):
+ return types.CodeType(
+ self.argcount,
+ self.posonlyargcount,
+ self.kwonlyargcount,
+ nlocals,
+ stacksize,
+ int(self.flags),
+ code_str,
+ tuple(self.consts),
+ tuple(self.names),
+ tuple(self.varnames),
+ self.filename,
+ self.name,
+ self.qualname,
+ self.first_lineno,
+ lnotab,
+ self._assemble_exception_table(),
+ tuple(self.freevars),
+ tuple(self.cellvars),
+ )
+ else:
+ return types.CodeType(
+ self.argcount,
+ self.posonlyargcount,
+ self.kwonlyargcount,
+ nlocals,
+ stacksize,
+ int(self.flags),
+ code_str,
+ tuple(self.consts),
+ tuple(self.names),
+ tuple(self.varnames),
+ self.filename,
+ self.name,
+ self.first_lineno,
+ lnotab,
+ tuple(self.freevars),
+ tuple(self.cellvars),
+ )
+
+ def to_bytecode(
+ self,
+ prune_caches: bool = True,
+ conserve_exception_block_stackdepth: bool = False,
+ ) -> _bytecode.Bytecode:
+ # On 3.11 we generate pseudo-instruction from the exception table
+
+ # Copy instruction and remove extended args if any (in-place)
+ c_instructions = self[:]
+ self._remove_extended_args(c_instructions)
+
+ # Find jump targets
+ jump_targets: Set[int] = set()
+ offset = 0
+ for c_instr in c_instructions:
+ if isinstance(c_instr, SetLineno):
+ continue
+ target = c_instr.get_jump_target(offset)
+ if target is not None:
+ jump_targets.add(target)
+ offset += (c_instr.size // 2) if OFFSET_AS_INSTRUCTION else c_instr.size
+
+ # On 3.11+ we need to also look at the exception table for jump targets
+ for ex_entry in self.exception_table:
+ jump_targets.add(ex_entry.target)
+
+ # Create look up dict to find entries based on either exception handling
+ # block exit or entry offsets. Several blocks can end on the same instruction
+ # so we store a list of entry per offset.
+ ex_start: Dict[int, ExceptionTableEntry] = {}
+ ex_end: Dict[int, List[ExceptionTableEntry]] = {}
+ for entry in self.exception_table:
+ # Ensure we do not have more than one entry with identical starting
+ # offsets
+ assert entry.start_offset not in ex_start
+ ex_start[entry.start_offset] = entry
+ ex_end.setdefault(entry.stop_offset, []).append(entry)
+
+ # Create labels and instructions
+ jumps: List[Tuple[int, int]] = []
+ instructions: List[Union[Instr, Label, TryBegin, TryEnd, SetLineno]] = []
+ labels = {}
+ tb_instrs: Dict[ExceptionTableEntry, TryBegin] = {}
+ offset = 0
+ # In Python 3.11+ cell and varnames can be shared and are indexed in a single
+ # array.
+ # As a consequence, the instruction argument can be either:
+ # - < len(varnames): the name is shared an we can directly use
+ # the index to access the name in cellvars
+ # - > len(varnames): the name is not shared and is offset by the
+ # number unshared varname.
+ # Free vars are never shared and correspond to index larger than the
+ # largest cell var.
+ # See PyCode_NewWithPosOnlyArgs
+ if sys.version_info >= (3, 11):
+ cells_lookup = self.varnames + [
+ n for n in self.cellvars if n not in self.varnames
+ ]
+ ncells = len(cells_lookup)
+ else:
+ ncells = len(self.cellvars)
+ cells_lookup = self.cellvars
+
+ for lineno, c_instr in self._normalize_lineno(
+ c_instructions, self.first_lineno
+ ):
+ if offset in jump_targets:
+ label = Label()
+ labels[offset] = label
+ instructions.append(label)
+
+ # Handle TryBegin pseudo instructions
+ if offset in ex_start:
+ entry = ex_start[offset]
+ tb_instr = TryBegin(
+ Label(),
+ entry.push_lasti,
+ entry.stack_depth if conserve_exception_block_stackdepth else UNSET,
+ )
+ # Per entry store the pseudo instruction associated
+ tb_instrs[entry] = tb_instr
+ instructions.append(tb_instr)
+
+ jump_target = c_instr.get_jump_target(offset)
+ size = c_instr.size
+ # If an instruction uses extended args, those appear before the instruction
+ # causing the instruction to appear at offset that accounts for extended
+ # args. So we first update the offset to account for extended args, then
+ # record the instruction offset and then add the instruction itself to the
+ # offset.
+ offset += (size // 2 - 1) if OFFSET_AS_INSTRUCTION else (size - 2)
+ current_instr_offset = offset
+ offset += 1 if OFFSET_AS_INSTRUCTION else 2
+
+ # on Python 3.11+ remove CACHE opcodes if we are requested to do so.
+ # We are careful to first advance the offset and check that the CACHE
+ # is not a jump target. It should never be the case but we double check.
+ if prune_caches and c_instr.name == "CACHE":
+ assert jump_target is None
+
+ # We may need to insert a TryEnd after a CACHE so we need to run the
+ # through the last block.
+ else:
+ arg: InstrArg
+ c_arg = c_instr.arg
+ # FIXME: better error reporting
+ if c_instr.opcode in _opcode.hasconst:
+ arg = self.consts[c_arg]
+ elif c_instr.opcode in _opcode.haslocal:
+ arg = self.varnames[c_arg]
+ elif c_instr.opcode in _opcode.hasname:
+ if c_instr.name in BITFLAG_INSTRUCTIONS:
+ arg = (bool(c_arg & 1), self.names[c_arg >> 1])
+ elif c_instr.name in BITFLAG2_INSTRUCTIONS:
+ arg = (bool(c_arg & 1), bool(c_arg & 2), self.names[c_arg >> 2])
+ else:
+ arg = self.names[c_arg]
+ elif c_instr.opcode in _opcode.hasfree:
+ if c_arg < ncells:
+ name = cells_lookup[c_arg]
+ arg = CellVar(name)
+ else:
+ name = self.freevars[c_arg - ncells]
+ arg = FreeVar(name)
+ elif c_instr.opcode in _opcode.hascompare:
+ arg = Compare(
+ (c_arg >> 4) if sys.version_info >= (3, 12) else c_arg
+ )
+ elif c_instr.opcode in INTRINSIC_1OP:
+ arg = Intrinsic1Op(c_arg)
+ elif c_instr.opcode in INTRINSIC_2OP:
+ arg = Intrinsic2Op(c_arg)
+ else:
+ arg = c_arg
+
+ location = c_instr.location or InstrLocation(lineno, None, None, None)
+
+ if jump_target is not None:
+ arg = PLACEHOLDER_LABEL
+ instr_index = len(instructions)
+ jumps.append((instr_index, jump_target))
+
+ instructions.append(Instr(c_instr.name, arg, location=location))
+
+ # We now insert the TryEnd entries
+ if current_instr_offset in ex_end:
+ entries = ex_end[current_instr_offset]
+ for entry in reversed(entries):
+ instructions.append(TryEnd(tb_instrs[entry]))
+
+ # Replace jump targets with labels
+ for index, jump_target in jumps:
+ instr = instructions[index]
+ assert isinstance(instr, Instr) and instr.arg is PLACEHOLDER_LABEL
+ # FIXME: better error reporting on missing label
+ instr.arg = labels[jump_target]
+
+ # Set the label for TryBegin
+ for entry, tb in tb_instrs.items():
+ tb.target = labels[entry.target]
+
+ bytecode = _bytecode.Bytecode()
+ bytecode._copy_attr_from(self)
+
+ nargs = bytecode.argcount + bytecode.kwonlyargcount
+ nargs += bytecode.posonlyargcount
+ if bytecode.flags & inspect.CO_VARARGS:
+ nargs += 1
+ if bytecode.flags & inspect.CO_VARKEYWORDS:
+ nargs += 1
+ bytecode.argnames = self.varnames[:nargs]
+ _set_docstring(bytecode, self.consts)
+
+ bytecode.extend(instructions)
+ return bytecode
+
+
+class _ConvertBytecodeToConcrete:
+ # XXX document attributes
+
+ #: Default number of passes of compute_jumps() before giving up. Refer to
+ #: assemble_jump_offsets() in compile.c for background.
+ _compute_jumps_passes = 10
+
+ def __init__(self, code: _bytecode.Bytecode) -> None:
+ assert isinstance(code, _bytecode.Bytecode)
+ self.bytecode = code
+
+ # temporary variables
+ self.instructions: List[ConcreteInstr] = []
+ self.jumps: List[Tuple[int, Label, ConcreteInstr]] = []
+ self.labels: Dict[Label, int] = {}
+ self.exception_handling_blocks: Dict[TryBegin, ExceptionTableEntry] = {}
+ self.required_caches = 0
+ self.seen_manual_cache = False
+
+ # used to build ConcreteBytecode() object
+ self.consts_indices: Dict[Union[bytes, Tuple[type, int]], int] = {}
+ self.consts_list: List[Any] = []
+ self.names: List[str] = []
+ self.varnames: List[str] = []
+
+ def add_const(self, value: Any) -> int:
+ key = const_key(value)
+ if key in self.consts_indices:
+ return self.consts_indices[key]
+ index = len(self.consts_indices)
+ self.consts_indices[key] = index
+ self.consts_list.append(value)
+ return index
+
+ @staticmethod
+ def add(names: List[str], name: str) -> int:
+ try:
+ index = names.index(name)
+ except ValueError:
+ index = len(names)
+ names.append(name)
+ return index
+
+ def concrete_instructions(self) -> None:
+ lineno = self.bytecode.first_lineno
+ # Track instruction (index) using cell vars and free vars to be able to update
+ # the index used once all the names are known.
+ cell_instrs: List[int] = []
+ free_instrs: List[int] = []
+
+ for instr in self.bytecode:
+ # Enforce proper use of CACHE opcode on Python 3.11+ by checking we get the
+ # number we expect or directly generate the needed ones.
+ if isinstance(instr, Instr) and instr.name == "CACHE":
+ if not self.required_caches:
+ raise RuntimeError("Found a CACHE opcode when none was expected.")
+ self.seen_manual_cache = True
+ self.required_caches -= 1
+
+ elif self.required_caches:
+ if not self.seen_manual_cache:
+ # We preserve the location of the instruction requiring the
+ # presence of cache instructions
+ self.instructions.extend(
+ [
+ ConcreteInstr(
+ "CACHE", 0, location=self.instructions[-1].location
+ )
+ for i in range(self.required_caches)
+ ]
+ )
+ self.required_caches = 0
+ self.seen_manual_cache = False
+ else:
+ raise RuntimeError(
+ "Found some manual opcode but less than expected. "
+ f"Missing {self.required_caches} CACHE opcodes."
+ )
+
+ if isinstance(instr, Label):
+ self.labels[instr] = len(self.instructions)
+ continue
+
+ if isinstance(instr, SetLineno):
+ lineno = instr.lineno
+ continue
+
+ if isinstance(instr, TryBegin):
+ # We expect the stack depth to have be provided or computed earlier
+ assert instr.stack_depth is not UNSET
+ # NOTE here we store the index of the instruction at which the
+ # exception table entry starts. This is not the final value we want,
+ # we want the offset in the bytecode but that requires to compute
+ # the jumps first to resolve any possible extended arg needed in a
+ # jump.
+ self.exception_handling_blocks[instr] = ExceptionTableEntry(
+ len(self.instructions), 0, 0, instr.stack_depth, instr.push_lasti
+ )
+ continue
+
+ # Do not handle TryEnd before we insert possible CACHE opcode
+ if isinstance(instr, TryEnd):
+ entry = self.exception_handling_blocks[instr.entry]
+ # The TryEnd is located after the last opcode in the exception entry
+ # so we move the offset by one. We choose one so that the end does
+ # encompass a possible EXTENDED_ARG
+ entry.stop_offset = len(self.instructions) - 1
+ continue
+
+ assert isinstance(instr, Instr)
+
+ if instr.lineno is not UNSET and instr.lineno is not None:
+ lineno = instr.lineno
+ elif instr.lineno is UNSET:
+ instr.lineno = lineno
+
+ arg = instr.arg
+ is_jump = False
+ if isinstance(arg, Label):
+ label = arg
+ # fake value, real value is set in compute_jumps()
+ arg = 0
+ is_jump = True
+ elif instr.opcode in _opcode.hasconst:
+ arg = self.add_const(arg)
+ elif instr.opcode in _opcode.haslocal:
+ assert isinstance(arg, str)
+ arg = self.add(self.varnames, arg)
+ elif instr.opcode in _opcode.hasname:
+ if instr.name in BITFLAG_INSTRUCTIONS:
+ assert (
+ isinstance(arg, tuple)
+ and len(arg) == 2
+ and isinstance(arg[0], bool)
+ and isinstance(arg[1], str)
+ ), arg
+ index = self.add(self.names, arg[1])
+ arg = int(arg[0]) + (index << 1)
+ elif instr.name in BITFLAG2_INSTRUCTIONS:
+ assert (
+ isinstance(arg, tuple)
+ and len(arg) == 3
+ and isinstance(arg[0], bool)
+ and isinstance(arg[1], bool)
+ and isinstance(arg[2], str)
+ ), arg
+ index = self.add(self.names, arg[2])
+ arg = int(arg[0]) + 2 * int(arg[1]) + (index << 2)
+ else:
+ assert isinstance(arg, str), f"Got {arg}, expected a str"
+ arg = self.add(self.names, arg)
+ elif instr.opcode in _opcode.hasfree:
+ if isinstance(arg, CellVar):
+ cell_instrs.append(len(self.instructions))
+ arg = self.bytecode.cellvars.index(arg.name)
+ else:
+ assert isinstance(arg, FreeVar)
+ free_instrs.append(len(self.instructions))
+ arg = self.bytecode.freevars.index(arg.name)
+ elif instr.opcode in _opcode.hascompare:
+ if isinstance(arg, Compare):
+ # In Python 3.12 the 4 lowest bits are used for caching
+ # See compare_masks in compile.c
+ if sys.version_info >= (3, 12):
+ arg = arg._get_mask() + (arg.value << 4)
+ else:
+ arg = arg.value
+ elif instr.opcode in INTRINSIC:
+ if isinstance(arg, (Intrinsic1Op, Intrinsic2Op)):
+ arg = arg.value
+
+ # The above should have performed all the necessary conversion
+ assert isinstance(arg, int)
+ c_instr = ConcreteInstr(instr.name, arg, location=instr.location)
+ if is_jump:
+ self.jumps.append((len(self.instructions), label, c_instr))
+
+ # If the instruction expect some cache
+ if sys.version_info >= (3, 11):
+ self.required_caches = c_instr.use_cache_opcodes()
+ self.seen_manual_cache = False
+
+ self.instructions.append(c_instr)
+
+ # On Python 3.11 varnames and cells can share some names. Wind the shared
+ # names and update the arg argument of instructions using cell vars.
+ # We also track by how much to offset free vars which are stored in a
+ # contiguous array after the cell vars
+ if sys.version_info >= (3, 11):
+ # Map naive cell index to shared index
+ shared_name_indexes: Dict[int, int] = {}
+ n_shared = 0
+ n_unshared = 0
+ for i, name in enumerate(self.bytecode.cellvars):
+ if name in self.varnames:
+ shared_name_indexes[i] = self.varnames.index(name)
+ n_shared += 1
+ else:
+ shared_name_indexes[i] = len(self.varnames) + n_unshared
+ n_unshared += 1
+
+ for index in cell_instrs:
+ c_instr = self.instructions[index]
+ c_instr.arg = shared_name_indexes[c_instr.arg]
+
+ free_offset = len(self.varnames) + len(self.bytecode.cellvars) - n_shared
+ else:
+ free_offset = len(self.bytecode.cellvars)
+
+ for index in free_instrs:
+ c_instr = self.instructions[index]
+ c_instr.arg += free_offset
+
+ def compute_jumps(self) -> bool:
+ # For labels we need the offset before the instruction at a given index but for
+ # exception table entries we need the offset of the instruction which can differ
+ # in the presence of extended args...
+ label_offsets = []
+ instruction_offsets = []
+ offset = 0
+ for index, instr in enumerate(self.instructions):
+ label_offsets.append(offset)
+ # If an instruction uses extended args, those appear before the instruction
+ # causing the instruction to appear at offset that accounts for extended
+ # args.
+ offset += (
+ (instr.size // 2 - 1) if OFFSET_AS_INSTRUCTION else (instr.size - 2)
+ )
+ instruction_offsets.append(offset)
+ offset += 1 if OFFSET_AS_INSTRUCTION else 2
+ # needed if a label is at the end
+ label_offsets.append(offset)
+
+ # FIXME may need some extra check to validate jump forward vs jump backward
+ # fix argument of jump instructions: resolve labels
+ modified = False
+ for index, label, instr in self.jumps:
+ target_index = self.labels[label]
+ target_offset = label_offsets[target_index]
+
+ # FIXME use opcode
+ # Under 3.12+, FOR_ITER, SEND jump is increased by 1 implicitely
+ # to skip over END_FOR, END_SEND see Python/instrumentation.c
+ if sys.version_info >= (3, 12) and instr.name in ("FOR_ITER", "SEND"):
+ target_offset -= 1
+
+ if instr.is_forward_rel_jump():
+ instr_offset = label_offsets[index]
+ target_offset -= instr_offset + (
+ instr.size // 2 if OFFSET_AS_INSTRUCTION else instr.size
+ )
+ elif instr.is_backward_rel_jump():
+ instr_offset = label_offsets[index]
+ target_offset = (
+ instr_offset
+ + (instr.size // 2 if OFFSET_AS_INSTRUCTION else instr.size)
+ - target_offset
+ )
+
+ old_size = instr.size
+ # FIXME: better error report if target_offset is negative
+ instr.arg = target_offset
+ if instr.size != old_size:
+ modified = True
+
+ # If a jump required an extended arg hence invalidating the calculation
+ # we return early before filling the exception table entries
+ if modified:
+ return modified
+
+ # Resolve labels for exception handling entries
+ for tb, entry in self.exception_handling_blocks.items():
+ # Set the offset for the start and end offset from the instruction
+ # index stored when assembling the concrete instructions.
+ entry.start_offset = instruction_offsets[entry.start_offset]
+ entry.stop_offset = instruction_offsets[entry.stop_offset]
+
+ # Set the offset to the target instruction
+ lb = tb.target
+ assert isinstance(lb, Label)
+ target_index = self.labels[lb]
+ target_offset = label_offsets[target_index]
+ entry.target = target_offset
+
+ return False
+
+ def to_concrete_bytecode(
+ self,
+ compute_jumps_passes: Optional[int] = None,
+ compute_exception_stack_depths: bool = True,
+ ) -> ConcreteBytecode:
+ if sys.version_info >= (3, 11) and compute_exception_stack_depths:
+ cfg = _bytecode.ControlFlowGraph.from_bytecode(self.bytecode)
+ cfg.compute_stacksize(compute_exception_stack_depths=True)
+ self.bytecode = cfg.to_bytecode()
+
+ if compute_jumps_passes is None:
+ compute_jumps_passes = self._compute_jumps_passes
+
+ first_const = self.bytecode.docstring
+ if first_const is not UNSET:
+ self.add_const(first_const)
+
+ self.varnames.extend(self.bytecode.argnames)
+
+ self.concrete_instructions()
+ for pas in range(0, compute_jumps_passes):
+ modified = self.compute_jumps()
+ if not modified:
+ break
+ else:
+ raise RuntimeError(
+ "compute_jumps() failed to converge after" " %d passes" % (pas + 1)
+ )
+
+ concrete = ConcreteBytecode(
+ self.instructions,
+ consts=tuple(self.consts_list),
+ names=tuple(self.names),
+ varnames=self.varnames,
+ exception_table=list(self.exception_handling_blocks.values()),
+ )
+ concrete._copy_attr_from(self.bytecode)
+ return concrete
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/flags.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/flags.py
new file mode 100644
index 0000000..039150f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/flags.py
@@ -0,0 +1,187 @@
+import opcode
+import sys
+from enum import IntFlag
+from typing import Optional, Union
+
+# alias to keep the 'bytecode' variable free
+import bytecode as _bytecode
+
+
+class CompilerFlags(IntFlag):
+ """Possible values of the co_flags attribute of Code object.
+
+ Note: We do not rely on inspect values here as some of them are missing and
+ furthermore would be version dependent.
+
+ """
+
+ OPTIMIZED = 0x00001 # noqa
+ NEWLOCALS = 0x00002 # noqa
+ VARARGS = 0x00004 # noqa
+ VARKEYWORDS = 0x00008 # noqa
+ NESTED = 0x00010 # noqa
+ GENERATOR = 0x00020 # noqa
+ NOFREE = 0x00040 # noqa
+ # New in Python 3.5
+ # Used for coroutines defined using async def ie native coroutine
+ COROUTINE = 0x00080 # noqa
+ # Used for coroutines defined as a generator and then decorated using
+ # types.coroutine
+ ITERABLE_COROUTINE = 0x00100 # noqa
+ # New in Python 3.6
+ # Generator defined in an async def function
+ ASYNC_GENERATOR = 0x00200 # noqa
+
+ # __future__ flags
+ # future flags changed in Python 3.9
+ if sys.version_info < (3, 9):
+ FUTURE_GENERATOR_STOP = 0x80000 # noqa
+ FUTURE_ANNOTATIONS = 0x100000
+ else:
+ FUTURE_GENERATOR_STOP = 0x800000 # noqa
+ FUTURE_ANNOTATIONS = 0x1000000
+
+
+def infer_flags(
+ bytecode: Union[
+ "_bytecode.Bytecode", "_bytecode.ConcreteBytecode", "_bytecode.ControlFlowGraph"
+ ],
+ is_async: Optional[bool] = None,
+):
+ """Infer the proper flags for a bytecode based on the instructions.
+
+ Because the bytecode does not have enough context to guess if a function
+ is asynchronous the algorithm tries to be conservative and will never turn
+ a previously async code into a sync one.
+
+ Parameters
+ ----------
+ bytecode : Bytecode | ConcreteBytecode | ControlFlowGraph
+ Bytecode for which to infer the proper flags
+ is_async : bool | None, optional
+ Force the code to be marked as asynchronous if True, prevent it from
+ being marked as asynchronous if False and simply infer the best
+ solution based on the opcode and the existing flag if None.
+
+ """
+ flags = CompilerFlags(0)
+ if not isinstance(
+ bytecode,
+ (_bytecode.Bytecode, _bytecode.ConcreteBytecode, _bytecode.ControlFlowGraph),
+ ):
+ msg = (
+ "Expected a Bytecode, ConcreteBytecode or ControlFlowGraph "
+ "instance not %s"
+ )
+ raise ValueError(msg % bytecode)
+
+ instructions = (
+ bytecode._get_instructions()
+ if isinstance(bytecode, _bytecode.ControlFlowGraph)
+ else bytecode
+ )
+ instr_names = {
+ i.name
+ for i in instructions
+ if not isinstance(
+ i,
+ (
+ _bytecode.SetLineno,
+ _bytecode.Label,
+ _bytecode.TryBegin,
+ _bytecode.TryEnd,
+ ),
+ )
+ }
+
+ # Identify optimized code
+ if not (instr_names & {"STORE_NAME", "LOAD_NAME", "DELETE_NAME"}):
+ flags |= CompilerFlags.OPTIMIZED
+
+ # Check for free variables
+ if not (instr_names & {opcode.opname[i] for i in opcode.hasfree}):
+ flags |= CompilerFlags.NOFREE
+
+ # Copy flags for which we cannot infer the right value
+ flags |= bytecode.flags & (
+ CompilerFlags.NEWLOCALS
+ | CompilerFlags.VARARGS
+ | CompilerFlags.VARKEYWORDS
+ | CompilerFlags.NESTED
+ )
+
+ sure_generator = instr_names & {"YIELD_VALUE"}
+ maybe_generator = instr_names & {"YIELD_VALUE", "YIELD_FROM"}
+
+ sure_async = instr_names & {
+ "GET_AWAITABLE",
+ "GET_AITER",
+ "GET_ANEXT",
+ "BEFORE_ASYNC_WITH",
+ "SETUP_ASYNC_WITH",
+ "END_ASYNC_FOR",
+ "ASYNC_GEN_WRAP", # New in 3.11
+ }
+
+ # If performing inference or forcing an async behavior, first inspect
+ # the flags since this is the only way to identify iterable coroutines
+ if is_async in (None, True):
+ if bytecode.flags & CompilerFlags.COROUTINE:
+ if sure_generator:
+ flags |= CompilerFlags.ASYNC_GENERATOR
+ else:
+ flags |= CompilerFlags.COROUTINE
+ elif bytecode.flags & CompilerFlags.ITERABLE_COROUTINE:
+ if sure_async:
+ msg = (
+ "The ITERABLE_COROUTINE flag is set but bytecode that"
+ "can only be used in async functions have been "
+ "detected. Please unset that flag before performing "
+ "inference."
+ )
+ raise ValueError(msg)
+ flags |= CompilerFlags.ITERABLE_COROUTINE
+ elif bytecode.flags & CompilerFlags.ASYNC_GENERATOR:
+ if not sure_generator:
+ flags |= CompilerFlags.COROUTINE
+ else:
+ flags |= CompilerFlags.ASYNC_GENERATOR
+
+ # If the code was not asynchronous before determine if it should now be
+ # asynchronous based on the opcode and the is_async argument.
+ else:
+ if sure_async:
+ # YIELD_FROM is not allowed in async generator
+ if sure_generator:
+ flags |= CompilerFlags.ASYNC_GENERATOR
+ else:
+ flags |= CompilerFlags.COROUTINE
+
+ elif maybe_generator:
+ if is_async:
+ if sure_generator:
+ flags |= CompilerFlags.ASYNC_GENERATOR
+ else:
+ flags |= CompilerFlags.COROUTINE
+ else:
+ flags |= CompilerFlags.GENERATOR
+
+ elif is_async:
+ flags |= CompilerFlags.COROUTINE
+
+ # If the code should not be asynchronous, check first it is possible and
+ # next set the GENERATOR flag if relevant
+ else:
+ if sure_async:
+ raise ValueError(
+ "The is_async argument is False but bytecodes "
+ "that can only be used in async functions have "
+ "been detected."
+ )
+
+ if maybe_generator:
+ flags |= CompilerFlags.GENERATOR
+
+ flags |= bytecode.flags & CompilerFlags.FUTURE_GENERATOR_STOP
+
+ return flags
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/instr.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/instr.py
new file mode 100644
index 0000000..e927cdf
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/instr.py
@@ -0,0 +1,878 @@
+import dis
+import enum
+import opcode as _opcode
+import sys
+from abc import abstractmethod
+from dataclasses import dataclass
+from marshal import dumps as _dumps
+from typing import Any, Callable, Dict, Generic, Optional, Tuple, TypeVar, Union
+
+try:
+ from typing import TypeGuard
+except ImportError:
+ from typing_extensions import TypeGuard # type: ignore
+
+import bytecode as _bytecode
+
+# --- Instruction argument tools and
+
+MIN_INSTRUMENTED_OPCODE = getattr(_opcode, "MIN_INSTRUMENTED_OPCODE", 256)
+
+# Instructions relying on a bit to modify its behavior.
+# The lowest bit is used to encode custom behavior.
+BITFLAG_INSTRUCTIONS = (
+ ("LOAD_GLOBAL", "LOAD_ATTR")
+ if sys.version_info >= (3, 12)
+ else ("LOAD_GLOBAL",)
+ if sys.version_info >= (3, 11)
+ else ()
+)
+
+BITFLAG2_INSTRUCTIONS = ("LOAD_SUPER_ATTR",) if sys.version_info >= (3, 12) else ()
+
+# Intrinsic related opcodes
+INTRINSIC_1OP = (
+ (_opcode.opmap["CALL_INTRINSIC_1"],) if sys.version_info >= (3, 12) else ()
+)
+INTRINSIC_2OP = (
+ (_opcode.opmap["CALL_INTRINSIC_2"],) if sys.version_info >= (3, 12) else ()
+)
+INTRINSIC = INTRINSIC_1OP + INTRINSIC_2OP
+
+
+# Used for COMPARE_OP opcode argument
+@enum.unique
+class Compare(enum.IntEnum):
+ LT = 0
+ LE = 1
+ EQ = 2
+ NE = 3
+ GT = 4
+ GE = 5
+ if sys.version_info < (3, 9):
+ IN = 6
+ NOT_IN = 7
+ IS = 8
+ IS_NOT = 9
+ EXC_MATCH = 10
+
+ if sys.version_info >= (3, 12):
+
+ def _get_mask(self):
+ if self == Compare.EQ:
+ return 8
+ elif self == Compare.NE:
+ return 1 + 2 + 4
+ elif self == Compare.LT:
+ return 2
+ elif self == Compare.LE:
+ return 2 + 8
+ elif self == Compare.GT:
+ return 4
+ elif self == Compare.GE:
+ return 4 + 8
+
+
+# Used for BINARY_OP under Python 3.11+
+@enum.unique
+class BinaryOp(enum.IntEnum):
+ ADD = 0
+ AND = 1
+ FLOOR_DIVIDE = 2
+ LSHIFT = 3
+ MATRIX_MULTIPLY = 4
+ MULTIPLY = 5
+ REMAINDER = 6
+ OR = 7
+ POWER = 8
+ RSHIFT = 9
+ SUBTRACT = 10
+ TRUE_DIVIDE = 11
+ XOR = 12
+ INPLACE_ADD = 13
+ INPLACE_AND = 14
+ INPLACE_FLOOR_DIVIDE = 15
+ INPLACE_LSHIFT = 16
+ INPLACE_MATRIX_MULTIPLY = 17
+ INPLACE_MULTIPLY = 18
+ INPLACE_REMAINDER = 19
+ INPLACE_OR = 20
+ INPLACE_POWER = 21
+ INPLACE_RSHIFT = 22
+ INPLACE_SUBTRACT = 23
+ INPLACE_TRUE_DIVIDE = 24
+ INPLACE_XOR = 25
+
+
+@enum.unique
+class Intrinsic1Op(enum.IntEnum):
+ INTRINSIC_1_INVALID = 0
+ INTRINSIC_PRINT = 1
+ INTRINSIC_IMPORT_STAR = 2
+ INTRINSIC_STOPITERATION_ERROR = 3
+ INTRINSIC_ASYNC_GEN_WRAP = 4
+ INTRINSIC_UNARY_POSITIVE = 5
+ INTRINSIC_LIST_TO_TUPLE = 6
+ INTRINSIC_TYPEVAR = 7
+ INTRINSIC_PARAMSPEC = 8
+ INTRINSIC_TYPEVARTUPLE = 9
+ INTRINSIC_SUBSCRIPT_GENERIC = 10
+ INTRINSIC_TYPEALIAS = 11
+
+
+@enum.unique
+class Intrinsic2Op(enum.IntEnum):
+ INTRINSIC_2_INVALID = 0
+ INTRINSIC_PREP_RERAISE_STAR = 1
+ INTRINSIC_TYPEVAR_WITH_BOUND = 2
+ INTRINSIC_TYPEVAR_WITH_CONSTRAINTS = 3
+ INTRINSIC_SET_FUNCTION_TYPE_PARAMS = 4
+
+
+# This make type checking happy but means it won't catch attempt to manipulate an unset
+# statically. We would need guard on object attribute narrowed down through methods
+class _UNSET(int):
+ instance = None
+
+ def __new__(cls):
+ if cls.instance is None:
+ cls.instance = super().__new__(cls)
+ return cls.instance
+
+ def __eq__(self, other) -> bool:
+ return self is other
+
+
+for op in [
+ "__abs__",
+ "__add__",
+ "__and__",
+ "__bool__",
+ "__ceil__",
+ "__divmod__",
+ "__float__",
+ "__floor__",
+ "__floordiv__",
+ "__ge__",
+ "__gt__",
+ "__hash__",
+ "__index__",
+ "__int__",
+ "__invert__",
+ "__le__",
+ "__lshift__",
+ "__lt__",
+ "__mod__",
+ "__mul__",
+ "__ne__",
+ "__neg__",
+ "__or__",
+ "__pos__",
+ "__pow__",
+ "__radd__",
+ "__rand__",
+ "__rdivmod__",
+ "__rfloordiv__",
+ "__rlshift__",
+ "__rmod__",
+ "__rmul__",
+ "__ror__",
+ "__round__",
+ "__rpow__",
+ "__rrshift__",
+ "__rshift__",
+ "__rsub__",
+ "__rtruediv__",
+ "__rxor__",
+ "__sub__",
+ "__truediv__",
+ "__trunc__",
+ "__xor__",
+]:
+ setattr(_UNSET, op, lambda *args: NotImplemented)
+
+
+UNSET = _UNSET()
+
+
+def const_key(obj: Any) -> Union[bytes, Tuple[type, int]]:
+ try:
+ return _dumps(obj)
+ except ValueError:
+ # For other types, we use the object identifier as an unique identifier
+ # to ensure that they are seen as unequal.
+ return (type(obj), id(obj))
+
+
+class Label:
+ __slots__ = ()
+
+
+#: Placeholder label temporarily used when performing some conversions
+#: concrete -> bytecode
+PLACEHOLDER_LABEL = Label()
+
+
+class _Variable:
+ __slots__ = ("name",)
+
+ def __init__(self, name: str) -> None:
+ self.name: str = name
+
+ def __eq__(self, other: Any) -> bool:
+ if type(self) is not type(other):
+ return False
+ return self.name == other.name
+
+ def __str__(self) -> str:
+ return self.name
+
+ def __repr__(self) -> str:
+ return "<%s %r>" % (self.__class__.__name__, self.name)
+
+
+class CellVar(_Variable):
+ __slots__ = ()
+
+
+class FreeVar(_Variable):
+ __slots__ = ()
+
+
+def _check_arg_int(arg: Any, name: str) -> TypeGuard[int]:
+ if not isinstance(arg, int):
+ raise TypeError(
+ "operation %s argument must be an int, "
+ "got %s" % (name, type(arg).__name__)
+ )
+
+ if not (0 <= arg <= 2147483647):
+ raise ValueError(
+ "operation %s argument must be in " "the range 0..2,147,483,647" % name
+ )
+
+ return True
+
+
+if sys.version_info >= (3, 12):
+
+ def opcode_has_argument(opcode: int) -> bool:
+ return opcode in dis.hasarg
+
+else:
+
+ def opcode_has_argument(opcode: int) -> bool:
+ return opcode >= dis.HAVE_ARGUMENT
+
+
+# --- Instruction stack effect impact
+
+# We split the stack effect between the manipulations done on the stack before
+# executing the instruction (fetching the elements that are going to be used)
+# and what is pushed back on the stack after the execution is complete.
+
+# Stack effects that do not depend on the argument of the instruction
+STATIC_STACK_EFFECTS: Dict[str, Tuple[int, int]] = {
+ "ROT_TWO": (-2, 2),
+ "ROT_THREE": (-3, 3),
+ "ROT_FOUR": (-4, 4),
+ "DUP_TOP": (-1, 2),
+ "DUP_TOP_TWO": (-2, 4),
+ "GET_LEN": (-1, 2),
+ "GET_ITER": (-1, 1),
+ "GET_YIELD_FROM_ITER": (-1, 1),
+ "GET_AWAITABLE": (-1, 1),
+ "GET_AITER": (-1, 1),
+ "GET_ANEXT": (-1, 2),
+ "LIST_TO_TUPLE": (-1, 1),
+ "LIST_EXTEND": (-2, 1),
+ "SET_UPDATE": (-2, 1),
+ "DICT_UPDATE": (-2, 1),
+ "DICT_MERGE": (-2, 1),
+ "COMPARE_OP": (-2, 1),
+ "IS_OP": (-2, 1),
+ "CONTAINS_OP": (-2, 1),
+ "IMPORT_NAME": (-2, 1),
+ "ASYNC_GEN_WRAP": (-1, 1),
+ "PUSH_EXC_INFO": (-1, 2),
+ # Pop TOS and push TOS.__aexit__ and result of TOS.__aenter__()
+ "BEFORE_ASYNC_WITH": (-1, 2),
+ # Replace TOS based on TOS and TOS1
+ "IMPORT_FROM": (-1, 2),
+ "COPY_DICT_WITHOUT_KEYS": (-2, 2),
+ # Call a function at position 7 (4 3.11+) on the stack and push the return value
+ "WITH_EXCEPT_START": (-4, 5) if sys.version_info >= (3, 11) else (-7, 8),
+ # Starting with Python 3.11 MATCH_CLASS does not push a boolean anymore
+ "MATCH_CLASS": (-3, 1 if sys.version_info >= (3, 11) else 2),
+ "MATCH_MAPPING": (-1, 2),
+ "MATCH_SEQUENCE": (-1, 2),
+ "MATCH_KEYS": (-2, 3 if sys.version_info >= (3, 11) else 4),
+ "CHECK_EXC_MATCH": (-2, 2), # (TOS1, TOS) -> (TOS1, bool)
+ "CHECK_EG_MATCH": (-2, 2), # (TOS, TOS1) -> non-matched, matched or TOS1, None)
+ "PREP_RERAISE_STAR": (-2, 1), # (TOS1, TOS) -> new exception group)
+ **{k: (-1, 1) for k in (o for o in _opcode.opmap if (o.startswith("UNARY_")))},
+ **{
+ k: (-2, 1)
+ for k in (
+ o
+ for o in _opcode.opmap
+ if (o.startswith("BINARY_") or o.startswith("INPLACE_"))
+ )
+ },
+ # Python 3.12 changes not covered by dis.stack_effect
+ "BINARY_SLICE": (-3, 1),
+ # "STORE_SLICE" handled by dis.stack_effect
+ "LOAD_FROM_DICT_OR_GLOBALS": (-1, 1),
+ "LOAD_FROM_DICT_OR_DEREF": (-1, 1),
+ "LOAD_INTRISIC_1": (-1, 1),
+ "LOAD_INTRISIC_2": (-2, 1),
+}
+
+
+DYNAMIC_STACK_EFFECTS: Dict[
+ str, Callable[[int, Any, Optional[bool]], Tuple[int, int]]
+] = {
+ # PRECALL pops all arguments (as per its stack effect) and leaves
+ # the callable and either self or NULL
+ # CALL pops the 2 above items and push the return
+ # (when PRECALL does not exist it pops more as encoded by the effect)
+ "CALL": lambda effect, arg, jump: (
+ -2 - arg if sys.version_info >= (3, 12) else -2,
+ 1,
+ ),
+ # 3.12 changed the behavior of LOAD_ATTR
+ "LOAD_ATTR": lambda effect, arg, jump: (-1, 1 + effect),
+ "LOAD_SUPER_ATTR": lambda effect, arg, jump: (-3, 3 + effect),
+ "SWAP": lambda effect, arg, jump: (-arg, arg),
+ "COPY": lambda effect, arg, jump: (-arg, arg + effect),
+ "ROT_N": lambda effect, arg, jump: (-arg, arg),
+ "SET_ADD": lambda effect, arg, jump: (-arg, arg - 1),
+ "LIST_APPEND": lambda effect, arg, jump: (-arg, arg - 1),
+ "MAP_ADD": lambda effect, arg, jump: (-arg, arg - 2),
+ "FORMAT_VALUE": lambda effect, arg, jump: (effect - 1, 1),
+ # FOR_ITER needs TOS to be an iterator, hence a prerequisite of 1 on the stack
+ "FOR_ITER": lambda effect, arg, jump: (effect, 0) if jump else (-1, 2),
+ **{
+ # Instr(UNPACK_* , n) pops 1 and pushes n
+ k: lambda effect, arg, jump: (-1, effect + 1)
+ for k in (
+ "UNPACK_SEQUENCE",
+ "UNPACK_EX",
+ )
+ },
+ **{
+ k: lambda effect, arg, jump: (effect - 1, 1)
+ for k in (
+ "MAKE_FUNCTION",
+ "CALL_FUNCTION",
+ "CALL_FUNCTION_EX",
+ "CALL_FUNCTION_KW",
+ "CALL_METHOD",
+ *(o for o in _opcode.opmap if o.startswith("BUILD_")),
+ )
+ },
+}
+
+
+# --- Instruction location
+
+
+def _check_location(
+ location: Optional[int], location_name: str, min_value: int
+) -> None:
+ if location is None:
+ return
+ if not isinstance(location, int):
+ raise TypeError(f"{location_name} must be an int, got {type(location)}")
+ if location < min_value:
+ raise ValueError(
+ f"invalid {location_name}, expected >= {min_value}, got {location}"
+ )
+
+
+@dataclass(frozen=True)
+class InstrLocation:
+ """Location information for an instruction."""
+
+ #: Lineno at which the instruction corresponds.
+ #: Optional so that a location of None in an instruction encode an unset value.
+ lineno: Optional[int]
+
+ #: End lineno at which the instruction corresponds (Python 3.11+ only)
+ end_lineno: Optional[int]
+
+ #: Column offset at which the instruction corresponds (Python 3.11+ only)
+ col_offset: Optional[int]
+
+ #: End column offset at which the instruction corresponds (Python 3.11+ only)
+ end_col_offset: Optional[int]
+
+ __slots__ = ["lineno", "end_lineno", "col_offset", "end_col_offset"]
+
+ def __init__(
+ self,
+ lineno: Optional[int],
+ end_lineno: Optional[int],
+ col_offset: Optional[int],
+ end_col_offset: Optional[int],
+ ) -> None:
+ # Needed because we want the class to be frozen
+ object.__setattr__(self, "lineno", lineno)
+ object.__setattr__(self, "end_lineno", end_lineno)
+ object.__setattr__(self, "col_offset", col_offset)
+ object.__setattr__(self, "end_col_offset", end_col_offset)
+ # In Python 3.11 0 is a valid lineno for some instructions (RESUME for example)
+ _check_location(lineno, "lineno", 0 if sys.version_info >= (3, 11) else 1)
+ _check_location(end_lineno, "end_lineno", 1)
+ _check_location(col_offset, "col_offset", 0)
+ _check_location(end_col_offset, "end_col_offset", 0)
+ if end_lineno:
+ if lineno is None:
+ raise ValueError("End lineno specified with no lineno.")
+ elif lineno > end_lineno:
+ raise ValueError(
+ f"End lineno {end_lineno} cannot be smaller than lineno {lineno}."
+ )
+
+ if col_offset is not None or end_col_offset is not None:
+ if lineno is None or end_lineno is None:
+ raise ValueError(
+ "Column offsets were specified but lineno information are "
+ f"incomplete. Lineno: {lineno}, end lineno: {end_lineno}."
+ )
+ if end_col_offset is not None:
+ if col_offset is None:
+ raise ValueError(
+ "End column offset specified with no column offset."
+ )
+ # Column offset must be increasing inside a signle line but
+ # have no relations between different lines.
+ elif lineno == end_lineno and col_offset > end_col_offset:
+ raise ValueError(
+ f"End column offset {end_col_offset} cannot be smaller than "
+ f"column offset: {col_offset}."
+ )
+ else:
+ raise ValueError(
+ "No end column offset was specified but a column offset was given."
+ )
+
+ @classmethod
+ def from_positions(cls, position: "dis.Positions") -> "InstrLocation": # type: ignore
+ return InstrLocation(
+ position.lineno,
+ position.end_lineno,
+ position.col_offset,
+ position.end_col_offset,
+ )
+
+
+class SetLineno:
+ __slots__ = ("_lineno",)
+
+ def __init__(self, lineno: int) -> None:
+ # In Python 3.11 0 is a valid lineno for some instructions (RESUME for example)
+ _check_location(lineno, "lineno", 0 if sys.version_info >= (3, 11) else 1)
+ self._lineno: int = lineno
+
+ @property
+ def lineno(self) -> int:
+ return self._lineno
+
+ def __eq__(self, other: Any) -> bool:
+ if not isinstance(other, SetLineno):
+ return False
+ return self._lineno == other._lineno
+
+
+# --- Pseudo instructions used to represent exception handling (3.11+)
+
+
+class TryBegin:
+ __slots__ = ("target", "push_lasti", "stack_depth")
+
+ def __init__(
+ self,
+ target: Union[Label, "_bytecode.BasicBlock"],
+ push_lasti: bool,
+ stack_depth: Union[int, _UNSET] = UNSET,
+ ) -> None:
+ self.target: Union[Label, "_bytecode.BasicBlock"] = target
+ self.push_lasti: bool = push_lasti
+ self.stack_depth: Union[int, _UNSET] = stack_depth
+
+ def copy(self) -> "TryBegin":
+ return TryBegin(self.target, self.push_lasti, self.stack_depth)
+
+
+class TryEnd:
+ __slots__ = "entry"
+
+ def __init__(self, entry: TryBegin) -> None:
+ self.entry: TryBegin = entry
+
+ def copy(self) -> "TryEnd":
+ return TryEnd(self.entry)
+
+
+T = TypeVar("T", bound="BaseInstr")
+A = TypeVar("A", bound=object)
+
+
+class BaseInstr(Generic[A]):
+ """Abstract instruction."""
+
+ __slots__ = ("_name", "_opcode", "_arg", "_location")
+
+ # Work around an issue with the default value of arg
+ def __init__(
+ self,
+ name: str,
+ arg: A = UNSET, # type: ignore
+ *,
+ lineno: Union[int, None, _UNSET] = UNSET,
+ location: Optional[InstrLocation] = None,
+ ) -> None:
+ self._set(name, arg)
+ if location:
+ self._location = location
+ elif lineno is UNSET:
+ self._location = None
+ else:
+ self._location = InstrLocation(lineno, None, None, None)
+
+ # Work around an issue with the default value of arg
+ def set(self, name: str, arg: A = UNSET) -> None: # type: ignore
+ """Modify the instruction in-place.
+
+ Replace name and arg attributes. Don't modify lineno.
+
+ """
+ self._set(name, arg)
+
+ def require_arg(self) -> bool:
+ """Does the instruction require an argument?"""
+ return opcode_has_argument(self._opcode)
+
+ @property
+ def name(self) -> str:
+ return self._name
+
+ @name.setter
+ def name(self, name: str) -> None:
+ self._set(name, self._arg)
+
+ @property
+ def opcode(self) -> int:
+ return self._opcode
+
+ @opcode.setter
+ def opcode(self, op: int) -> None:
+ if not isinstance(op, int):
+ raise TypeError("operator code must be an int")
+ if 0 <= op <= 255:
+ name = _opcode.opname[op]
+ valid = name != "<%r>" % op
+ else:
+ valid = False
+ if not valid:
+ raise ValueError("invalid operator code")
+
+ self._set(name, self._arg)
+
+ @property
+ def arg(self) -> A:
+ return self._arg
+
+ @arg.setter
+ def arg(self, arg: A):
+ self._set(self._name, arg)
+
+ @property
+ def lineno(self) -> Union[int, _UNSET, None]:
+ return self._location.lineno if self._location is not None else UNSET
+
+ @lineno.setter
+ def lineno(self, lineno: Union[int, _UNSET, None]) -> None:
+ loc = self._location
+ if loc and (
+ loc.end_lineno is not None
+ or loc.col_offset is not None
+ or loc.end_col_offset is not None
+ ):
+ raise RuntimeError(
+ "The lineno of an instruction with detailed location information "
+ "cannot be set."
+ )
+
+ if lineno is UNSET:
+ self._location = None
+ else:
+ self._location = InstrLocation(lineno, None, None, None)
+
+ @property
+ def location(self) -> Optional[InstrLocation]:
+ return self._location
+
+ @location.setter
+ def location(self, location: Optional[InstrLocation]) -> None:
+ if location and not isinstance(location, InstrLocation):
+ raise TypeError(
+ "The instr location must be an instance of InstrLocation or None."
+ )
+ self._location = location
+
+ def stack_effect(self, jump: Optional[bool] = None) -> int:
+ if not self.require_arg():
+ arg = None
+ # 3.11 where LOAD_GLOBAL arg encode whether or we push a null
+ # 3.12 does the same for LOAD_ATTR
+ elif self.name in BITFLAG_INSTRUCTIONS and isinstance(self._arg, tuple):
+ assert len(self._arg) == 2
+ arg = self._arg[0]
+ # 3.12 does a similar trick for LOAD_SUPER_ATTR
+ elif self.name in BITFLAG2_INSTRUCTIONS and isinstance(self._arg, tuple):
+ assert len(self._arg) == 3
+ arg = self._arg[0]
+ elif not isinstance(self._arg, int) or self._opcode in _opcode.hasconst:
+ # Argument is either a non-integer or an integer constant,
+ # not oparg.
+ arg = 0
+ else:
+ arg = self._arg
+
+ return dis.stack_effect(self._opcode, arg, jump=jump)
+
+ def pre_and_post_stack_effect(self, jump: Optional[bool] = None) -> Tuple[int, int]:
+ # Allow to check that execution will not cause a stack underflow
+ _effect = self.stack_effect(jump=jump)
+
+ n = self.name
+ if n in STATIC_STACK_EFFECTS:
+ return STATIC_STACK_EFFECTS[n]
+ elif n in DYNAMIC_STACK_EFFECTS:
+ return DYNAMIC_STACK_EFFECTS[n](_effect, self.arg, jump)
+ else:
+ # For instruction with no special value we simply consider the effect apply
+ # before execution
+ return (_effect, 0)
+
+ def copy(self: T) -> T:
+ return self.__class__(self._name, self._arg, location=self._location)
+
+ def has_jump(self) -> bool:
+ return self._has_jump(self._opcode)
+
+ def is_cond_jump(self) -> bool:
+ """Is a conditional jump?"""
+ # Ex: POP_JUMP_IF_TRUE, JUMP_IF_FALSE_OR_POP
+ # IN 3.11+ the JUMP and the IF are no necessary adjacent in the name.
+ name = self._name
+ return "JUMP_" in name and "IF_" in name
+
+ def is_uncond_jump(self) -> bool:
+ """Is an unconditional jump?"""
+ # JUMP_BACKWARD has been introduced in 3.11+
+ # JUMP_ABSOLUTE was removed in 3.11+
+ return self.name in {
+ "JUMP_FORWARD",
+ "JUMP_ABSOLUTE",
+ "JUMP_BACKWARD",
+ "JUMP_BACKWARD_NO_INTERRUPT",
+ }
+
+ def is_abs_jump(self) -> bool:
+ """Is an absolute jump."""
+ return self._opcode in _opcode.hasjabs
+
+ def is_forward_rel_jump(self) -> bool:
+ """Is a forward relative jump."""
+ return self._opcode in _opcode.hasjrel and "BACKWARD" not in self._name
+
+ def is_backward_rel_jump(self) -> bool:
+ """Is a backward relative jump."""
+ return self._opcode in _opcode.hasjrel and "BACKWARD" in self._name
+
+ def is_final(self) -> bool:
+ if self._name in {
+ "RETURN_VALUE",
+ "RETURN_CONST",
+ "RAISE_VARARGS",
+ "RERAISE",
+ "BREAK_LOOP",
+ "CONTINUE_LOOP",
+ }:
+ return True
+ if self.is_uncond_jump():
+ return True
+ return False
+
+ def __repr__(self) -> str:
+ if self._arg is not UNSET:
+ return "<%s arg=%r location=%s>" % (self._name, self._arg, self._location)
+ else:
+ return "<%s location=%s>" % (self._name, self._location)
+
+ def __eq__(self, other: Any) -> bool:
+ if type(self) is not type(other):
+ return False
+ return self._cmp_key() == other._cmp_key()
+
+ # --- Private API
+
+ _name: str
+
+ _location: Optional[InstrLocation]
+
+ _opcode: int
+
+ _arg: A
+
+ def _set(self, name: str, arg: A) -> None:
+ if not isinstance(name, str):
+ raise TypeError("operation name must be a str")
+ try:
+ opcode = _opcode.opmap[name]
+ except KeyError:
+ raise ValueError(f"invalid operation name: {name}")
+
+ if opcode >= MIN_INSTRUMENTED_OPCODE:
+ raise ValueError(
+ f"operation {name} is an instrumented or pseudo opcode. "
+ "Only base opcodes are supported"
+ )
+
+ self._check_arg(name, opcode, arg)
+
+ self._name = name
+ self._opcode = opcode
+ self._arg = arg
+
+ @staticmethod
+ def _has_jump(opcode) -> bool:
+ return opcode in _opcode.hasjrel or opcode in _opcode.hasjabs
+
+ @abstractmethod
+ def _check_arg(self, name: str, opcode: int, arg: A) -> None:
+ pass
+
+ @abstractmethod
+ def _cmp_key(self) -> Tuple[Optional[InstrLocation], str, Any]:
+ pass
+
+
+InstrArg = Union[
+ int,
+ str,
+ Label,
+ CellVar,
+ FreeVar,
+ "_bytecode.BasicBlock",
+ Compare,
+ Tuple[bool, str],
+ Tuple[bool, bool, str],
+]
+
+
+class Instr(BaseInstr[InstrArg]):
+ __slots__ = ()
+
+ def _cmp_key(self) -> Tuple[Optional[InstrLocation], str, Any]:
+ arg: Any = self._arg
+ if self._opcode in _opcode.hasconst:
+ arg = const_key(arg)
+ return (self._location, self._name, arg)
+
+ def _check_arg(self, name: str, opcode: int, arg: InstrArg) -> None:
+ if name == "EXTENDED_ARG":
+ raise ValueError(
+ "only concrete instruction can contain EXTENDED_ARG, "
+ "highlevel instruction can represent arbitrary argument without it"
+ )
+
+ if opcode_has_argument(opcode):
+ if arg is UNSET:
+ raise ValueError("operation %s requires an argument" % name)
+ else:
+ if arg is not UNSET:
+ raise ValueError("operation %s has no argument" % name)
+
+ if self._has_jump(opcode):
+ if not isinstance(arg, (Label, _bytecode.BasicBlock)):
+ raise TypeError(
+ "operation %s argument type must be "
+ "Label or BasicBlock, got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode in _opcode.hasfree:
+ if not isinstance(arg, (CellVar, FreeVar)):
+ raise TypeError(
+ "operation %s argument must be CellVar "
+ "or FreeVar, got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode in _opcode.haslocal or opcode in _opcode.hasname:
+ if name in BITFLAG_INSTRUCTIONS:
+ if not (
+ isinstance(arg, tuple)
+ and len(arg) == 2
+ and isinstance(arg[0], bool)
+ and isinstance(arg[1], str)
+ ):
+ raise TypeError(
+ "operation %s argument must be a tuple[bool, str], "
+ "got %s (value=%s)" % (name, type(arg).__name__, str(arg))
+ )
+
+ elif name in BITFLAG2_INSTRUCTIONS:
+ if not (
+ isinstance(arg, tuple)
+ and len(arg) == 3
+ and isinstance(arg[0], bool)
+ and isinstance(arg[1], bool)
+ and isinstance(arg[2], str)
+ ):
+ raise TypeError(
+ "operation %s argument must be a tuple[bool, bool, str], "
+ "got %s (value=%s)" % (name, type(arg).__name__, str(arg))
+ )
+
+ elif not isinstance(arg, str):
+ raise TypeError(
+ "operation %s argument must be a str, "
+ "got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode in _opcode.hasconst:
+ if isinstance(arg, Label):
+ raise ValueError(
+ "label argument cannot be used " "in %s operation" % name
+ )
+ if isinstance(arg, _bytecode.BasicBlock):
+ raise ValueError(
+ "block argument cannot be used " "in %s operation" % name
+ )
+
+ elif opcode in _opcode.hascompare:
+ if not isinstance(arg, Compare):
+ raise TypeError(
+ "operation %s argument type must be "
+ "Compare, got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode in INTRINSIC_1OP:
+ if not isinstance(arg, Intrinsic1Op):
+ raise TypeError(
+ "operation %s argument type must be "
+ "Intrinsic1Op, got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode in INTRINSIC_2OP:
+ if not isinstance(arg, Intrinsic2Op):
+ raise TypeError(
+ "operation %s argument type must be "
+ "Intrinsic2Op, got %s" % (name, type(arg).__name__)
+ )
+
+ elif opcode_has_argument(opcode):
+ _check_arg_int(arg, name)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/py.typed b/lambdas/aws-dd-forwarder-3.127.0/bytecode/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/bytecode/version.py b/lambdas/aws-dd-forwarder-3.127.0/bytecode/version.py
new file mode 100644
index 0000000..2d91554
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/bytecode/version.py
@@ -0,0 +1,19 @@
+# This file is auto-generated by setuptools-scm do NOT edit it.
+
+from collections import namedtuple
+
+#: A namedtuple of the version info for the current release.
+_version_info = namedtuple("_version_info", "major minor micro status")
+
+parts = "0.15.1".split(".", 3)
+version_info = _version_info(
+ int(parts[0]),
+ int(parts[1]),
+ int(parts[2]),
+ parts[3] if len(parts) == 4 else "",
+)
+
+# Remove everything but the 'version_info' from this module.
+del namedtuple, _version_info, parts
+
+__version__ = "0.15.1"
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/base_tags_cache.py b/lambdas/aws-dd-forwarder-3.127.0/caching/base_tags_cache.py
new file mode 100644
index 0000000..c38aa00
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/base_tags_cache.py
@@ -0,0 +1,172 @@
+import json
+import logging
+import os
+from random import randint
+from time import time
+
+import boto3
+from botocore.exceptions import ClientError
+
+from caching.common import get_last_modified_time
+from settings import (
+ DD_S3_BUCKET_NAME,
+ DD_S3_CACHE_DIRNAME,
+ DD_S3_CACHE_LOCK_TTL_SECONDS,
+ DD_TAGS_CACHE_TTL_SECONDS,
+)
+from telemetry import send_forwarder_internal_metrics
+
+JITTER_MIN = 1
+JITTER_MAX = 100
+DD_TAGS_CACHE_TTL_SECONDS = DD_TAGS_CACHE_TTL_SECONDS + randint(JITTER_MIN, JITTER_MAX)
+
+
+class BaseTagsCache(object):
+ def __init__(
+ self,
+ prefix,
+ cache_filename,
+ cache_lock_filename,
+ tags_ttl_seconds=DD_TAGS_CACHE_TTL_SECONDS,
+ ):
+ self.cache_dirname = DD_S3_CACHE_DIRNAME
+ self.tags_ttl_seconds = tags_ttl_seconds
+ self.tags_by_id = {}
+ self.last_tags_fetch_time = 0
+ self.cache_prefix = prefix
+ self.cache_filename = cache_filename
+ self.cache_lock_filename = cache_lock_filename
+ self.logger = logging.getLogger()
+ self.logger.setLevel(
+ logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper())
+ )
+ self.resource_tagging_client = boto3.client("resourcegroupstaggingapi")
+ self.s3_client = boto3.resource("s3")
+
+ def get_resources_paginator(self):
+ return self.resource_tagging_client.get_paginator("get_resources")
+
+ def get_cache_name_with_prefix(self):
+ return f"{self.cache_dirname}/{self.cache_prefix}_{self.cache_filename}"
+
+ def get_cache_lock_with_prefix(self):
+ return f"{self.cache_dirname}/{self.cache_prefix}_{self.cache_lock_filename}"
+
+ def write_cache_to_s3(self, data):
+ """Writes tags cache to s3"""
+ try:
+ self.logger.debug("Trying to write data to s3: {}".format(data))
+ s3_object = self.s3_client.Object(
+ DD_S3_BUCKET_NAME, self.get_cache_name_with_prefix()
+ )
+ s3_object.put(Body=(bytes(json.dumps(data).encode("UTF-8"))))
+ except ClientError:
+ send_forwarder_internal_metrics("s3_cache_write_failure")
+ self.logger.debug("Unable to write new cache to S3", exc_info=True)
+
+ def acquire_s3_cache_lock(self):
+ """Acquire cache lock"""
+ cache_lock_object = self.s3_client.Object(
+ DD_S3_BUCKET_NAME, self.get_cache_lock_with_prefix()
+ )
+ try:
+ file_content = cache_lock_object.get()
+
+ # check lock file expiration
+ last_modified_unix_time = get_last_modified_time(file_content)
+ if last_modified_unix_time + DD_S3_CACHE_LOCK_TTL_SECONDS >= time():
+ return False
+ except Exception:
+ self.logger.debug("Unable to get cache lock file")
+
+ # lock file doesn't exist, create file to acquire lock
+ try:
+ cache_lock_object.put(Body=(bytes("lock".encode("UTF-8"))))
+ send_forwarder_internal_metrics("s3_cache_lock_acquired")
+ self.logger.debug("S3 cache lock acquired")
+ except ClientError:
+ self.logger.debug("Unable to write S3 cache lock file", exc_info=True)
+ return False
+
+ return True
+
+ def release_s3_cache_lock(self):
+ """Release cache lock"""
+ try:
+ cache_lock_object = self.s3_client.Object(
+ DD_S3_BUCKET_NAME, self.get_cache_lock_with_prefix()
+ )
+ cache_lock_object.delete()
+ send_forwarder_internal_metrics("s3_cache_lock_released")
+ self.logger.debug("S3 cache lock released")
+ except ClientError:
+ send_forwarder_internal_metrics("s3_cache_lock_release_failure")
+ self.logger.debug("Unable to release S3 cache lock", exc_info=True)
+
+ def get_cache_from_s3(self):
+ """Retrieves tags cache from s3 and returns the body along with
+ the last modified datetime for the cache"""
+ cache_object = self.s3_client.Object(
+ DD_S3_BUCKET_NAME, self.get_cache_name_with_prefix()
+ )
+ try:
+ file_content = cache_object.get()
+ tags_cache = json.loads(file_content["Body"].read().decode("utf-8"))
+ last_modified_unix_time = get_last_modified_time(file_content)
+ except:
+ send_forwarder_internal_metrics("s3_cache_fetch_failure")
+ self.logger.debug("Unable to fetch cache from S3", exc_info=True)
+ return {}, -1
+
+ return tags_cache, last_modified_unix_time
+
+ def _refresh(self):
+ """Populate the tags in the local cache by getting cache from s3
+ If cache not in s3, then cache is built using build_tags_cache
+ """
+ self.last_tags_fetch_time = time()
+
+ # If the custom tag fetch env var is not set to true do not fetch
+ if not self.should_fetch_tags():
+ self.logger.debug(
+ "Not fetching custom tags because the env variable for the cache {} is not set to true".format(
+ self.cache_filename
+ )
+ )
+ return
+
+ tags_fetched, last_modified = self.get_cache_from_s3()
+
+ if self._is_expired(last_modified):
+ send_forwarder_internal_metrics("s3_cache_expired")
+ self.logger.debug("S3 cache expired, rebuilding cache")
+ lock_acquired = self.acquire_s3_cache_lock()
+ if lock_acquired:
+ success, new_tags_fetched = self.build_tags_cache()
+ if success:
+ self.tags_by_id = new_tags_fetched
+ self.write_cache_to_s3(self.tags_by_id)
+ elif tags_fetched != {}:
+ self.tags_by_id = tags_fetched
+
+ self.release_s3_cache_lock()
+ # s3 cache fetch succeeded and isn't expired
+ elif last_modified > -1:
+ self.tags_by_id = tags_fetched
+
+ def _is_expired(self, last_modified=None):
+ """Returns bool for whether the fetch TTL has expired"""
+ if not last_modified:
+ last_modified = self.last_tags_fetch_time
+
+ earliest_time_to_refetch_tags = last_modified + self.tags_ttl_seconds
+ return time() > earliest_time_to_refetch_tags
+
+ def should_fetch_tags(self):
+ raise Exception("SHOULD FETCH TAGS MUST BE DEFINED FOR TAGS CACHES")
+
+ def get(self, key):
+ raise Exception("GET TAGS MUST BE DEFINED FOR TAGS CACHES")
+
+ def build_tags_cache(self):
+ raise Exception("BUILD TAGS MUST BE DEFINED FOR TAGS CACHES")
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/cache_layer.py b/lambdas/aws-dd-forwarder-3.127.0/caching/cache_layer.py
new file mode 100644
index 0000000..eef6a53
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/cache_layer.py
@@ -0,0 +1,24 @@
+from caching.cloudwatch_log_group_cache import CloudwatchLogGroupTagsCache
+from caching.step_functions_cache import StepFunctionsTagsCache
+from caching.s3_tags_cache import S3TagsCache
+from caching.lambda_cache import LambdaTagsCache
+
+
+class CacheLayer:
+ def __init__(self, prefix):
+ self._cloudwatch_log_group_cache = CloudwatchLogGroupTagsCache(prefix)
+ self._s3_tags_cache = S3TagsCache(prefix)
+ self._step_functions_cache = StepFunctionsTagsCache(prefix)
+ self._lambda_cache = LambdaTagsCache(prefix)
+
+ def get_cloudwatch_log_group_tags_cache(self):
+ return self._cloudwatch_log_group_cache
+
+ def get_s3_tags_cache(self):
+ return self._s3_tags_cache
+
+ def get_step_functions_tags_cache(self):
+ return self._step_functions_cache
+
+ def get_lambda_tags_cache(self):
+ return self._lambda_cache
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/cloudwatch_log_group_cache.py b/lambdas/aws-dd-forwarder-3.127.0/caching/cloudwatch_log_group_cache.py
new file mode 100644
index 0000000..f20d9a5
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/cloudwatch_log_group_cache.py
@@ -0,0 +1,194 @@
+import json
+import logging
+import os
+from random import randint
+from time import time
+
+import boto3
+from botocore.config import Config
+
+from caching.common import sanitize_aws_tag_string
+from settings import (
+ DD_S3_BUCKET_NAME,
+ DD_S3_CACHE_DIRNAME,
+ DD_S3_LOG_GROUP_CACHE_DIRNAME,
+ DD_TAGS_CACHE_TTL_SECONDS,
+)
+from telemetry import send_forwarder_internal_metrics
+
+
+class CloudwatchLogGroupTagsCache:
+ def __init__(
+ self,
+ prefix,
+ ):
+ self.cache_dirname = f"{DD_S3_CACHE_DIRNAME}/{DD_S3_LOG_GROUP_CACHE_DIRNAME}"
+ self.cache_ttl_seconds = DD_TAGS_CACHE_TTL_SECONDS
+ self.bucket_name = DD_S3_BUCKET_NAME
+ self.cache_prefix = prefix
+ self.tags_by_log_group = {}
+ # We need to use the standard retry mode for the Cloudwatch Logs client that defaults to 3 retries
+ self.cloudwatch_logs_client = boto3.client(
+ "logs", config=Config(retries={"mode": "standard"})
+ )
+ self.s3_client = boto3.client("s3")
+
+ self.logger = logging.getLogger()
+ self.logger.setLevel(
+ logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper())
+ )
+
+ # Initialize the cache
+ if self._should_fetch_tags():
+ self._build_tags_cache()
+
+ def get(self, log_group_arn):
+ """Get the tags for the Cloudwatch Log Group from the cache
+
+ Will refetch the tags if they are out of date, or a log group is encountered
+ which isn't in the tag list
+
+ Args:
+ key (str): the key we're getting tags from the cache for
+
+ Returns:
+ log_group_tags (str[]): the list of "key:value" Datadog tag strings
+ """
+ # If the custom tag fetch env var is not set to true do not fetch tags
+ if not self._should_fetch_tags():
+ self.logger.debug(
+ "Not fetching custom tags because the env variable DD_FETCH_LOG_GROUP_TAGS is "
+ "not set to true"
+ )
+ return []
+
+ return self._fetch_log_group_tags(log_group_arn)
+
+ def _should_fetch_tags(self):
+ return os.environ.get("DD_FETCH_LOG_GROUP_TAGS", "false").lower() == "true"
+
+ def _build_tags_cache(self):
+ try:
+ prefix = self._get_cache_file_prefix()
+ response = self.s3_client.list_objects_v2(
+ Bucket=DD_S3_BUCKET_NAME, Prefix=prefix
+ )
+ cache_files = [content["Key"] for content in response.get("Contents", [])]
+ for cache_file in cache_files:
+ log_group_tags, last_modified = self._get_log_group_tags_from_cache(
+ cache_file
+ )
+ if log_group_tags and not self._is_expired(last_modified):
+ log_group = cache_file.split("/")[-1].split(".")[0]
+ self.tags_by_log_group[log_group] = {
+ "tags": log_group_tags,
+ "last_modified": last_modified,
+ }
+ self.logger.debug(
+ f"loggroup_tags_cache initialized successfully {self.tags_by_log_group}"
+ )
+ except Exception:
+ self.logger.exception("failed to build log group tags cache", exc_info=True)
+
+ def _fetch_log_group_tags(self, log_group_arn):
+ # first, check in-memory cache
+ log_group_tags_struct = self.tags_by_log_group.get(log_group_arn, None)
+ if log_group_tags_struct and not self._is_expired(
+ log_group_tags_struct.get("last_modified", None)
+ ):
+ send_forwarder_internal_metrics("loggroup_local_cache_hit")
+ return log_group_tags_struct.get("tags", [])
+
+ # then, check cache file, update and return
+ cache_file_name = self._get_cache_file_name(log_group_arn)
+ log_group_tags, last_modified = self._get_log_group_tags_from_cache(
+ cache_file_name
+ )
+ if log_group_tags and not self._is_expired(last_modified):
+ self.tags_by_log_group[log_group_arn] = {
+ "tags": log_group_tags,
+ "last_modified": time(),
+ }
+ send_forwarder_internal_metrics("loggroup_s3_cache_hit")
+ return log_group_tags
+
+ # finally, make an api call, update and return
+ log_group_tags = self._get_log_group_tags(log_group_arn) or []
+ self._update_log_group_tags_cache(log_group_arn, log_group_tags)
+ self.tags_by_log_group[log_group_arn] = {
+ "tags": log_group_tags,
+ "last_modified": time(),
+ }
+
+ return log_group_tags
+
+ def _get_log_group_tags_from_cache(self, cache_file_name):
+ try:
+ response = self.s3_client.get_object(
+ Bucket=self.bucket_name, Key=cache_file_name
+ )
+ tags_cache = json.loads(response.get("Body").read().decode("utf-8"))
+ last_modified_unix_time = int(response.get("LastModified").timestamp())
+ except Exception:
+ send_forwarder_internal_metrics("loggroup_cache_fetch_failure")
+ self.logger.exception(
+ "Failed to get log group tags from cache", exc_info=True
+ )
+ return None, -1
+
+ return tags_cache, last_modified_unix_time
+
+ def _update_log_group_tags_cache(self, log_group, tags):
+ cache_file_name = self._get_cache_file_name(log_group)
+ try:
+ self.s3_client.put_object(
+ Bucket=self.bucket_name,
+ Key=cache_file_name,
+ Body=(bytes(json.dumps(tags).encode("UTF-8"))),
+ )
+ except Exception:
+ send_forwarder_internal_metrics("loggroup_cache_write_failure")
+ self.logger.exception(
+ "Failed to update log group tags cache", exc_info=True
+ )
+
+ def _is_expired(self, last_modified):
+ if not last_modified:
+ return True
+
+ # add a random number of seconds to avoid having all tags refetched at the same time
+ earliest_time_to_refetch_tags = (
+ last_modified + self.cache_ttl_seconds + randint(1, 100)
+ )
+ return time() > earliest_time_to_refetch_tags
+
+ def _get_cache_file_name(self, log_group_arn):
+ log_group_name = log_group_arn.replace("/", "_").replace(":", "_")
+ return f"{self._get_cache_file_prefix()}/{log_group_name}.json"
+
+ def _get_cache_file_prefix(self):
+ return f"{self.cache_dirname}/{self.cache_prefix}"
+
+ def _get_log_group_tags(self, log_group_arn):
+ response = None
+ try:
+ send_forwarder_internal_metrics("list_tags_log_group_api_call")
+ response = self.cloudwatch_logs_client.list_tags_for_resource(
+ resourceArn=log_group_arn
+ )
+ except Exception:
+ self.logger.exception("Failed to get log group tags", exc_info=True)
+ formatted_tags = None
+ if response is not None:
+ formatted_tags = [
+ (
+ "{key}:{value}".format(
+ key=sanitize_aws_tag_string(k, remove_colons=True),
+ value=sanitize_aws_tag_string(v, remove_leading_digits=False),
+ )
+ if v
+ else sanitize_aws_tag_string(k, remove_colons=True)
+ )
+ for k, v in response["tags"].items()
+ ]
+ return formatted_tags
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/common.py b/lambdas/aws-dd-forwarder-3.127.0/caching/common.py
new file mode 100644
index 0000000..7d7db88
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/common.py
@@ -0,0 +1,103 @@
+import os
+import datetime
+import logging
+import re
+from collections import defaultdict
+
+logger = logging.getLogger()
+logger.setLevel(logging.getLevelName(os.environ.get("DD_LOG_LEVEL", "INFO").upper()))
+
+
+_other_chars = r"\w:\-\.\/"
+Sanitize = re.compile(r"[^%s]" % _other_chars, re.UNICODE).sub
+Dedupe = re.compile(r"_+", re.UNICODE).sub
+FixInit = re.compile(r"^[_\d]*", re.UNICODE).sub
+
+
+def get_last_modified_time(s3_file):
+ last_modified_str = s3_file["ResponseMetadata"]["HTTPHeaders"]["last-modified"]
+ last_modified_date = datetime.datetime.strptime(
+ last_modified_str, "%a, %d %b %Y %H:%M:%S %Z"
+ )
+ last_modified_unix_time = int(last_modified_date.strftime("%s"))
+ return last_modified_unix_time
+
+
+def parse_get_resources_response_for_tags_by_arn(get_resources_page):
+ """Parses a page of GetResources response for the mapping from ARN to tags
+
+ Args:
+ get_resources_page (dict[]>): one page of the GetResources response.
+ Partial example:
+ {"ResourceTagMappingList": [{
+ 'ResourceARN': 'arn:aws:lambda:us-east-1:123497598159:function:my-test-lambda',
+ 'Tags': [{'Key': 'stage', 'Value': 'dev'}, {'Key': 'team', 'Value': 'serverless'}]
+ }]}
+
+ Returns:
+ tags_by_arn (dict): Lambda tag lists keyed by ARN
+ """
+ tags_by_arn = defaultdict(list)
+
+ aws_resouce_tag_mappings = get_resources_page["ResourceTagMappingList"]
+ for aws_resource_tag_mapping in aws_resouce_tag_mappings:
+ function_arn = aws_resource_tag_mapping["ResourceARN"]
+ lowercase_function_arn = function_arn.lower()
+
+ raw_aws_tags = aws_resource_tag_mapping["Tags"]
+ tags = map(get_dd_tag_string_from_aws_dict, raw_aws_tags)
+
+ tags_by_arn[lowercase_function_arn] += tags
+
+ return tags_by_arn
+
+
+def get_dd_tag_string_from_aws_dict(aws_key_value_tag_dict):
+ """Converts the AWS dict tag format to the dd key:value string format and truncates to 200 characters
+
+ Args:
+ aws_key_value_tag_dict (dict): the dict the GetResources endpoint returns for a tag
+ ex: { "Key": "creator", "Value": "swf"}
+
+ Returns:
+ key:value colon-separated string built from the dict
+ ex: "creator:swf"
+ """
+ key = sanitize_aws_tag_string(aws_key_value_tag_dict["Key"], remove_colons=True)
+ value = sanitize_aws_tag_string(
+ aws_key_value_tag_dict.get("Value"), remove_leading_digits=False
+ )
+ # Value is optional in DD and AWS
+ if not value:
+ return key
+ return f"{key}:{value}"[0:200]
+
+
+def sanitize_aws_tag_string(tag, remove_colons=False, remove_leading_digits=True):
+ """Convert characters banned from DD but allowed in AWS tags to underscores"""
+ global Sanitize, Dedupe, FixInit
+
+ # 1. Replace colons with _
+ # 2. Convert to all lowercase unicode string
+ # 3. Convert bad characters to underscores
+ # 4. Dedupe contiguous underscores
+ # 5. Remove initial underscores/digits such that the string
+ # starts with an alpha char
+ # FIXME: tag normalization incorrectly supports tags starting
+ # with a ':', but this behavior should be phased out in future
+ # as it results in unqueryable data. See dogweb/#11193
+ # 6. Strip trailing underscores
+
+ if len(tag) == 0:
+ # if tag is empty, nothing to do
+ return tag
+
+ if remove_colons:
+ tag = tag.replace(":", "_")
+ tag = Dedupe("_", Sanitize("_", tag.lower()))
+ if remove_leading_digits:
+ first_char = tag[0]
+ if first_char == "_" or "0" <= first_char <= "9":
+ tag = FixInit("", tag)
+ tag = tag.rstrip("_")
+ return tag
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/lambda_cache.py b/lambdas/aws-dd-forwarder-3.127.0/caching/lambda_cache.py
new file mode 100644
index 0000000..e1d28e0
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/lambda_cache.py
@@ -0,0 +1,90 @@
+import os
+
+from botocore.exceptions import ClientError
+
+from caching.base_tags_cache import BaseTagsCache
+from caching.common import parse_get_resources_response_for_tags_by_arn
+from settings import (
+ DD_S3_LAMBDA_CACHE_FILENAME,
+ DD_S3_LAMBDA_CACHE_LOCK_FILENAME,
+ GET_RESOURCES_LAMBDA_FILTER,
+)
+from telemetry import send_forwarder_internal_metrics
+
+
+class LambdaTagsCache(BaseTagsCache):
+ def __init__(self, prefix):
+ super().__init__(
+ prefix, DD_S3_LAMBDA_CACHE_FILENAME, DD_S3_LAMBDA_CACHE_LOCK_FILENAME
+ )
+
+ def should_fetch_tags(self):
+ return os.environ.get("DD_FETCH_LAMBDA_TAGS", "false").lower() == "true"
+
+ def build_tags_cache(self):
+ """Makes API calls to GetResources to get the live tags of the account's Lambda functions
+
+ Returns an empty dict instead of fetching custom tags if the tag fetch env variable is not set to true
+
+ Returns:
+ tags_by_arn_cache (dict): each Lambda's tags in a dict keyed by ARN
+ """
+ tags_fetch_success = False
+ tags_by_arn_cache = {}
+ resource_paginator = self.get_resources_paginator()
+
+ try:
+ for page in resource_paginator.paginate(
+ ResourceTypeFilters=[GET_RESOURCES_LAMBDA_FILTER], ResourcesPerPage=100
+ ):
+ send_forwarder_internal_metrics("get_resources_api_calls")
+ page_tags_by_arn = parse_get_resources_response_for_tags_by_arn(page)
+ tags_by_arn_cache.update(page_tags_by_arn)
+ tags_fetch_success = True
+
+ except ClientError as e:
+ self.logger.exception(
+ "Encountered a ClientError when trying to fetch tags. You may need to give "
+ "this Lambda's role the 'tag:GetResources' permission"
+ )
+ additional_tags = [
+ f"http_status_code:{e.response['ResponseMetadata']['HTTPStatusCode']}"
+ ]
+ send_forwarder_internal_metrics(
+ "client_error", additional_tags=additional_tags
+ )
+ tags_fetch_success = False
+
+ self.logger.debug(
+ "Built this tags cache from GetResources API calls: %s", tags_by_arn_cache
+ )
+
+ return tags_fetch_success, tags_by_arn_cache
+
+ def get(self, key):
+ """Get the tags for the Lambda function from the cache
+
+ Will refetch the tags if they are out of date, or a lambda arn is encountered
+ which isn't in the tag list
+
+ Note: the ARNs in the cache have been lowercased, so resource_arn must be lowercased
+
+ Args:
+ key (str): the key we're getting tags from the cache for
+
+ Returns:
+ lambda_tags (str[]): the list of "key:value" Datadog tag strings
+ """
+ if not self.should_fetch_tags():
+ self.logger.debug(
+ "Not fetching lambda function tags because the env variable DD_FETCH_LAMBDA_TAGS is "
+ "not set to true"
+ )
+ return []
+
+ if self._is_expired():
+ send_forwarder_internal_metrics("local_lambda_cache_expired")
+ self.logger.debug("Local cache expired, fetching cache from S3")
+ self._refresh()
+
+ return self.tags_by_id.get(key, [])
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/s3_tags_cache.py b/lambdas/aws-dd-forwarder-3.127.0/caching/s3_tags_cache.py
new file mode 100644
index 0000000..b60c873
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/s3_tags_cache.py
@@ -0,0 +1,64 @@
+from botocore.exceptions import ClientError
+from caching.base_tags_cache import BaseTagsCache
+from caching.common import parse_get_resources_response_for_tags_by_arn
+from telemetry import send_forwarder_internal_metrics
+from settings import (
+ DD_S3_TAGS_CACHE_FILENAME,
+ DD_S3_TAGS_CACHE_LOCK_FILENAME,
+ GET_RESOURCES_S3_FILTER,
+)
+
+
+class S3TagsCache(BaseTagsCache):
+ def __init__(self, prefix):
+ super().__init__(
+ prefix, DD_S3_TAGS_CACHE_FILENAME, DD_S3_TAGS_CACHE_LOCK_FILENAME
+ )
+
+ def should_fetch_tags(self):
+ return True
+
+ def build_tags_cache(self):
+ """Makes API calls to GetResources to get the live tags of the account's S3 buckets
+ Returns an empty dict instead of fetching custom tags if the tag fetch env variable is not set to true
+ Returns:
+ tags_by_arn_cache (dict): each S3 bucket's tags in a dict keyed by ARN
+ """
+ tags_fetch_success = False
+ tags_by_arn_cache = {}
+ resource_paginator = self.get_resources_paginator()
+
+ try:
+ for page in resource_paginator.paginate(
+ ResourceTypeFilters=[GET_RESOURCES_S3_FILTER], ResourcesPerPage=100
+ ):
+ send_forwarder_internal_metrics("get_s3_resources_api_calls")
+ page_tags_by_arn = parse_get_resources_response_for_tags_by_arn(page)
+ tags_by_arn_cache.update(page_tags_by_arn)
+ tags_fetch_success = True
+ except ClientError as e:
+ self.logger.exception(
+ "Encountered a ClientError when trying to fetch tags. You may need to give "
+ "this Lambda's role the 'tag:GetResources' permission"
+ )
+ additional_tags = [
+ f"http_status_code:{e.response['ResponseMetadata']['HTTPStatusCode']}"
+ ]
+ send_forwarder_internal_metrics(
+ "client_error", additional_tags=additional_tags
+ )
+ tags_fetch_success = False
+
+ self.logger.debug(
+ "Built this tags cache from GetResources API calls: %s", tags_by_arn_cache
+ )
+
+ return tags_fetch_success, tags_by_arn_cache
+
+ def get(self, bucket_arn):
+ if self._is_expired():
+ send_forwarder_internal_metrics("local_s3_tags_cache_expired")
+ self.logger.debug("Local cache expired, fetching cache from S3")
+ self._refresh()
+
+ return self.tags_by_id.get(bucket_arn, [])
diff --git a/lambdas/aws-dd-forwarder-3.127.0/caching/step_functions_cache.py b/lambdas/aws-dd-forwarder-3.127.0/caching/step_functions_cache.py
new file mode 100644
index 0000000..4b2c497
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/caching/step_functions_cache.py
@@ -0,0 +1,144 @@
+import os
+from botocore.exceptions import ClientError
+from caching.base_tags_cache import BaseTagsCache
+from caching.common import (
+ sanitize_aws_tag_string,
+ parse_get_resources_response_for_tags_by_arn,
+)
+from telemetry import send_forwarder_internal_metrics
+from settings import (
+ DD_S3_STEP_FUNCTIONS_CACHE_FILENAME,
+ DD_S3_STEP_FUNCTIONS_CACHE_LOCK_FILENAME,
+ GET_RESOURCES_STEP_FUNCTIONS_FILTER,
+)
+
+
+class StepFunctionsTagsCache(BaseTagsCache):
+ def __init__(self, prefix):
+ super().__init__(
+ prefix,
+ DD_S3_STEP_FUNCTIONS_CACHE_FILENAME,
+ DD_S3_STEP_FUNCTIONS_CACHE_LOCK_FILENAME,
+ )
+
+ def should_fetch_tags(self):
+ return os.environ.get("DD_FETCH_STEP_FUNCTIONS_TAGS", "false").lower() == "true"
+
+ def build_tags_cache(self):
+ """Makes API calls to GetResources to get the live tags of the account's Step Functions
+ Returns an empty dict instead of fetching custom tags if the tag fetch env variable is not
+ set to true.
+ Returns:
+ tags_by_arn_cache (dict): each Lambda's tags in a dict keyed by ARN
+ """
+ tags_fetch_success = False
+ tags_by_arn_cache = {}
+ get_resources_paginator = self.get_resources_paginator()
+
+ try:
+ for page in get_resources_paginator.paginate(
+ ResourceTypeFilters=[GET_RESOURCES_STEP_FUNCTIONS_FILTER],
+ ResourcesPerPage=100,
+ ):
+ send_forwarder_internal_metrics(
+ "step_functions_get_resources_api_calls"
+ )
+ page_tags_by_arn = parse_get_resources_response_for_tags_by_arn(page)
+ tags_by_arn_cache.update(page_tags_by_arn)
+ tags_fetch_success = True
+
+ except ClientError as e:
+ self.logger.exception(
+ "Encountered a ClientError when trying to fetch tags. You may need to give "
+ "this Lambda's role the 'tag:GetResources' permission"
+ )
+ additional_tags = [
+ f"http_status_code:{e.response['ResponseMetadata']['HTTPStatusCode']}"
+ ]
+ send_forwarder_internal_metrics(
+ "client_error", additional_tags=additional_tags
+ )
+
+ self.logger.debug(
+ "All Step Functions tags refreshed: {}".format(tags_by_arn_cache)
+ )
+
+ return tags_fetch_success, tags_by_arn_cache
+
+ def get(self, state_machine_arn):
+ """Get the tags for the Step Functions from the cache
+
+ Will re-fetch the tags if they are out of date, or a log group is encountered
+ which isn't in the tag list
+
+ Args:
+ state_machine_arn (str): the key we're getting tags from the cache for
+
+ Returns:
+ state_machine_tags (List[str]): the list of "key:value" Datadog tag strings
+ """
+ if self._is_expired():
+ send_forwarder_internal_metrics("local_step_functions_tags_cache_expired")
+ self.logger.debug( # noqa: F821
+ "Local cache expired for Step Functions tags. Fetching cache from S3"
+ )
+ self._refresh()
+
+ state_machine_tags = self.tags_by_id.get(state_machine_arn, None)
+ if state_machine_tags is None:
+ # If the custom tag fetch env var is not set to true do not fetch
+ if not self.should_fetch_tags():
+ self.logger.debug(
+ "Not fetching custom tags because the env variable DD_FETCH_STEP_FUNCTIONS_TAGS"
+ " is not set to true"
+ )
+ return []
+ state_machine_tags = self._get_state_machine_tags(state_machine_arn) or []
+ self.tags_by_id[state_machine_arn] = state_machine_tags
+
+ return state_machine_tags
+
+ def _get_state_machine_tags(self, state_machine_arn: str):
+ """Return a list of tags of a state machine in dd format (max 200 chars)
+
+ Example response from get source api:
+ {
+ "ResourceTagMappingList": [
+ {
+ "ResourceARN": "arn:aws:states:us-east-1:1234567890:stateMachine:example-machine",
+ "Tags": [
+ {
+ "Key": "ENV",
+ "Value": "staging"
+ }
+ ]
+ }
+ ]
+ }
+
+ Args:
+ state_machine_arn (str): the key we're getting tags from the cache for
+ Returns:
+ state_machine_arn (List[str]): e.g. ["k1:v1", "k2:v2"]
+ """
+ response = None
+ formatted_tags = []
+
+ try:
+ send_forwarder_internal_metrics("get_state_machine_tags")
+ response = self.resource_tagging_client.get_resources(
+ ResourceARNList=[state_machine_arn]
+ )
+ except Exception as e:
+ self.logger.exception(f"Failed to get Step Functions tags due to {e}")
+
+ if response and len(response.get("ResourceTagMappingList", {})) > 0:
+ resource_dict = response.get("ResourceTagMappingList")[0]
+ for a_tag in resource_dict.get("Tags", []):
+ key = sanitize_aws_tag_string(a_tag["Key"], remove_colons=True)
+ value = sanitize_aws_tag_string(
+ a_tag.get("Value"), remove_leading_digits=False
+ )
+ formatted_tags.append(f"{key}:{value}"[:200]) # same logic as lambda
+
+ return formatted_tags
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/.DS_Store b/lambdas/aws-dd-forwarder-3.127.0/cattr/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..d86ee78a2df942869f542add7ddcfcb8b72b86c2
GIT binary patch
literal 6148
zcmeHKu};H447E!UMO`{F-Y@hILKVKCD^j2-G(*EhNDOTEX-s?sU&Hg+Dx@I;3j$FGSWw2Qo2>EOOqXrdz71p*yMu-fsAf49MNh
zaa$F2^o+avxW8(@TdwQacAwH7@oZyRZuW5lPwbbPm+RNd@qOF4{f2kf46-;wu8;VQ
z)fDN0?)!P3zTxB}kE8r{mfygum)D3_Kc9rdT$}-Cz!~^+44`I<%;t(dIs?vtGjL!)
zz7GK^SQsY7{OQ1uTL9n`<}8>?FCj6(urN%DSb?yH0yUJa#b6DGJ(yo%m=raf*qRTv
zli4~H&ZlGlkll$3MIW63XQ0o(i9Rl*{$Gvv|NS6;at54%f5iY#%XPWJD_LzFyqwh9
s0KI{Vh+k4XgkX|OF?^*IUqG|K9%KS643i=(5dR~PY4E`r_)!Ml0o%S%EdT%j
literal 0
HcmV?d00001
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/__init__.py
new file mode 100644
index 0000000..6c262fe
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/__init__.py
@@ -0,0 +1,25 @@
+from .converters import BaseConverter, Converter, GenConverter, UnstructureStrategy
+from .gen import override
+
+__all__ = (
+ "global_converter",
+ "unstructure",
+ "structure",
+ "structure_attrs_fromtuple",
+ "structure_attrs_fromdict",
+ "UnstructureStrategy",
+ "BaseConverter",
+ "Converter",
+ "GenConverter",
+ "override",
+)
+from cattrs import global_converter
+
+unstructure = global_converter.unstructure
+structure = global_converter.structure
+structure_attrs_fromtuple = global_converter.structure_attrs_fromtuple
+structure_attrs_fromdict = global_converter.structure_attrs_fromdict
+register_structure_hook = global_converter.register_structure_hook
+register_structure_hook_func = global_converter.register_structure_hook_func
+register_unstructure_hook = global_converter.register_unstructure_hook
+register_unstructure_hook_func = global_converter.register_unstructure_hook_func
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/converters.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/converters.py
new file mode 100644
index 0000000..4434fe5
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/converters.py
@@ -0,0 +1,8 @@
+from cattrs.converters import (
+ BaseConverter,
+ Converter,
+ GenConverter,
+ UnstructureStrategy,
+)
+
+__all__ = ["BaseConverter", "Converter", "GenConverter", "UnstructureStrategy"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/disambiguators.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/disambiguators.py
new file mode 100644
index 0000000..f10797a
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/disambiguators.py
@@ -0,0 +1,3 @@
+from cattrs.disambiguators import create_uniq_field_dis_func
+
+__all__ = ["create_uniq_field_dis_func"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/dispatch.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/dispatch.py
new file mode 100644
index 0000000..2474247
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/dispatch.py
@@ -0,0 +1,3 @@
+from cattrs.dispatch import FunctionDispatch, MultiStrategyDispatch
+
+__all__ = ["FunctionDispatch", "MultiStrategyDispatch"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/errors.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/errors.py
new file mode 100644
index 0000000..af092e9
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/errors.py
@@ -0,0 +1,15 @@
+from cattrs.errors import (
+ BaseValidationError,
+ ClassValidationError,
+ ForbiddenExtraKeysError,
+ IterableValidationError,
+ StructureHandlerNotFoundError,
+)
+
+__all__ = [
+ "BaseValidationError",
+ "ClassValidationError",
+ "ForbiddenExtraKeysError",
+ "IterableValidationError",
+ "StructureHandlerNotFoundError",
+]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/gen.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/gen.py
new file mode 100644
index 0000000..b1f63b5
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/gen.py
@@ -0,0 +1,21 @@
+from cattrs.cols import iterable_unstructure_factory as make_iterable_unstructure_fn
+from cattrs.gen import (
+ make_dict_structure_fn,
+ make_dict_unstructure_fn,
+ make_hetero_tuple_unstructure_fn,
+ make_mapping_structure_fn,
+ make_mapping_unstructure_fn,
+ override,
+)
+from cattrs.gen._consts import AttributeOverride
+
+__all__ = [
+ "AttributeOverride",
+ "make_dict_structure_fn",
+ "make_dict_unstructure_fn",
+ "make_hetero_tuple_unstructure_fn",
+ "make_iterable_unstructure_fn",
+ "make_mapping_structure_fn",
+ "make_mapping_unstructure_fn",
+ "override",
+]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/__init__.py
new file mode 100644
index 0000000..fa6ad35
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/__init__.py
@@ -0,0 +1,3 @@
+from cattrs.preconf import validate_datetime
+
+__all__ = ["validate_datetime"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/bson.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/bson.py
new file mode 100644
index 0000000..4ac9743
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/bson.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for bson."""
+
+from cattrs.preconf.bson import BsonConverter, configure_converter, make_converter
+
+__all__ = ["BsonConverter", "configure_converter", "make_converter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/json.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/json.py
new file mode 100644
index 0000000..d590bd6
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/json.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for the stdlib json."""
+
+from cattrs.preconf.json import JsonConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "JsonConverter", "make_converter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/msgpack.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/msgpack.py
new file mode 100644
index 0000000..1a579d6
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/msgpack.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for msgpack."""
+
+from cattrs.preconf.msgpack import MsgpackConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "make_converter", "MsgpackConverter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/orjson.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/orjson.py
new file mode 100644
index 0000000..4450990
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/orjson.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for orjson."""
+
+from cattrs.preconf.orjson import OrjsonConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "make_converter", "OrjsonConverter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/pyyaml.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/pyyaml.py
new file mode 100644
index 0000000..63d39f1
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/pyyaml.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for pyyaml."""
+
+from cattrs.preconf.pyyaml import PyyamlConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "make_converter", "PyyamlConverter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/tomlkit.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/tomlkit.py
new file mode 100644
index 0000000..6add731
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/tomlkit.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for tomlkit."""
+
+from cattrs.preconf.tomlkit import TomlkitConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "make_converter", "TomlkitConverter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/ujson.py b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/ujson.py
new file mode 100644
index 0000000..ef85c47
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattr/preconf/ujson.py
@@ -0,0 +1,5 @@
+"""Preconfigured converters for ujson."""
+
+from cattrs.preconf.ujson import UjsonConverter, configure_converter, make_converter
+
+__all__ = ["configure_converter", "make_converter", "UjsonConverter"]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattr/py.typed b/lambdas/aws-dd-forwarder-3.127.0/cattr/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/METADATA
new file mode 100644
index 0000000..0c6a750
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/METADATA
@@ -0,0 +1,161 @@
+Metadata-Version: 2.3
+Name: cattrs
+Version: 24.1.2
+Summary: Composable complex class support for attrs and dataclasses.
+Project-URL: Homepage, https://catt.rs
+Project-URL: Changelog, https://catt.rs/en/latest/history.html
+Project-URL: Bug Tracker, https://github.com/python-attrs/cattrs/issues
+Project-URL: Repository, https://github.com/python-attrs/cattrs
+Project-URL: Documentation, https://catt.rs/en/stable/
+Author-email: Tin Tvrtkovic
+License: MIT
+License-File: LICENSE
+Keywords: attrs,dataclasses,serialization
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: Intended Audience :: Developers
+Classifier: License :: OSI Approved :: MIT License
+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: Typing :: Typed
+Requires-Python: >=3.8
+Requires-Dist: attrs>=23.1.0
+Requires-Dist: exceptiongroup>=1.1.1; python_version < '3.11'
+Requires-Dist: typing-extensions!=4.6.3,>=4.1.0; python_version < '3.11'
+Provides-Extra: bson
+Requires-Dist: pymongo>=4.4.0; extra == 'bson'
+Provides-Extra: cbor2
+Requires-Dist: cbor2>=5.4.6; extra == 'cbor2'
+Provides-Extra: msgpack
+Requires-Dist: msgpack>=1.0.5; extra == 'msgpack'
+Provides-Extra: msgspec
+Requires-Dist: msgspec>=0.18.5; (implementation_name == 'cpython') and extra == 'msgspec'
+Provides-Extra: orjson
+Requires-Dist: orjson>=3.9.2; (implementation_name == 'cpython') and extra == 'orjson'
+Provides-Extra: pyyaml
+Requires-Dist: pyyaml>=6.0; extra == 'pyyaml'
+Provides-Extra: tomlkit
+Requires-Dist: tomlkit>=0.11.8; extra == 'tomlkit'
+Provides-Extra: ujson
+Requires-Dist: ujson>=5.7.0; extra == 'ujson'
+Description-Content-Type: text/markdown
+
+# *cattrs*: Flexible Object Serialization and Validation
+
+*Because validation belongs to the edges.*
+
+[![Documentation](https://img.shields.io/badge/Docs-Read%20The%20Docs-black)](https://catt.rs/)
+[![License: MIT](https://img.shields.io/badge/license-MIT-C06524)](https://github.com/hynek/stamina/blob/main/LICENSE)
+[![PyPI](https://img.shields.io/pypi/v/cattrs.svg)](https://pypi.python.org/pypi/cattrs)
+[![Supported Python Versions](https://img.shields.io/pypi/pyversions/cattrs.svg)](https://github.com/python-attrs/cattrs)
+[![Downloads](https://static.pepy.tech/badge/cattrs/month)](https://pepy.tech/project/cattrs)
+[![Coverage](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/Tinche/22405310d6a663164d894a2beab4d44d/raw/covbadge.json)](https://github.com/python-attrs/cattrs/actions/workflows/main.yml)
+
+---
+
+
+
+**cattrs** is a Swiss Army knife for (un)structuring and validating data in Python.
+In practice, that means it converts **unstructured dictionaries** into **proper classes** and back, while **validating** their contents.
+
+
+
+
+## Example
+
+
+
+_cattrs_ works best with [_attrs_](https://www.attrs.org/) classes, and [dataclasses](https://docs.python.org/3/library/dataclasses.html) where simple (un-)structuring works out of the box, even for nested data, without polluting your data model with serialization details:
+
+```python
+>>> from attrs import define
+>>> from cattrs import structure, unstructure
+>>> @define
+... class C:
+... a: int
+... b: list[str]
+>>> instance = structure({'a': 1, 'b': ['x', 'y']}, C)
+>>> instance
+C(a=1, b=['x', 'y'])
+>>> unstructure(instance)
+{'a': 1, 'b': ['x', 'y']}
+```
+
+
+
+
+Have a look at [*Why *cattrs*?*](https://catt.rs/en/latest/why.html) for more examples!
+
+
+
+## Features
+
+### Recursive Unstructuring
+
+- _attrs_ classes and dataclasses are converted into dictionaries in a way similar to `attrs.asdict()`, or into tuples in a way similar to `attrs.astuple()`.
+- Enumeration instances are converted to their values.
+- Other types are let through without conversion. This includes types such as integers, dictionaries, lists and instances of non-_attrs_ classes.
+- Custom converters for any type can be registered using `register_unstructure_hook`.
+
+
+### Recursive Structuring
+
+Converts unstructured data into structured data, recursively, according to your specification given as a type.
+The following types are supported:
+
+- `typing.Optional[T]` and its 3.10+ form, `T | None`.
+- `list[T]`, `typing.List[T]`, `typing.MutableSequence[T]`, `typing.Sequence[T]` convert to a lists.
+- `tuple` and `typing.Tuple` (both variants, `tuple[T, ...]` and `tuple[X, Y, Z]`).
+- `set[T]`, `typing.MutableSet[T]`, and `typing.Set[T]` convert to a sets.
+- `frozenset[T]`, and `typing.FrozenSet[T]` convert to a frozensets.
+- `dict[K, V]`, `typing.Dict[K, V]`, `typing.MutableMapping[K, V]`, and `typing.Mapping[K, V]` convert to a dictionaries.
+- [`typing.TypedDict`](https://docs.python.org/3/library/typing.html#typing.TypedDict), ordinary and generic.
+- [`typing.NewType`](https://docs.python.org/3/library/typing.html#newtype)
+- [PEP 695 type aliases](https://docs.python.org/3/library/typing.html#type-aliases) on 3.12+
+- _attrs_ classes with simple attributes and the usual `__init__`[^simple].
+- All _attrs_ classes and dataclasses with the usual `__init__`, if their complex attributes have type metadata.
+- Unions of supported _attrs_ classes, given that all of the classes have a unique field.
+- Unions of anything, if you provide a disambiguation function for it.
+- Custom converters for any type can be registered using `register_structure_hook`.
+
+[^simple]: Simple attributes are attributes that can be assigned unstructured data, like numbers, strings, and collections of unstructured data.
+
+
+### Batteries Included
+
+_cattrs_ comes with pre-configured converters for a number of serialization libraries, including JSON (standard library, [_orjson_](https://pypi.org/project/orjson/), [UltraJSON](https://pypi.org/project/ujson/)), [_msgpack_](https://pypi.org/project/msgpack/), [_cbor2_](https://pypi.org/project/cbor2/), [_bson_](https://pypi.org/project/bson/), [PyYAML](https://pypi.org/project/PyYAML/), [_tomlkit_](https://pypi.org/project/tomlkit/) and [_msgspec_](https://pypi.org/project/msgspec/) (supports only JSON at this time).
+
+For details, see the [cattrs.preconf package](https://catt.rs/en/stable/preconf.html).
+
+
+## Design Decisions
+
+_cattrs_ is based on a few fundamental design decisions:
+
+- Un/structuring rules are separate from the models.
+ This allows models to have a one-to-many relationship with un/structuring rules, and to create un/structuring rules for models which you do not own and you cannot change.
+ (_cattrs_ can be configured to use un/structuring rules from models using the [`use_class_methods` strategy](https://catt.rs/en/latest/strategies.html#using-class-specific-structure-and-unstructure-methods).)
+- Invent as little as possible; reuse existing ordinary Python instead.
+ For example, _cattrs_ did not have a custom exception type to group exceptions until the sanctioned Python [`exceptiongroups`](https://docs.python.org/3/library/exceptions.html#ExceptionGroup).
+ A side-effect of this design decision is that, in a lot of cases, when you're solving _cattrs_ problems you're actually learning Python instead of learning _cattrs_.
+- Resist the temptation to guess.
+ If there are two ways of solving a problem, _cattrs_ should refuse to guess and let the user configure it themselves.
+
+A foolish consistency is the hobgoblin of little minds, so these decisions can and are sometimes broken, but they have proven to be a good foundation.
+
+
+
+
+## Credits
+
+Major credits to Hynek Schlawack for creating [attrs](https://attrs.org) and its predecessor, [characteristic](https://github.com/hynek/characteristic).
+
+_cattrs_ is tested with [Hypothesis](http://hypothesis.readthedocs.io/en/latest/), by David R. MacIver.
+
+_cattrs_ is benchmarked using [perf](https://github.com/haypo/perf) and [pytest-benchmark](https://pytest-benchmark.readthedocs.io/en/latest/index.html).
+
+This package was created with [Cookiecutter](https://github.com/audreyr/cookiecutter) and the [`audreyr/cookiecutter-pypackage`](https://github.com/audreyr/cookiecutter-pypackage) project template.
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/RECORD
new file mode 100644
index 0000000..f7b3ae3
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/RECORD
@@ -0,0 +1,96 @@
+cattr/__init__.py,sha256=pODFKaZ7MisyHe_XPc9X6KKG73mqduHUvQO142XwijY,906
+cattr/__pycache__/__init__.cpython-311.pyc,,
+cattr/__pycache__/converters.cpython-311.pyc,,
+cattr/__pycache__/disambiguators.cpython-311.pyc,,
+cattr/__pycache__/dispatch.cpython-311.pyc,,
+cattr/__pycache__/errors.cpython-311.pyc,,
+cattr/__pycache__/gen.cpython-311.pyc,,
+cattr/converters.py,sha256=rQhY4J8r7QTZh5WICuFe4GWO1v0DS3DgQ9r569zd6jg,192
+cattr/disambiguators.py,sha256=ugD1fq1Z5x1pGu5P1lMzcT-IEi1q7IfQJIHEdmg62vM,103
+cattr/dispatch.py,sha256=uVEOgHWR9Hn5tm-wIw-bDccqrxJByVi8yRKaYyvL67k,125
+cattr/errors.py,sha256=V4RhoCObwGrlaM3oyn1H_FYxGR8iAB9dG5NxFDYM548,343
+cattr/gen.py,sha256=hWyKoZ_d2D36Jz_npspyGw8s9pWtUA69sXf0R3uOvgM,597
+cattr/preconf/__init__.py,sha256=NqPE7uhVfcP-PggkUpsbfAutMo8oHjcoB1cvjgLft-s,78
+cattr/preconf/__pycache__/__init__.cpython-311.pyc,,
+cattr/preconf/__pycache__/bson.cpython-311.pyc,,
+cattr/preconf/__pycache__/json.cpython-311.pyc,,
+cattr/preconf/__pycache__/msgpack.cpython-311.pyc,,
+cattr/preconf/__pycache__/orjson.cpython-311.pyc,,
+cattr/preconf/__pycache__/pyyaml.cpython-311.pyc,,
+cattr/preconf/__pycache__/tomlkit.cpython-311.pyc,,
+cattr/preconf/__pycache__/ujson.cpython-311.pyc,,
+cattr/preconf/bson.py,sha256=Bn4hJxac7OthGg_CR4LCPeBp_fz4kx3QniBVOZhguGs,195
+cattr/preconf/json.py,sha256=HBxWOTqKI7HOlmt-GnN6_wjQz1VphRi70sAOEbx0A2Y,206
+cattr/preconf/msgpack.py,sha256=VXqynPel11_lX8uTg84-u27LQhCqL1OoiF-lTqnoAkQ,207
+cattr/preconf/orjson.py,sha256=fs8qDPDYSBba9D8ib9Df1WVZ8iZaRPQq7kDigAxp14E,203
+cattr/preconf/pyyaml.py,sha256=lhuKwHrcvr16WOtdW4Q0mgIRzB90v1hwZkFXtPKOvAw,203
+cattr/preconf/tomlkit.py,sha256=rk393txIBHeWR66LfnATPh9Im1EFAHPJvSEGGSP2c-8,207
+cattr/preconf/ujson.py,sha256=r6ufraKDqmKdetNZUKxLYVSGmuJ-ckc-UjGYvCamr9k,199
+cattr/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+cattrs-24.1.2.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+cattrs-24.1.2.dist-info/METADATA,sha256=Dw1BXPd1jf0ooO8yiPhPNKrkXvGklnIuiYPdELv-Ohk,8420
+cattrs-24.1.2.dist-info/RECORD,,
+cattrs-24.1.2.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+cattrs-24.1.2.dist-info/WHEEL,sha256=1yFddiXMmvYK7QYTqtRNtX66WJ0Mz8PYEiEUoOUUxRY,87
+cattrs-24.1.2.dist-info/licenses/LICENSE,sha256=9fudHt43qIykf0IMSZ3KD0oFvJk-Esd9I1IKrSkcAb8,1074
+cattrs/__init__.py,sha256=peO0_Q9AEguPCMjXlRH-Nj0CahcCw5CJmpnpKxsWKSQ,1835
+cattrs/__pycache__/__init__.cpython-311.pyc,,
+cattrs/__pycache__/_compat.cpython-311.pyc,,
+cattrs/__pycache__/_generics.cpython-311.pyc,,
+cattrs/__pycache__/cols.cpython-311.pyc,,
+cattrs/__pycache__/converters.cpython-311.pyc,,
+cattrs/__pycache__/disambiguators.cpython-311.pyc,,
+cattrs/__pycache__/dispatch.cpython-311.pyc,,
+cattrs/__pycache__/errors.cpython-311.pyc,,
+cattrs/__pycache__/fns.cpython-311.pyc,,
+cattrs/__pycache__/v.cpython-311.pyc,,
+cattrs/_compat.py,sha256=DmHUZNi_MnI2UKvNPxwr77zuMs5tl3zDM4rdJK7kJiI,17620
+cattrs/_generics.py,sha256=ymyDdLjXoYi_XPBA_f_-xJC7Bc8RGqoUcdlwTbB7xl8,718
+cattrs/cols.py,sha256=sB9NTOp8pGLMUxVicSHWpcX_4czrD1g5MdCJO0Ko5s0,8433
+cattrs/converters.py,sha256=nMxuapDj3Q75oW4sVXnYdIeHhodwzLNUcDcaIfKMLQM,53916
+cattrs/disambiguators.py,sha256=ljl73QtSB3MAGcl7-phAUR66b4yx_1ORYLb5fUgW8bY,6825
+cattrs/dispatch.py,sha256=fEE100tCqcqC_wl5y2FCdVEocLOuDlys0sduJrTfmB4,6810
+cattrs/errors.py,sha256=rHps9Qp7SoRafb2VuAkMbhsQf4pq87gX1SzM-jluMsE,4070
+cattrs/fns.py,sha256=xQceStzW4qLiMTJgGM-pVUudGwHm0Hin8oCYe1feS5c,633
+cattrs/gen/__init__.py,sha256=yBOs4V1SQ6RAPFSGyIkwi4ZEU7fqA_nQrH6ujgT88eI,38527
+cattrs/gen/__pycache__/__init__.cpython-311.pyc,,
+cattrs/gen/__pycache__/_consts.cpython-311.pyc,,
+cattrs/gen/__pycache__/_generics.cpython-311.pyc,,
+cattrs/gen/__pycache__/_lc.cpython-311.pyc,,
+cattrs/gen/__pycache__/_shared.cpython-311.pyc,,
+cattrs/gen/__pycache__/typeddicts.cpython-311.pyc,,
+cattrs/gen/_consts.py,sha256=ZwT_m2J3S7p-UjltpbA1WtfQZLNj9KhmFYCAv6Zl-g0,511
+cattrs/gen/_generics.py,sha256=_DyXCGql2QIxGhAv3_B1hsi80uPK8PhK2hhZa95YOlo,3011
+cattrs/gen/_lc.py,sha256=ktP5F9oOUo4HpZ4-hlLliLPzr8XjFi31EXMl8YMMs-g,906
+cattrs/gen/_shared.py,sha256=4yX9-TD5yyVzDWlSjkECrQV5B82xHUeBt9n2N5UgOAE,2064
+cattrs/gen/typeddicts.py,sha256=C3Bp8tNM-MI7L7KO0X3sfwSkG5d0ua3j7qDtvcCEBQk,22004
+cattrs/preconf/__init__.py,sha256=dfkUXoU47ZJfmoKX9FsnARKqLlgJeBjMxORMzxrbKbs,604
+cattrs/preconf/__pycache__/__init__.cpython-311.pyc,,
+cattrs/preconf/__pycache__/bson.cpython-311.pyc,,
+cattrs/preconf/__pycache__/cbor2.cpython-311.pyc,,
+cattrs/preconf/__pycache__/json.cpython-311.pyc,,
+cattrs/preconf/__pycache__/msgpack.cpython-311.pyc,,
+cattrs/preconf/__pycache__/msgspec.cpython-311.pyc,,
+cattrs/preconf/__pycache__/orjson.cpython-311.pyc,,
+cattrs/preconf/__pycache__/pyyaml.cpython-311.pyc,,
+cattrs/preconf/__pycache__/tomlkit.cpython-311.pyc,,
+cattrs/preconf/__pycache__/ujson.cpython-311.pyc,,
+cattrs/preconf/bson.py,sha256=uBRpTVfwGZ-qfuDYGwsl8eXokVAmcVBedKQPGUmamhc,3656
+cattrs/preconf/cbor2.py,sha256=ANfQUXgs7pyU5-4_2hYmcqUxzQZhWhFzrk_0y6b1yYw,1635
+cattrs/preconf/json.py,sha256=CSU5RosdYyg6cIOpaohgZVfdMtOtKjZlSg837fW4fTw,2035
+cattrs/preconf/msgpack.py,sha256=cgwX_ARi_swQjG6hwa9j-n7FUynLNWIMVLouz_VoTuw,1753
+cattrs/preconf/msgspec.py,sha256=f8J04RXv8UErKAwwzVs1cMbvoM-9erMmmF49zKBbCDo,6343
+cattrs/preconf/orjson.py,sha256=RZ8DI-4K7Xi0QdpIihT9I3Cm-O8Aq8_MTt2R3a4fgEk,3241
+cattrs/preconf/pyyaml.py,sha256=Ga96zLypn2DglTgbrb9h3jcuH-caur_UQI1ADo-ynUA,2298
+cattrs/preconf/tomlkit.py,sha256=2k-BN0ZW3faWmHcMQ1bCvsKCClhdgSjTe056O1xEc4o,3060
+cattrs/preconf/ujson.py,sha256=JBh5dWluwMwKhAJPINJhpse_aQ1p9hzrGo8BuvmG6S0,1863
+cattrs/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+cattrs/strategies/__init__.py,sha256=nkZWCzSRYcS-75FMfk52mioZSuWykaN8hB39Vig5Xkg,339
+cattrs/strategies/__pycache__/__init__.cpython-311.pyc,,
+cattrs/strategies/__pycache__/_class_methods.cpython-311.pyc,,
+cattrs/strategies/__pycache__/_subclasses.cpython-311.pyc,,
+cattrs/strategies/__pycache__/_unions.cpython-311.pyc,,
+cattrs/strategies/_class_methods.py,sha256=vfiE3wKm04oc-3T9hchsIyhVzpMpJRdgTbujKsWyVpQ,2597
+cattrs/strategies/_subclasses.py,sha256=zzhLl7fSZlmlBuBY-rPX7L1d_C5tiDFDBmUTeRpG2uI,9204
+cattrs/strategies/_unions.py,sha256=l8CjVVFAwftkBa47g3m2KgtQ_b42Wnv-KwYY_LHReCA,9166
+cattrs/v.py,sha256=cTYt0EW8yr-gzKynw4_XjFv3RLpAF8IebvOb612l9QE,4399
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/WHEEL
new file mode 100644
index 0000000..cdd68a4
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/WHEEL
@@ -0,0 +1,4 @@
+Wheel-Version: 1.0
+Generator: hatchling 1.25.0
+Root-Is-Purelib: true
+Tag: py3-none-any
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/licenses/LICENSE b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/licenses/LICENSE
new file mode 100644
index 0000000..340022c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs-24.1.2.dist-info/licenses/LICENSE
@@ -0,0 +1,11 @@
+
+MIT License
+
+Copyright (c) 2016, Tin Tvrtković
+
+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/lambdas/aws-dd-forwarder-3.127.0/cattrs/.DS_Store b/lambdas/aws-dd-forwarder-3.127.0/cattrs/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..5aad9a2de44ee5958d21f27c0be89c9727ce63be
GIT binary patch
literal 6148
zcmeHKu};G<5Ixf%s&?tfm|y716sqtAS&>ScmK3RJDhd*8{v=|)8Ax7KOt
z@XezY74V@q<};ujJ%P~-ehDoe;CCUb;wlyw;dXS*2*abXAy3OZ)lORh+}UjXp-1(q
zfGVI0>=oeiAw^@%1g%GRbilbM05HL@GxYhFf^$;AOwfA749xgcpiedO#4tV`idN^-~v4{s#Ab^{Rj>a8RJx<
literal 0
HcmV?d00001
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/__init__.py
new file mode 100644
index 0000000..db49636
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/__init__.py
@@ -0,0 +1,55 @@
+from typing import Final
+
+from .converters import BaseConverter, Converter, GenConverter, UnstructureStrategy
+from .errors import (
+ AttributeValidationNote,
+ BaseValidationError,
+ ClassValidationError,
+ ForbiddenExtraKeysError,
+ IterableValidationError,
+ IterableValidationNote,
+ StructureHandlerNotFoundError,
+)
+from .gen import override
+from .v import transform_error
+
+__all__ = [
+ "structure",
+ "unstructure",
+ "get_structure_hook",
+ "get_unstructure_hook",
+ "register_structure_hook_func",
+ "register_structure_hook",
+ "register_unstructure_hook_func",
+ "register_unstructure_hook",
+ "structure_attrs_fromdict",
+ "structure_attrs_fromtuple",
+ "global_converter",
+ "BaseConverter",
+ "Converter",
+ "AttributeValidationNote",
+ "BaseValidationError",
+ "ClassValidationError",
+ "ForbiddenExtraKeysError",
+ "GenConverter",
+ "IterableValidationError",
+ "IterableValidationNote",
+ "override",
+ "StructureHandlerNotFoundError",
+ "transform_error",
+ "UnstructureStrategy",
+]
+
+#: The global converter. Prefer creating your own if customizations are required.
+global_converter: Final = Converter()
+
+unstructure = global_converter.unstructure
+structure = global_converter.structure
+structure_attrs_fromtuple = global_converter.structure_attrs_fromtuple
+structure_attrs_fromdict = global_converter.structure_attrs_fromdict
+register_structure_hook = global_converter.register_structure_hook
+register_structure_hook_func = global_converter.register_structure_hook_func
+register_unstructure_hook = global_converter.register_unstructure_hook
+register_unstructure_hook_func = global_converter.register_unstructure_hook_func
+get_structure_hook: Final = global_converter.get_structure_hook
+get_unstructure_hook: Final = global_converter.get_unstructure_hook
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/_compat.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/_compat.py
new file mode 100644
index 0000000..027ef47
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/_compat.py
@@ -0,0 +1,578 @@
+import sys
+from collections import deque
+from collections.abc import Mapping as AbcMapping
+from collections.abc import MutableMapping as AbcMutableMapping
+from collections.abc import MutableSet as AbcMutableSet
+from collections.abc import Set as AbcSet
+from dataclasses import MISSING, Field, is_dataclass
+from dataclasses import fields as dataclass_fields
+from functools import partial
+from inspect import signature as _signature
+from typing import AbstractSet as TypingAbstractSet
+from typing import (
+ Any,
+ Deque,
+ Dict,
+ Final,
+ FrozenSet,
+ List,
+ Literal,
+ NewType,
+ Optional,
+ Protocol,
+ Tuple,
+ Type,
+ Union,
+ get_args,
+ get_origin,
+ get_type_hints,
+)
+from typing import Mapping as TypingMapping
+from typing import MutableMapping as TypingMutableMapping
+from typing import MutableSequence as TypingMutableSequence
+from typing import MutableSet as TypingMutableSet
+from typing import Sequence as TypingSequence
+from typing import Set as TypingSet
+
+from attrs import NOTHING, Attribute, Factory, resolve_types
+from attrs import fields as attrs_fields
+from attrs import fields_dict as attrs_fields_dict
+
+__all__ = [
+ "ANIES",
+ "adapted_fields",
+ "fields_dict",
+ "ExceptionGroup",
+ "ExtensionsTypedDict",
+ "get_type_alias_base",
+ "has",
+ "is_type_alias",
+ "is_typeddict",
+ "TypeAlias",
+ "TypedDict",
+]
+
+try:
+ from typing_extensions import TypedDict as ExtensionsTypedDict
+except ImportError: # pragma: no cover
+ ExtensionsTypedDict = None
+
+if sys.version_info >= (3, 11):
+ from builtins import ExceptionGroup
+else:
+ from exceptiongroup import ExceptionGroup
+
+try:
+ from typing_extensions import is_typeddict as _is_typeddict
+except ImportError: # pragma: no cover
+ assert sys.version_info >= (3, 10)
+ from typing import is_typeddict as _is_typeddict
+
+try:
+ from typing_extensions import TypeAlias
+except ImportError: # pragma: no cover
+ assert sys.version_info >= (3, 11)
+ from typing import TypeAlias
+
+LITERALS = {Literal}
+try:
+ from typing_extensions import Literal as teLiteral
+
+ LITERALS.add(teLiteral)
+except ImportError: # pragma: no cover
+ pass
+
+# On some Python versions, `typing_extensions.Any` is different than
+# `typing.Any`.
+try:
+ from typing_extensions import Any as teAny
+
+ ANIES = frozenset([Any, teAny])
+except ImportError: # pragma: no cover
+ ANIES = frozenset([Any])
+
+NoneType = type(None)
+
+
+def is_optional(typ: Type) -> bool:
+ return is_union_type(typ) and NoneType in typ.__args__ and len(typ.__args__) == 2
+
+
+def is_typeddict(cls):
+ """Thin wrapper around typing(_extensions).is_typeddict"""
+ return _is_typeddict(getattr(cls, "__origin__", cls))
+
+
+def is_type_alias(type: Any) -> bool:
+ """Is this a PEP 695 type alias?"""
+ return False
+
+
+def get_type_alias_base(type: Any) -> Any:
+ """
+ What is this a type alias of?
+
+ Works only on 3.12+.
+ """
+ return type.__value__
+
+
+def has(cls):
+ return hasattr(cls, "__attrs_attrs__") or hasattr(cls, "__dataclass_fields__")
+
+
+def has_with_generic(cls):
+ """Test whether the class if a normal or generic attrs or dataclass."""
+ return has(cls) or has(get_origin(cls))
+
+
+def fields(type):
+ try:
+ return type.__attrs_attrs__
+ except AttributeError:
+ return dataclass_fields(type)
+
+
+def fields_dict(type) -> Dict[str, Union[Attribute, Field]]:
+ """Return the fields_dict for attrs and dataclasses."""
+ if is_dataclass(type):
+ return {f.name: f for f in dataclass_fields(type)}
+ return attrs_fields_dict(type)
+
+
+def adapted_fields(cl) -> List[Attribute]:
+ """Return the attrs format of `fields()` for attrs and dataclasses."""
+ if is_dataclass(cl):
+ attrs = dataclass_fields(cl)
+ if any(isinstance(a.type, str) for a in attrs):
+ # Do this conditionally in case `get_type_hints` fails, so
+ # users can resolve on their own first.
+ type_hints = get_type_hints(cl)
+ else:
+ type_hints = {}
+ return [
+ Attribute(
+ attr.name,
+ (
+ attr.default
+ if attr.default is not MISSING
+ else (
+ Factory(attr.default_factory)
+ if attr.default_factory is not MISSING
+ else NOTHING
+ )
+ ),
+ None,
+ True,
+ None,
+ True,
+ attr.init,
+ True,
+ type=type_hints.get(attr.name, attr.type),
+ alias=attr.name,
+ )
+ for attr in attrs
+ ]
+ attribs = attrs_fields(cl)
+ if any(isinstance(a.type, str) for a in attribs):
+ # PEP 563 annotations - need to be resolved.
+ resolve_types(cl)
+ attribs = attrs_fields(cl)
+ return attribs
+
+
+def is_subclass(obj: type, bases) -> bool:
+ """A safe version of issubclass (won't raise)."""
+ try:
+ return issubclass(obj, bases)
+ except TypeError:
+ return False
+
+
+def is_hetero_tuple(type: Any) -> bool:
+ origin = getattr(type, "__origin__", None)
+ return origin is tuple and ... not in type.__args__
+
+
+def is_protocol(type: Any) -> bool:
+ return is_subclass(type, Protocol) and getattr(type, "_is_protocol", False)
+
+
+def is_bare_final(type) -> bool:
+ return type is Final
+
+
+def get_final_base(type) -> Optional[type]:
+ """Return the base of the Final annotation, if it is Final."""
+ if type is Final:
+ return Any
+ if type.__class__ is _GenericAlias and type.__origin__ is Final:
+ return type.__args__[0]
+ return None
+
+
+OriginAbstractSet = AbcSet
+OriginMutableSet = AbcMutableSet
+
+signature = _signature
+
+if sys.version_info >= (3, 10):
+ signature = partial(_signature, eval_str=True)
+
+if sys.version_info >= (3, 9):
+ from collections import Counter
+ from collections.abc import MutableSequence as AbcMutableSequence
+ from collections.abc import MutableSet as AbcMutableSet
+ from collections.abc import Sequence as AbcSequence
+ from collections.abc import Set as AbcSet
+ from types import GenericAlias
+ from typing import (
+ Annotated,
+ Generic,
+ TypedDict,
+ Union,
+ _AnnotatedAlias,
+ _GenericAlias,
+ _SpecialGenericAlias,
+ _UnionGenericAlias,
+ )
+ from typing import Counter as TypingCounter
+
+ try:
+ # Not present on 3.9.0, so we try carefully.
+ from typing import _LiteralGenericAlias
+
+ def is_literal(type) -> bool:
+ return type in LITERALS or (
+ isinstance(
+ type, (_GenericAlias, _LiteralGenericAlias, _SpecialGenericAlias)
+ )
+ and type.__origin__ in LITERALS
+ )
+
+ except ImportError: # pragma: no cover
+
+ def is_literal(_) -> bool:
+ return False
+
+ Set = AbcSet
+ AbstractSet = AbcSet
+ MutableSet = AbcMutableSet
+ Sequence = AbcSequence
+ MutableSequence = AbcMutableSequence
+ MutableMapping = AbcMutableMapping
+ Mapping = AbcMapping
+ FrozenSetSubscriptable = frozenset
+ TupleSubscriptable = tuple
+
+ def is_annotated(type) -> bool:
+ return getattr(type, "__class__", None) is _AnnotatedAlias
+
+ def is_tuple(type):
+ return (
+ type in (Tuple, tuple)
+ or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, Tuple))
+ or (getattr(type, "__origin__", None) is tuple)
+ )
+
+ if sys.version_info >= (3, 12):
+ from typing import TypeAliasType
+
+ def is_type_alias(type: Any) -> bool:
+ """Is this a PEP 695 type alias?"""
+ return isinstance(type, TypeAliasType)
+
+ if sys.version_info >= (3, 10):
+
+ def is_union_type(obj):
+ from types import UnionType
+
+ return (
+ obj is Union
+ or (isinstance(obj, _UnionGenericAlias) and obj.__origin__ is Union)
+ or isinstance(obj, UnionType)
+ )
+
+ def get_newtype_base(typ: Any) -> Optional[type]:
+ if typ is NewType or isinstance(typ, NewType):
+ return typ.__supertype__
+ return None
+
+ if sys.version_info >= (3, 11):
+ from typing import NotRequired, Required
+ else:
+ from typing_extensions import NotRequired, Required
+
+ else:
+ from typing_extensions import NotRequired, Required
+
+ def is_union_type(obj):
+ return (
+ obj is Union
+ or isinstance(obj, _UnionGenericAlias)
+ and obj.__origin__ is Union
+ )
+
+ def get_newtype_base(typ: Any) -> Optional[type]:
+ supertype = getattr(typ, "__supertype__", None)
+ if (
+ supertype is not None
+ and getattr(typ, "__qualname__", "") == "NewType..new_type"
+ and typ.__module__ in ("typing", "typing_extensions")
+ ):
+ return supertype
+ return None
+
+ def get_notrequired_base(type) -> "Union[Any, Literal[NOTHING]]":
+ if is_annotated(type):
+ # Handle `Annotated[NotRequired[int]]`
+ type = get_args(type)[0]
+ if get_origin(type) in (NotRequired, Required):
+ return get_args(type)[0]
+ return NOTHING
+
+ def is_sequence(type: Any) -> bool:
+ """A predicate function for sequences.
+
+ Matches lists, sequences, mutable sequences, deques and homogenous
+ tuples.
+ """
+ origin = getattr(type, "__origin__", None)
+ return (
+ type
+ in (
+ List,
+ list,
+ TypingSequence,
+ TypingMutableSequence,
+ AbcMutableSequence,
+ tuple,
+ Tuple,
+ deque,
+ Deque,
+ )
+ or (
+ type.__class__ is _GenericAlias
+ and (
+ (origin is not tuple)
+ and is_subclass(origin, TypingSequence)
+ or origin is tuple
+ and type.__args__[1] is ...
+ )
+ )
+ or (origin in (list, deque, AbcMutableSequence, AbcSequence))
+ or (origin is tuple and type.__args__[1] is ...)
+ )
+
+ def is_deque(type):
+ return (
+ type in (deque, Deque)
+ or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, deque))
+ or (getattr(type, "__origin__", None) is deque)
+ )
+
+ def is_mutable_set(type: Any) -> bool:
+ """A predicate function for (mutable) sets.
+
+ Matches built-in sets and sets from the typing module.
+ """
+ return (
+ type in (TypingSet, TypingMutableSet, set)
+ or (
+ type.__class__ is _GenericAlias
+ and is_subclass(type.__origin__, TypingMutableSet)
+ )
+ or (getattr(type, "__origin__", None) in (set, AbcMutableSet, AbcSet))
+ )
+
+ def is_frozenset(type: Any) -> bool:
+ """A predicate function for frozensets.
+
+ Matches built-in frozensets and frozensets from the typing module.
+ """
+ return (
+ type in (FrozenSet, frozenset)
+ or (
+ type.__class__ is _GenericAlias
+ and is_subclass(type.__origin__, FrozenSet)
+ )
+ or (getattr(type, "__origin__", None) is frozenset)
+ )
+
+ def is_bare(type):
+ return isinstance(type, _SpecialGenericAlias) or (
+ not hasattr(type, "__origin__") and not hasattr(type, "__args__")
+ )
+
+ def is_mapping(type: Any) -> bool:
+ """A predicate function for mappings."""
+ return (
+ type in (dict, Dict, TypingMapping, TypingMutableMapping, AbcMutableMapping)
+ or (
+ type.__class__ is _GenericAlias
+ and is_subclass(type.__origin__, TypingMapping)
+ )
+ or is_subclass(
+ getattr(type, "__origin__", type), (dict, AbcMutableMapping, AbcMapping)
+ )
+ )
+
+ def is_counter(type):
+ return (
+ type in (Counter, TypingCounter)
+ or getattr(type, "__origin__", None) is Counter
+ )
+
+ def is_generic(type) -> bool:
+ """Whether `type` is a generic type."""
+ # Inheriting from protocol will inject `Generic` into the MRO
+ # without `__orig_bases__`.
+ return isinstance(type, (_GenericAlias, GenericAlias)) or (
+ is_subclass(type, Generic) and hasattr(type, "__orig_bases__")
+ )
+
+ def copy_with(type, args):
+ """Replace a generic type's arguments."""
+ if is_annotated(type):
+ # typing.Annotated requires a special case.
+ return Annotated[args]
+ if isinstance(args, tuple) and len(args) == 1:
+ # Some annotations can't handle 1-tuples.
+ args = args[0]
+ return type.__origin__[args]
+
+ def get_full_type_hints(obj, globalns=None, localns=None):
+ return get_type_hints(obj, globalns, localns, include_extras=True)
+
+else:
+ # 3.8
+ Set = TypingSet
+ AbstractSet = TypingAbstractSet
+ MutableSet = TypingMutableSet
+
+ Sequence = TypingSequence
+ MutableSequence = TypingMutableSequence
+ MutableMapping = TypingMutableMapping
+ Mapping = TypingMapping
+ FrozenSetSubscriptable = FrozenSet
+ TupleSubscriptable = Tuple
+
+ from collections import Counter as ColCounter
+ from typing import Counter, Generic, TypedDict, Union, _GenericAlias
+
+ from typing_extensions import Annotated, NotRequired, Required
+ from typing_extensions import get_origin as te_get_origin
+
+ def is_annotated(type) -> bool:
+ return te_get_origin(type) is Annotated
+
+ def is_tuple(type):
+ return type in (Tuple, tuple) or (
+ type.__class__ is _GenericAlias and is_subclass(type.__origin__, Tuple)
+ )
+
+ def is_union_type(obj):
+ return (
+ obj is Union or isinstance(obj, _GenericAlias) and obj.__origin__ is Union
+ )
+
+ def get_newtype_base(typ: Any) -> Optional[type]:
+ supertype = getattr(typ, "__supertype__", None)
+ if (
+ supertype is not None
+ and getattr(typ, "__qualname__", "") == "NewType..new_type"
+ and typ.__module__ in ("typing", "typing_extensions")
+ ):
+ return supertype
+ return None
+
+ def is_sequence(type: Any) -> bool:
+ return type in (List, list, Tuple, tuple) or (
+ type.__class__ is _GenericAlias
+ and (
+ type.__origin__ not in (Union, Tuple, tuple)
+ and is_subclass(type.__origin__, TypingSequence)
+ )
+ or (type.__origin__ in (Tuple, tuple) and type.__args__[1] is ...)
+ )
+
+ def is_deque(type: Any) -> bool:
+ return (
+ type in (deque, Deque)
+ or (type.__class__ is _GenericAlias and is_subclass(type.__origin__, deque))
+ or type.__origin__ is deque
+ )
+
+ def is_mutable_set(type) -> bool:
+ return type in (set, TypingAbstractSet) or (
+ type.__class__ is _GenericAlias
+ and is_subclass(type.__origin__, (MutableSet, TypingAbstractSet))
+ )
+
+ def is_frozenset(type):
+ return type is frozenset or (
+ type.__class__ is _GenericAlias and is_subclass(type.__origin__, FrozenSet)
+ )
+
+ def is_mapping(type: Any) -> bool:
+ """A predicate function for mappings."""
+ return (
+ type in (TypingMapping, dict)
+ or (
+ type.__class__ is _GenericAlias
+ and is_subclass(type.__origin__, TypingMapping)
+ )
+ or is_subclass(
+ getattr(type, "__origin__", type), (dict, AbcMutableMapping, AbcMapping)
+ )
+ )
+
+ bare_generic_args = {
+ List.__args__,
+ TypingSequence.__args__,
+ TypingMapping.__args__,
+ Dict.__args__,
+ TypingMutableSequence.__args__,
+ Tuple.__args__,
+ None, # non-parametrized containers do not have `__args__ attribute in py3.7-8
+ }
+
+ def is_bare(type):
+ return getattr(type, "__args__", None) in bare_generic_args
+
+ def is_counter(type):
+ return (
+ type in (Counter, ColCounter)
+ or getattr(type, "__origin__", None) is ColCounter
+ )
+
+ def is_literal(type) -> bool:
+ return type in LITERALS or (
+ isinstance(type, _GenericAlias) and type.__origin__ in LITERALS
+ )
+
+ def is_generic(obj):
+ return isinstance(obj, _GenericAlias) or (
+ is_subclass(obj, Generic) and hasattr(obj, "__orig_bases__")
+ )
+
+ def copy_with(type, args):
+ """Replace a generic type's arguments."""
+ return type.copy_with(args)
+
+ def get_notrequired_base(type) -> "Union[Any, Literal[NOTHING]]":
+ if is_annotated(type):
+ # Handle `Annotated[NotRequired[int]]`
+ type = get_origin(type)
+
+ if get_origin(type) in (NotRequired, Required):
+ return get_args(type)[0]
+ return NOTHING
+
+ def get_full_type_hints(obj, globalns=None, localns=None):
+ return get_type_hints(obj, globalns, localns)
+
+
+def is_generic_attrs(type) -> bool:
+ """Return True for both specialized (A[int]) and unspecialized (A) generics."""
+ return is_generic(type) and has(type.__origin__)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/_generics.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/_generics.py
new file mode 100644
index 0000000..c473f43
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/_generics.py
@@ -0,0 +1,24 @@
+from typing import Any, Mapping
+
+from ._compat import copy_with, get_args, is_annotated, is_generic
+
+
+def deep_copy_with(t, mapping: Mapping[str, Any]):
+ args = get_args(t)
+ rest = ()
+ if is_annotated(t) and args:
+ # If we're dealing with `Annotated`, we only map the first type parameter
+ rest = tuple(args[1:])
+ args = (args[0],)
+ new_args = (
+ tuple(
+ (
+ mapping[a.__name__]
+ if hasattr(a, "__name__") and a.__name__ in mapping
+ else (deep_copy_with(a, mapping) if is_generic(a) else a)
+ )
+ for a in args
+ )
+ + rest
+ )
+ return copy_with(t, new_args) if new_args != args else t
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/cols.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/cols.py
new file mode 100644
index 0000000..8ff5c0f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/cols.py
@@ -0,0 +1,289 @@
+"""Utility functions for collections."""
+
+from __future__ import annotations
+
+from sys import version_info
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Iterable,
+ Literal,
+ NamedTuple,
+ Tuple,
+ TypeVar,
+ get_type_hints,
+)
+
+from attrs import NOTHING, Attribute
+
+from ._compat import ANIES, is_bare, is_frozenset, is_mapping, is_sequence, is_subclass
+from ._compat import is_mutable_set as is_set
+from .dispatch import StructureHook, UnstructureHook
+from .errors import IterableValidationError, IterableValidationNote
+from .fns import identity
+from .gen import (
+ AttributeOverride,
+ already_generating,
+ make_dict_structure_fn_from_attrs,
+ make_dict_unstructure_fn_from_attrs,
+ make_hetero_tuple_unstructure_fn,
+ mapping_structure_factory,
+)
+from .gen import make_iterable_unstructure_fn as iterable_unstructure_factory
+
+if TYPE_CHECKING:
+ from .converters import BaseConverter
+
+__all__ = [
+ "is_any_set",
+ "is_frozenset",
+ "is_namedtuple",
+ "is_mapping",
+ "is_set",
+ "is_sequence",
+ "iterable_unstructure_factory",
+ "list_structure_factory",
+ "namedtuple_structure_factory",
+ "namedtuple_unstructure_factory",
+ "namedtuple_dict_structure_factory",
+ "namedtuple_dict_unstructure_factory",
+ "mapping_structure_factory",
+]
+
+
+def is_any_set(type) -> bool:
+ """A predicate function for both mutable and frozensets."""
+ return is_set(type) or is_frozenset(type)
+
+
+if version_info[:2] >= (3, 9):
+
+ def is_namedtuple(type: Any) -> bool:
+ """A predicate function for named tuples."""
+
+ if is_subclass(type, tuple):
+ for cl in type.mro():
+ orig_bases = cl.__dict__.get("__orig_bases__", ())
+ if NamedTuple in orig_bases:
+ return True
+ return False
+
+else:
+
+ def is_namedtuple(type: Any) -> bool:
+ """A predicate function for named tuples."""
+ # This is tricky. It may not be possible for this function to be 100%
+ # accurate, since it doesn't seem like we can distinguish between tuple
+ # subclasses and named tuples reliably.
+
+ if is_subclass(type, tuple):
+ for cl in type.mro():
+ if cl is tuple:
+ # No point going further.
+ break
+ if "_fields" in cl.__dict__:
+ return True
+ return False
+
+
+def _is_passthrough(type: type[tuple], converter: BaseConverter) -> bool:
+ """If all fields would be passed through, this class should not be processed
+ either.
+ """
+ return all(
+ converter.get_unstructure_hook(t) == identity
+ for t in type.__annotations__.values()
+ )
+
+
+T = TypeVar("T")
+
+
+def list_structure_factory(type: type, converter: BaseConverter) -> StructureHook:
+ """A hook factory for structuring lists.
+
+ Converts any given iterable into a list.
+ """
+
+ if is_bare(type) or type.__args__[0] in ANIES:
+
+ def structure_list(obj: Iterable[T], _: type = type) -> list[T]:
+ return list(obj)
+
+ return structure_list
+
+ elem_type = type.__args__[0]
+
+ try:
+ handler = converter.get_structure_hook(elem_type)
+ except RecursionError:
+ # Break the cycle by using late binding.
+ handler = converter.structure
+
+ if converter.detailed_validation:
+
+ def structure_list(
+ obj: Iterable[T], _: type = type, _handler=handler, _elem_type=elem_type
+ ) -> list[T]:
+ errors = []
+ res = []
+ ix = 0 # Avoid `enumerate` for performance.
+ for e in obj:
+ try:
+ res.append(handler(e, _elem_type))
+ except Exception as e:
+ msg = IterableValidationNote(
+ f"Structuring {type} @ index {ix}", ix, elem_type
+ )
+ e.__notes__ = [*getattr(e, "__notes__", []), msg]
+ errors.append(e)
+ finally:
+ ix += 1
+ if errors:
+ raise IterableValidationError(
+ f"While structuring {type!r}", errors, type
+ )
+
+ return res
+
+ else:
+
+ def structure_list(
+ obj: Iterable[T], _: type = type, _handler=handler, _elem_type=elem_type
+ ) -> list[T]:
+ return [_handler(e, _elem_type) for e in obj]
+
+ return structure_list
+
+
+def namedtuple_unstructure_factory(
+ cl: type[tuple], converter: BaseConverter, unstructure_to: Any = None
+) -> UnstructureHook:
+ """A hook factory for unstructuring namedtuples.
+
+ :param unstructure_to: Force unstructuring to this type, if provided.
+ """
+
+ if unstructure_to is None and _is_passthrough(cl, converter):
+ return identity
+
+ return make_hetero_tuple_unstructure_fn(
+ cl,
+ converter,
+ unstructure_to=tuple if unstructure_to is None else unstructure_to,
+ type_args=tuple(cl.__annotations__.values()),
+ )
+
+
+def namedtuple_structure_factory(
+ cl: type[tuple], converter: BaseConverter
+) -> StructureHook:
+ """A hook factory for structuring namedtuples from iterables."""
+ # We delegate to the existing infrastructure for heterogenous tuples.
+ hetero_tuple_type = Tuple[tuple(cl.__annotations__.values())]
+ base_hook = converter.get_structure_hook(hetero_tuple_type)
+ return lambda v, _: cl(*base_hook(v, hetero_tuple_type))
+
+
+def _namedtuple_to_attrs(cl: type[tuple]) -> list[Attribute]:
+ """Generate pseudo attributes for a namedtuple."""
+ return [
+ Attribute(
+ name,
+ cl._field_defaults.get(name, NOTHING),
+ None,
+ False,
+ False,
+ False,
+ True,
+ False,
+ type=a,
+ alias=name,
+ )
+ for name, a in get_type_hints(cl).items()
+ ]
+
+
+def namedtuple_dict_structure_factory(
+ cl: type[tuple],
+ converter: BaseConverter,
+ detailed_validation: bool | Literal["from_converter"] = "from_converter",
+ forbid_extra_keys: bool = False,
+ use_linecache: bool = True,
+ /,
+ **kwargs: AttributeOverride,
+) -> StructureHook:
+ """A hook factory for hooks structuring namedtuples from dictionaries.
+
+ :param forbid_extra_keys: Whether the hook should raise a `ForbiddenExtraKeysError`
+ if unknown keys are encountered.
+ :param use_linecache: Whether to store the source code in the Python linecache.
+
+ .. versionadded:: 24.1.0
+ """
+ try:
+ working_set = already_generating.working_set
+ except AttributeError:
+ working_set = set()
+ already_generating.working_set = working_set
+ else:
+ if cl in working_set:
+ raise RecursionError()
+
+ working_set.add(cl)
+
+ try:
+ return make_dict_structure_fn_from_attrs(
+ _namedtuple_to_attrs(cl),
+ cl,
+ converter,
+ _cattrs_forbid_extra_keys=forbid_extra_keys,
+ _cattrs_use_detailed_validation=detailed_validation,
+ _cattrs_use_linecache=use_linecache,
+ **kwargs,
+ )
+ finally:
+ working_set.remove(cl)
+ if not working_set:
+ del already_generating.working_set
+
+
+def namedtuple_dict_unstructure_factory(
+ cl: type[tuple],
+ converter: BaseConverter,
+ omit_if_default: bool = False,
+ use_linecache: bool = True,
+ /,
+ **kwargs: AttributeOverride,
+) -> UnstructureHook:
+ """A hook factory for hooks unstructuring namedtuples to dictionaries.
+
+ :param omit_if_default: When true, attributes equal to their default values
+ will be omitted in the result dictionary.
+ :param use_linecache: Whether to store the source code in the Python linecache.
+
+ .. versionadded:: 24.1.0
+ """
+ try:
+ working_set = already_generating.working_set
+ except AttributeError:
+ working_set = set()
+ already_generating.working_set = working_set
+ if cl in working_set:
+ raise RecursionError()
+
+ working_set.add(cl)
+
+ try:
+ return make_dict_unstructure_fn_from_attrs(
+ _namedtuple_to_attrs(cl),
+ cl,
+ converter,
+ _cattrs_omit_if_default=omit_if_default,
+ _cattrs_use_linecache=use_linecache,
+ **kwargs,
+ )
+ finally:
+ working_set.remove(cl)
+ if not working_set:
+ del already_generating.working_set
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/converters.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/converters.py
new file mode 100644
index 0000000..1490ec2
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/converters.py
@@ -0,0 +1,1419 @@
+from __future__ import annotations
+
+from collections import Counter, deque
+from collections.abc import Mapping as AbcMapping
+from collections.abc import MutableMapping as AbcMutableMapping
+from collections.abc import MutableSet as AbcMutableSet
+from dataclasses import Field
+from enum import Enum
+from inspect import Signature
+from inspect import signature as inspect_signature
+from pathlib import Path
+from typing import Any, Callable, Iterable, Optional, Tuple, TypeVar, overload
+
+from attrs import Attribute, resolve_types
+from attrs import has as attrs_has
+
+from ._compat import (
+ ANIES,
+ FrozenSetSubscriptable,
+ Mapping,
+ MutableMapping,
+ MutableSequence,
+ NoneType,
+ OriginAbstractSet,
+ OriginMutableSet,
+ Sequence,
+ Set,
+ TypeAlias,
+ fields,
+ get_final_base,
+ get_newtype_base,
+ get_origin,
+ get_type_alias_base,
+ has,
+ has_with_generic,
+ is_annotated,
+ is_bare,
+ is_counter,
+ is_deque,
+ is_frozenset,
+ is_generic,
+ is_generic_attrs,
+ is_hetero_tuple,
+ is_literal,
+ is_mapping,
+ is_mutable_set,
+ is_optional,
+ is_protocol,
+ is_sequence,
+ is_tuple,
+ is_type_alias,
+ is_typeddict,
+ is_union_type,
+ signature,
+)
+from .cols import (
+ is_namedtuple,
+ iterable_unstructure_factory,
+ list_structure_factory,
+ namedtuple_structure_factory,
+ namedtuple_unstructure_factory,
+)
+from .disambiguators import create_default_dis_func, is_supported_union
+from .dispatch import (
+ HookFactory,
+ MultiStrategyDispatch,
+ StructuredValue,
+ StructureHook,
+ TargetType,
+ UnstructuredValue,
+ UnstructureHook,
+)
+from .errors import (
+ IterableValidationError,
+ IterableValidationNote,
+ StructureHandlerNotFoundError,
+)
+from .fns import Predicate, identity, raise_error
+from .gen import (
+ AttributeOverride,
+ DictStructureFn,
+ HeteroTupleUnstructureFn,
+ IterableUnstructureFn,
+ MappingStructureFn,
+ MappingUnstructureFn,
+ make_dict_structure_fn,
+ make_dict_unstructure_fn,
+ make_hetero_tuple_unstructure_fn,
+ make_mapping_structure_fn,
+ make_mapping_unstructure_fn,
+)
+from .gen.typeddicts import make_dict_structure_fn as make_typeddict_dict_struct_fn
+from .gen.typeddicts import make_dict_unstructure_fn as make_typeddict_dict_unstruct_fn
+
+__all__ = ["UnstructureStrategy", "BaseConverter", "Converter", "GenConverter"]
+
+T = TypeVar("T")
+V = TypeVar("V")
+
+UnstructureHookFactory = TypeVar(
+ "UnstructureHookFactory", bound=HookFactory[UnstructureHook]
+)
+
+# The Extended factory also takes a converter.
+ExtendedUnstructureHookFactory: TypeAlias = Callable[[TargetType, T], UnstructureHook]
+
+# This typevar for the BaseConverter.
+AnyUnstructureHookFactoryBase = TypeVar(
+ "AnyUnstructureHookFactoryBase",
+ bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[BaseConverter]",
+)
+
+# This typevar for the Converter.
+AnyUnstructureHookFactory = TypeVar(
+ "AnyUnstructureHookFactory",
+ bound="HookFactory[UnstructureHook] | ExtendedUnstructureHookFactory[Converter]",
+)
+
+StructureHookFactory = TypeVar("StructureHookFactory", bound=HookFactory[StructureHook])
+
+# The Extended factory also takes a converter.
+ExtendedStructureHookFactory: TypeAlias = Callable[[TargetType, T], StructureHook]
+
+# This typevar for the BaseConverter.
+AnyStructureHookFactoryBase = TypeVar(
+ "AnyStructureHookFactoryBase",
+ bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[BaseConverter]",
+)
+
+# This typevar for the Converter.
+AnyStructureHookFactory = TypeVar(
+ "AnyStructureHookFactory",
+ bound="HookFactory[StructureHook] | ExtendedStructureHookFactory[Converter]",
+)
+
+UnstructureHookT = TypeVar("UnstructureHookT", bound=UnstructureHook)
+StructureHookT = TypeVar("StructureHookT", bound=StructureHook)
+
+
+class UnstructureStrategy(Enum):
+ """`attrs` classes unstructuring strategies."""
+
+ AS_DICT = "asdict"
+ AS_TUPLE = "astuple"
+
+
+def is_literal_containing_enums(typ: type) -> bool:
+ return is_literal(typ) and any(isinstance(val, Enum) for val in typ.__args__)
+
+
+def _is_extended_factory(factory: Callable) -> bool:
+ """Does this factory also accept a converter arg?"""
+ # We use the original `inspect.signature` to not evaluate string
+ # annotations.
+ sig = inspect_signature(factory)
+ return (
+ len(sig.parameters) >= 2
+ and (list(sig.parameters.values())[1]).default is Signature.empty
+ )
+
+
+class BaseConverter:
+ """Converts between structured and unstructured data."""
+
+ __slots__ = (
+ "_unstructure_func",
+ "_unstructure_attrs",
+ "_structure_attrs",
+ "_dict_factory",
+ "_union_struct_registry",
+ "_structure_func",
+ "_prefer_attrib_converters",
+ "detailed_validation",
+ "_struct_copy_skip",
+ "_unstruct_copy_skip",
+ )
+
+ def __init__(
+ self,
+ dict_factory: Callable[[], Any] = dict,
+ unstruct_strat: UnstructureStrategy = UnstructureStrategy.AS_DICT,
+ prefer_attrib_converters: bool = False,
+ detailed_validation: bool = True,
+ unstructure_fallback_factory: HookFactory[UnstructureHook] = lambda _: identity,
+ structure_fallback_factory: HookFactory[StructureHook] = lambda _: raise_error,
+ ) -> None:
+ """
+ :param detailed_validation: Whether to use a slightly slower mode for detailed
+ validation errors.
+ :param unstructure_fallback_factory: A hook factory to be called when no
+ registered unstructuring hooks match.
+ :param structure_fallback_factory: A hook factory to be called when no
+ registered structuring hooks match.
+
+ .. versionadded:: 23.2.0 *unstructure_fallback_factory*
+ .. versionadded:: 23.2.0 *structure_fallback_factory*
+ """
+ unstruct_strat = UnstructureStrategy(unstruct_strat)
+ self._prefer_attrib_converters = prefer_attrib_converters
+
+ self.detailed_validation = detailed_validation
+ self._union_struct_registry: dict[Any, Callable[[Any, type[T]], T]] = {}
+
+ # Create a per-instance cache.
+ if unstruct_strat is UnstructureStrategy.AS_DICT:
+ self._unstructure_attrs = self.unstructure_attrs_asdict
+ self._structure_attrs = self.structure_attrs_fromdict
+ else:
+ self._unstructure_attrs = self.unstructure_attrs_astuple
+ self._structure_attrs = self.structure_attrs_fromtuple
+
+ self._unstructure_func = MultiStrategyDispatch(
+ unstructure_fallback_factory, self
+ )
+ self._unstructure_func.register_cls_list(
+ [(bytes, identity), (str, identity), (Path, str)]
+ )
+ self._unstructure_func.register_func_list(
+ [
+ (
+ is_protocol,
+ lambda o: self.unstructure(o, unstructure_as=o.__class__),
+ ),
+ (
+ lambda t: get_final_base(t) is not None,
+ lambda t: self.get_unstructure_hook(get_final_base(t)),
+ True,
+ ),
+ (
+ is_type_alias,
+ lambda t: self.get_unstructure_hook(get_type_alias_base(t)),
+ True,
+ ),
+ (is_mapping, self._unstructure_mapping),
+ (is_sequence, self._unstructure_seq),
+ (is_mutable_set, self._unstructure_seq),
+ (is_frozenset, self._unstructure_seq),
+ (lambda t: issubclass(t, Enum), self._unstructure_enum),
+ (has, self._unstructure_attrs),
+ (is_union_type, self._unstructure_union),
+ (lambda t: t in ANIES, self.unstructure),
+ ]
+ )
+
+ # Per-instance register of to-attrs converters.
+ # Singledispatch dispatches based on the first argument, so we
+ # store the function and switch the arguments in self.loads.
+ self._structure_func = MultiStrategyDispatch(structure_fallback_factory, self)
+ self._structure_func.register_func_list(
+ [
+ (
+ lambda cl: cl in ANIES or cl is Optional or cl is None,
+ lambda v, _: v,
+ ),
+ (is_generic_attrs, self._gen_structure_generic, True),
+ (lambda t: get_newtype_base(t) is not None, self._structure_newtype),
+ (is_type_alias, self._find_type_alias_structure_hook, True),
+ (
+ lambda t: get_final_base(t) is not None,
+ self._structure_final_factory,
+ True,
+ ),
+ (is_literal, self._structure_simple_literal),
+ (is_literal_containing_enums, self._structure_enum_literal),
+ (is_sequence, list_structure_factory, "extended"),
+ (is_deque, self._structure_deque),
+ (is_mutable_set, self._structure_set),
+ (is_frozenset, self._structure_frozenset),
+ (is_tuple, self._structure_tuple),
+ (is_namedtuple, namedtuple_structure_factory, "extended"),
+ (is_mapping, self._structure_dict),
+ (is_supported_union, self._gen_attrs_union_structure, True),
+ (is_optional, self._structure_optional),
+ (
+ lambda t: is_union_type(t) and t in self._union_struct_registry,
+ self._union_struct_registry.__getitem__,
+ True,
+ ),
+ (has, self._structure_attrs),
+ ]
+ )
+ # Strings are sequences.
+ self._structure_func.register_cls_list(
+ [
+ (str, self._structure_call),
+ (bytes, self._structure_call),
+ (int, self._structure_call),
+ (float, self._structure_call),
+ (Enum, self._structure_call),
+ (Path, self._structure_call),
+ ]
+ )
+
+ self._dict_factory = dict_factory
+
+ self._unstruct_copy_skip = self._unstructure_func.get_num_fns()
+ self._struct_copy_skip = self._structure_func.get_num_fns()
+
+ def unstructure(self, obj: Any, unstructure_as: Any = None) -> Any:
+ return self._unstructure_func.dispatch(
+ obj.__class__ if unstructure_as is None else unstructure_as
+ )(obj)
+
+ @property
+ def unstruct_strat(self) -> UnstructureStrategy:
+ """The default way of unstructuring ``attrs`` classes."""
+ return (
+ UnstructureStrategy.AS_DICT
+ if self._unstructure_attrs == self.unstructure_attrs_asdict
+ else UnstructureStrategy.AS_TUPLE
+ )
+
+ @overload
+ def register_unstructure_hook(self, cls: UnstructureHookT) -> UnstructureHookT: ...
+
+ @overload
+ def register_unstructure_hook(self, cls: Any, func: UnstructureHook) -> None: ...
+
+ def register_unstructure_hook(
+ self, cls: Any = None, func: UnstructureHook | None = None
+ ) -> Callable[[UnstructureHook]] | None:
+ """Register a class-to-primitive converter function for a class.
+
+ The converter function should take an instance of the class and return
+ its Python equivalent.
+
+ May also be used as a decorator. When used as a decorator, the first
+ argument annotation from the decorated function will be used as the
+ type to register the hook for.
+
+ .. versionchanged:: 24.1.0
+ This method may now be used as a decorator.
+ """
+ if func is None:
+ # Autodetecting decorator.
+ func = cls
+ sig = signature(func)
+ cls = next(iter(sig.parameters.values())).annotation
+ self.register_unstructure_hook(cls, func)
+
+ return func
+
+ if attrs_has(cls):
+ resolve_types(cls)
+ if is_union_type(cls):
+ self._unstructure_func.register_func_list([(lambda t: t == cls, func)])
+ elif get_newtype_base(cls) is not None:
+ # This is a newtype, so we handle it specially.
+ self._unstructure_func.register_func_list([(lambda t: t is cls, func)])
+ else:
+ self._unstructure_func.register_cls_list([(cls, func)])
+ return None
+
+ def register_unstructure_hook_func(
+ self, check_func: Predicate, func: UnstructureHook
+ ) -> None:
+ """Register a class-to-primitive converter function for a class, using
+ a function to check if it's a match.
+ """
+ self._unstructure_func.register_func_list([(check_func, func)])
+
+ @overload
+ def register_unstructure_hook_factory(
+ self, predicate: Predicate
+ ) -> Callable[[AnyUnstructureHookFactoryBase], AnyUnstructureHookFactoryBase]: ...
+
+ @overload
+ def register_unstructure_hook_factory(
+ self, predicate: Predicate, factory: UnstructureHookFactory
+ ) -> UnstructureHookFactory: ...
+
+ @overload
+ def register_unstructure_hook_factory(
+ self,
+ predicate: Predicate,
+ factory: ExtendedUnstructureHookFactory[BaseConverter],
+ ) -> ExtendedUnstructureHookFactory[BaseConverter]: ...
+
+ def register_unstructure_hook_factory(self, predicate, factory=None):
+ """
+ Register a hook factory for a given predicate.
+
+ The hook factory may expose an additional required parameter. In this case,
+ the current converter will be provided to the hook factory as that
+ parameter.
+
+ May also be used as a decorator.
+
+ :param predicate: A function that, given a type, returns whether the factory
+ can produce a hook for that type.
+ :param factory: A callable that, given a type, produces an unstructuring
+ hook for that type. This unstructuring hook will be cached.
+
+ .. versionchanged:: 24.1.0
+ This method may now be used as a decorator.
+ The factory may also receive the converter as a second, required argument.
+ """
+ if factory is None:
+
+ def decorator(factory):
+ # Is this an extended factory (takes a converter too)?
+ if _is_extended_factory(factory):
+ self._unstructure_func.register_func_list(
+ [(predicate, factory, "extended")]
+ )
+ else:
+ self._unstructure_func.register_func_list(
+ [(predicate, factory, True)]
+ )
+
+ return decorator
+
+ self._unstructure_func.register_func_list(
+ [
+ (
+ predicate,
+ factory,
+ "extended" if _is_extended_factory(factory) else True,
+ )
+ ]
+ )
+ return factory
+
+ def get_unstructure_hook(
+ self, type: Any, cache_result: bool = True
+ ) -> UnstructureHook:
+ """Get the unstructure hook for the given type.
+
+ This hook can be manually called, or composed with other functions
+ and re-registered.
+
+ If no hook is registered, the converter unstructure fallback factory
+ will be used to produce one.
+
+ :param cache: Whether to cache the returned hook.
+
+ .. versionadded:: 24.1.0
+ """
+ return (
+ self._unstructure_func.dispatch(type)
+ if cache_result
+ else self._unstructure_func.dispatch_without_caching(type)
+ )
+
+ @overload
+ def register_structure_hook(self, cl: StructureHookT) -> StructureHookT: ...
+
+ @overload
+ def register_structure_hook(self, cl: Any, func: StructureHook) -> None: ...
+
+ def register_structure_hook(
+ self, cl: Any, func: StructureHook | None = None
+ ) -> None:
+ """Register a primitive-to-class converter function for a type.
+
+ The converter function should take two arguments:
+ * a Python object to be converted,
+ * the type to convert to
+
+ and return the instance of the class. The type may seem redundant, but
+ is sometimes needed (for example, when dealing with generic classes).
+
+ This method may be used as a decorator. In this case, the decorated
+ hook must have a return type annotation, and this annotation will be used
+ as the type for the hook.
+
+ .. versionchanged:: 24.1.0
+ This method may now be used as a decorator.
+ """
+ if func is None:
+ # The autodetecting decorator.
+ func = cl
+ sig = signature(func)
+ self.register_structure_hook(sig.return_annotation, func)
+ return func
+
+ if attrs_has(cl):
+ resolve_types(cl)
+ if is_union_type(cl):
+ self._union_struct_registry[cl] = func
+ self._structure_func.clear_cache()
+ elif get_newtype_base(cl) is not None:
+ # This is a newtype, so we handle it specially.
+ self._structure_func.register_func_list([(lambda t: t is cl, func)])
+ else:
+ self._structure_func.register_cls_list([(cl, func)])
+ return None
+
+ def register_structure_hook_func(
+ self, check_func: Predicate, func: StructureHook
+ ) -> None:
+ """Register a class-to-primitive converter function for a class, using
+ a function to check if it's a match.
+ """
+ self._structure_func.register_func_list([(check_func, func)])
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate
+ ) -> Callable[[AnyStructureHookFactoryBase], AnyStructureHookFactoryBase]: ...
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate, factory: StructureHookFactory
+ ) -> StructureHookFactory: ...
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate, factory: ExtendedStructureHookFactory[BaseConverter]
+ ) -> ExtendedStructureHookFactory[BaseConverter]: ...
+
+ def register_structure_hook_factory(self, predicate, factory=None):
+ """
+ Register a hook factory for a given predicate.
+
+ The hook factory may expose an additional required parameter. In this case,
+ the current converter will be provided to the hook factory as that
+ parameter.
+
+ May also be used as a decorator.
+
+ :param predicate: A function that, given a type, returns whether the factory
+ can produce a hook for that type.
+ :param factory: A callable that, given a type, produces a structuring
+ hook for that type. This structuring hook will be cached.
+
+ .. versionchanged:: 24.1.0
+ This method may now be used as a decorator.
+ The factory may also receive the converter as a second, required argument.
+ """
+ if factory is None:
+ # Decorator use.
+ def decorator(factory):
+ # Is this an extended factory (takes a converter too)?
+ if _is_extended_factory(factory):
+ self._structure_func.register_func_list(
+ [(predicate, factory, "extended")]
+ )
+ else:
+ self._structure_func.register_func_list(
+ [(predicate, factory, True)]
+ )
+
+ return decorator
+ self._structure_func.register_func_list(
+ [
+ (
+ predicate,
+ factory,
+ "extended" if _is_extended_factory(factory) else True,
+ )
+ ]
+ )
+ return factory
+
+ def structure(self, obj: UnstructuredValue, cl: type[T]) -> T:
+ """Convert unstructured Python data structures to structured data."""
+ return self._structure_func.dispatch(cl)(obj, cl)
+
+ def get_structure_hook(self, type: Any, cache_result: bool = True) -> StructureHook:
+ """Get the structure hook for the given type.
+
+ This hook can be manually called, or composed with other functions
+ and re-registered.
+
+ If no hook is registered, the converter structure fallback factory
+ will be used to produce one.
+
+ :param cache: Whether to cache the returned hook.
+
+ .. versionadded:: 24.1.0
+ """
+ return (
+ self._structure_func.dispatch(type)
+ if cache_result
+ else self._structure_func.dispatch_without_caching(type)
+ )
+
+ # Classes to Python primitives.
+ def unstructure_attrs_asdict(self, obj: Any) -> dict[str, Any]:
+ """Our version of `attrs.asdict`, so we can call back to us."""
+ attrs = fields(obj.__class__)
+ dispatch = self._unstructure_func.dispatch
+ rv = self._dict_factory()
+ for a in attrs:
+ name = a.name
+ v = getattr(obj, name)
+ rv[name] = dispatch(a.type or v.__class__)(v)
+ return rv
+
+ def unstructure_attrs_astuple(self, obj: Any) -> tuple[Any, ...]:
+ """Our version of `attrs.astuple`, so we can call back to us."""
+ attrs = fields(obj.__class__)
+ dispatch = self._unstructure_func.dispatch
+ res = []
+ for a in attrs:
+ name = a.name
+ v = getattr(obj, name)
+ res.append(dispatch(a.type or v.__class__)(v))
+ return tuple(res)
+
+ def _unstructure_enum(self, obj: Enum) -> Any:
+ """Convert an enum to its value."""
+ return obj.value
+
+ def _unstructure_seq(self, seq: Sequence[T]) -> Sequence[T]:
+ """Convert a sequence to primitive equivalents."""
+ # We can reuse the sequence class, so tuples stay tuples.
+ dispatch = self._unstructure_func.dispatch
+ return seq.__class__(dispatch(e.__class__)(e) for e in seq)
+
+ def _unstructure_mapping(self, mapping: Mapping[T, V]) -> Mapping[T, V]:
+ """Convert a mapping of attr classes to primitive equivalents."""
+
+ # We can reuse the mapping class, so dicts stay dicts and OrderedDicts
+ # stay OrderedDicts.
+ dispatch = self._unstructure_func.dispatch
+ return mapping.__class__(
+ (dispatch(k.__class__)(k), dispatch(v.__class__)(v))
+ for k, v in mapping.items()
+ )
+
+ # note: Use UnionType when 3.11 is released as
+ # the behaviour of @final is changed. This would
+ # affect how we can support UnionType in ._compat.py
+ def _unstructure_union(self, obj: Any) -> Any:
+ """
+ Unstructure an object as a union.
+
+ By default, just unstructures the instance.
+ """
+ return self._unstructure_func.dispatch(obj.__class__)(obj)
+
+ # Python primitives to classes.
+
+ def _gen_structure_generic(self, cl: type[T]) -> DictStructureFn[T]:
+ """Create and return a hook for structuring generics."""
+ return make_dict_structure_fn(
+ cl, self, _cattrs_prefer_attrib_converters=self._prefer_attrib_converters
+ )
+
+ def _gen_attrs_union_structure(
+ self, cl: Any, use_literals: bool = True
+ ) -> Callable[[Any, type[T]], type[T] | None]:
+ """
+ Generate a structuring function for a union of attrs classes (and maybe None).
+
+ :param use_literals: Whether to consider literal fields.
+ """
+ dis_fn = self._get_dis_func(cl, use_literals=use_literals)
+ has_none = NoneType in cl.__args__
+
+ if has_none:
+
+ def structure_attrs_union(obj, _) -> cl:
+ if obj is None:
+ return None
+ return self.structure(obj, dis_fn(obj))
+
+ else:
+
+ def structure_attrs_union(obj, _):
+ return self.structure(obj, dis_fn(obj))
+
+ return structure_attrs_union
+
+ @staticmethod
+ def _structure_call(obj: Any, cl: type[T]) -> Any:
+ """Just call ``cl`` with the given ``obj``.
+
+ This is just an optimization on the ``_structure_default`` case, when
+ we know we can skip the ``if`` s. Use for ``str``, ``bytes``, ``enum``,
+ etc.
+ """
+ return cl(obj)
+
+ @staticmethod
+ def _structure_simple_literal(val, type):
+ if val not in type.__args__:
+ raise Exception(f"{val} not in literal {type}")
+ return val
+
+ @staticmethod
+ def _structure_enum_literal(val, type):
+ vals = {(x.value if isinstance(x, Enum) else x): x for x in type.__args__}
+ try:
+ return vals[val]
+ except KeyError:
+ raise Exception(f"{val} not in literal {type}") from None
+
+ def _structure_newtype(self, val: UnstructuredValue, type) -> StructuredValue:
+ base = get_newtype_base(type)
+ return self.get_structure_hook(base)(val, base)
+
+ def _find_type_alias_structure_hook(self, type: Any) -> StructureHook:
+ base = get_type_alias_base(type)
+ res = self.get_structure_hook(base)
+ if res == self._structure_call:
+ # we need to replace the type arg of `structure_call`
+ return lambda v, _, __base=base: __base(v)
+ return lambda v, _, __base=base: res(v, __base)
+
+ def _structure_final_factory(self, type):
+ base = get_final_base(type)
+ res = self.get_structure_hook(base)
+ return lambda v, _, __base=base: res(v, __base)
+
+ # Attrs classes.
+
+ def structure_attrs_fromtuple(self, obj: tuple[Any, ...], cl: type[T]) -> T:
+ """Load an attrs class from a sequence (tuple)."""
+ conv_obj = [] # A list of converter parameters.
+ for a, value in zip(fields(cl), obj):
+ # We detect the type by the metadata.
+ converted = self._structure_attribute(a, value)
+ conv_obj.append(converted)
+
+ return cl(*conv_obj)
+
+ def _structure_attribute(self, a: Attribute | Field, value: Any) -> Any:
+ """Handle an individual attrs attribute."""
+ type_ = a.type
+ attrib_converter = getattr(a, "converter", None)
+ if self._prefer_attrib_converters and attrib_converter:
+ # A attrib converter is defined on this attribute, and
+ # prefer_attrib_converters is set to give these priority over registered
+ # structure hooks. So, pass through the raw value, which attrs will flow
+ # into the converter
+ return value
+ if type_ is None:
+ # No type metadata.
+ return value
+
+ try:
+ return self._structure_func.dispatch(type_)(value, type_)
+ except StructureHandlerNotFoundError:
+ if attrib_converter:
+ # Return the original value and fallback to using an attrib converter.
+ return value
+ raise
+
+ def structure_attrs_fromdict(self, obj: Mapping[str, Any], cl: type[T]) -> T:
+ """Instantiate an attrs class from a mapping (dict)."""
+ # For public use.
+
+ conv_obj = {} # Start with a fresh dict, to ignore extra keys.
+ for a in fields(cl):
+ try:
+ val = obj[a.name]
+ except KeyError:
+ continue
+
+ # try .alias and .name because this code also supports dataclasses!
+ conv_obj[getattr(a, "alias", a.name)] = self._structure_attribute(a, val)
+
+ return cl(**conv_obj)
+
+ def _structure_deque(self, obj: Iterable[T], cl: Any) -> deque[T]:
+ """Convert an iterable to a potentially generic deque."""
+ if is_bare(cl) or cl.__args__[0] in ANIES:
+ res = deque(obj)
+ else:
+ elem_type = cl.__args__[0]
+ handler = self._structure_func.dispatch(elem_type)
+ if self.detailed_validation:
+ errors = []
+ res = deque()
+ ix = 0 # Avoid `enumerate` for performance.
+ for e in obj:
+ try:
+ res.append(handler(e, elem_type))
+ except Exception as e:
+ msg = IterableValidationNote(
+ f"Structuring {cl} @ index {ix}", ix, elem_type
+ )
+ e.__notes__ = [*getattr(e, "__notes__", []), msg]
+ errors.append(e)
+ finally:
+ ix += 1
+ if errors:
+ raise IterableValidationError(
+ f"While structuring {cl!r}", errors, cl
+ )
+ else:
+ res = deque(handler(e, elem_type) for e in obj)
+ return res
+
+ def _structure_set(
+ self, obj: Iterable[T], cl: Any, structure_to: type = set
+ ) -> Set[T]:
+ """Convert an iterable into a potentially generic set."""
+ if is_bare(cl) or cl.__args__[0] in ANIES:
+ return structure_to(obj)
+ elem_type = cl.__args__[0]
+ handler = self._structure_func.dispatch(elem_type)
+ if self.detailed_validation:
+ errors = []
+ res = set()
+ ix = 0
+ for e in obj:
+ try:
+ res.add(handler(e, elem_type))
+ except Exception as exc:
+ msg = IterableValidationNote(
+ f"Structuring {structure_to.__name__} @ element {e!r}",
+ ix,
+ elem_type,
+ )
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+ finally:
+ ix += 1
+ if errors:
+ raise IterableValidationError(f"While structuring {cl!r}", errors, cl)
+ return res if structure_to is set else structure_to(res)
+ if structure_to is set:
+ return {handler(e, elem_type) for e in obj}
+ return structure_to([handler(e, elem_type) for e in obj])
+
+ def _structure_frozenset(
+ self, obj: Iterable[T], cl: Any
+ ) -> FrozenSetSubscriptable[T]:
+ """Convert an iterable into a potentially generic frozenset."""
+ return self._structure_set(obj, cl, structure_to=frozenset)
+
+ def _structure_dict(self, obj: Mapping[T, V], cl: Any) -> dict[T, V]:
+ """Convert a mapping into a potentially generic dict."""
+ if is_bare(cl) or cl.__args__ == (Any, Any):
+ return dict(obj)
+ key_type, val_type = cl.__args__
+
+ if self.detailed_validation:
+ key_handler = self._structure_func.dispatch(key_type)
+ val_handler = self._structure_func.dispatch(val_type)
+ errors = []
+ res = {}
+
+ for k, v in obj.items():
+ try:
+ value = val_handler(v, val_type)
+ except Exception as exc:
+ msg = IterableValidationNote(
+ f"Structuring mapping value @ key {k!r}", k, val_type
+ )
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+ continue
+
+ try:
+ key = key_handler(k, key_type)
+ res[key] = value
+ except Exception as exc:
+ msg = IterableValidationNote(
+ f"Structuring mapping key @ key {k!r}", k, key_type
+ )
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+
+ if errors:
+ raise IterableValidationError(f"While structuring {cl!r}", errors, cl)
+ return res
+
+ if key_type in ANIES:
+ val_conv = self._structure_func.dispatch(val_type)
+ return {k: val_conv(v, val_type) for k, v in obj.items()}
+ if val_type in ANIES:
+ key_conv = self._structure_func.dispatch(key_type)
+ return {key_conv(k, key_type): v for k, v in obj.items()}
+ key_conv = self._structure_func.dispatch(key_type)
+ val_conv = self._structure_func.dispatch(val_type)
+ return {key_conv(k, key_type): val_conv(v, val_type) for k, v in obj.items()}
+
+ def _structure_optional(self, obj, union):
+ if obj is None:
+ return None
+ union_params = union.__args__
+ other = union_params[0] if union_params[1] is NoneType else union_params[1]
+ # We can't actually have a Union of a Union, so this is safe.
+ return self._structure_func.dispatch(other)(obj, other)
+
+ def _structure_tuple(self, obj: Any, tup: type[T]) -> T:
+ """Deal with structuring into a tuple."""
+ tup_params = None if tup in (Tuple, tuple) else tup.__args__
+ has_ellipsis = tup_params and tup_params[-1] is Ellipsis
+ if tup_params is None or (has_ellipsis and tup_params[0] in ANIES):
+ # Just a Tuple. (No generic information.)
+ return tuple(obj)
+ if has_ellipsis:
+ # We're dealing with a homogenous tuple, Tuple[int, ...]
+ tup_type = tup_params[0]
+ conv = self._structure_func.dispatch(tup_type)
+ if self.detailed_validation:
+ errors = []
+ res = []
+ ix = 0
+ for e in obj:
+ try:
+ res.append(conv(e, tup_type))
+ except Exception as exc:
+ msg = IterableValidationNote(
+ f"Structuring {tup} @ index {ix}", ix, tup_type
+ )
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+ finally:
+ ix += 1
+ if errors:
+ raise IterableValidationError(
+ f"While structuring {tup!r}", errors, tup
+ )
+ return tuple(res)
+ return tuple(conv(e, tup_type) for e in obj)
+
+ # We're dealing with a heterogenous tuple.
+ exp_len = len(tup_params)
+ try:
+ len_obj = len(obj)
+ except TypeError:
+ pass # most likely an unsized iterator, eg generator
+ else:
+ if len_obj > exp_len:
+ exp_len = len_obj
+ if self.detailed_validation:
+ errors = []
+ res = []
+ for ix, (t, e) in enumerate(zip(tup_params, obj)):
+ try:
+ conv = self._structure_func.dispatch(t)
+ res.append(conv(e, t))
+ except Exception as exc:
+ msg = IterableValidationNote(
+ f"Structuring {tup} @ index {ix}", ix, t
+ )
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+ if len(res) < exp_len:
+ problem = "Not enough" if len(res) < len(tup_params) else "Too many"
+ exc = ValueError(f"{problem} values in {obj!r} to structure as {tup!r}")
+ msg = f"Structuring {tup}"
+ exc.__notes__ = [*getattr(exc, "__notes__", []), msg]
+ errors.append(exc)
+ if errors:
+ raise IterableValidationError(f"While structuring {tup!r}", errors, tup)
+ return tuple(res)
+
+ res = tuple(
+ [self._structure_func.dispatch(t)(e, t) for t, e in zip(tup_params, obj)]
+ )
+ if len(res) < exp_len:
+ problem = "Not enough" if len(res) < len(tup_params) else "Too many"
+ raise ValueError(f"{problem} values in {obj!r} to structure as {tup!r}")
+ return res
+
+ def _get_dis_func(
+ self,
+ union: Any,
+ use_literals: bool = True,
+ overrides: dict[str, AttributeOverride] | None = None,
+ ) -> Callable[[Any], type]:
+ """Fetch or try creating a disambiguation function for a union."""
+ union_types = union.__args__
+ if NoneType in union_types:
+ # We support unions of attrs classes and NoneType higher in the
+ # logic.
+ union_types = tuple(e for e in union_types if e is not NoneType)
+
+ # TODO: technically both disambiguators could support TypedDicts and
+ # dataclasses...
+ if not all(has(get_origin(e) or e) for e in union_types):
+ raise StructureHandlerNotFoundError(
+ "Only unions of attrs classes supported "
+ "currently. Register a structure hook manually.",
+ type_=union,
+ )
+
+ return create_default_dis_func(
+ self,
+ *union_types,
+ use_literals=use_literals,
+ overrides=overrides if overrides is not None else "from_converter",
+ )
+
+ def __deepcopy__(self, _) -> BaseConverter:
+ return self.copy()
+
+ def copy(
+ self,
+ dict_factory: Callable[[], Any] | None = None,
+ unstruct_strat: UnstructureStrategy | None = None,
+ prefer_attrib_converters: bool | None = None,
+ detailed_validation: bool | None = None,
+ ) -> BaseConverter:
+ """Create a copy of the converter, keeping all existing custom hooks.
+
+ :param detailed_validation: Whether to use a slightly slower mode for detailed
+ validation errors.
+ """
+ res = self.__class__(
+ dict_factory if dict_factory is not None else self._dict_factory,
+ (
+ unstruct_strat
+ if unstruct_strat is not None
+ else (
+ UnstructureStrategy.AS_DICT
+ if self._unstructure_attrs == self.unstructure_attrs_asdict
+ else UnstructureStrategy.AS_TUPLE
+ )
+ ),
+ (
+ prefer_attrib_converters
+ if prefer_attrib_converters is not None
+ else self._prefer_attrib_converters
+ ),
+ (
+ detailed_validation
+ if detailed_validation is not None
+ else self.detailed_validation
+ ),
+ )
+
+ self._unstructure_func.copy_to(res._unstructure_func, self._unstruct_copy_skip)
+ self._structure_func.copy_to(res._structure_func, self._struct_copy_skip)
+
+ return res
+
+
+class Converter(BaseConverter):
+ """A converter which generates specialized un/structuring functions."""
+
+ __slots__ = (
+ "omit_if_default",
+ "forbid_extra_keys",
+ "type_overrides",
+ "_unstruct_collection_overrides",
+ )
+
+ def __init__(
+ self,
+ dict_factory: Callable[[], Any] = dict,
+ unstruct_strat: UnstructureStrategy = UnstructureStrategy.AS_DICT,
+ omit_if_default: bool = False,
+ forbid_extra_keys: bool = False,
+ type_overrides: Mapping[type, AttributeOverride] = {},
+ unstruct_collection_overrides: Mapping[type, Callable] = {},
+ prefer_attrib_converters: bool = False,
+ detailed_validation: bool = True,
+ unstructure_fallback_factory: HookFactory[UnstructureHook] = lambda _: identity,
+ structure_fallback_factory: HookFactory[StructureHook] = lambda _: raise_error,
+ ):
+ """
+ :param detailed_validation: Whether to use a slightly slower mode for detailed
+ validation errors.
+ :param unstructure_fallback_factory: A hook factory to be called when no
+ registered unstructuring hooks match.
+ :param structure_fallback_factory: A hook factory to be called when no
+ registered structuring hooks match.
+
+ .. versionadded:: 23.2.0 *unstructure_fallback_factory*
+ .. versionadded:: 23.2.0 *structure_fallback_factory*
+ """
+ super().__init__(
+ dict_factory=dict_factory,
+ unstruct_strat=unstruct_strat,
+ prefer_attrib_converters=prefer_attrib_converters,
+ detailed_validation=detailed_validation,
+ unstructure_fallback_factory=unstructure_fallback_factory,
+ structure_fallback_factory=structure_fallback_factory,
+ )
+ self.omit_if_default = omit_if_default
+ self.forbid_extra_keys = forbid_extra_keys
+ self.type_overrides = dict(type_overrides)
+
+ unstruct_collection_overrides = {
+ get_origin(k) or k: v for k, v in unstruct_collection_overrides.items()
+ }
+
+ self._unstruct_collection_overrides = unstruct_collection_overrides
+
+ # Do a little post-processing magic to make things easier for users.
+ co = unstruct_collection_overrides
+
+ # abc.Set overrides, if defined, apply to abc.MutableSets and sets
+ if OriginAbstractSet in co:
+ if OriginMutableSet not in co:
+ co[OriginMutableSet] = co[OriginAbstractSet]
+ co[AbcMutableSet] = co[OriginAbstractSet] # For 3.8 compatibility.
+ if FrozenSetSubscriptable not in co:
+ co[FrozenSetSubscriptable] = co[OriginAbstractSet]
+
+ # abc.MutableSet overrrides, if defined, apply to sets
+ if OriginMutableSet in co and set not in co:
+ co[set] = co[OriginMutableSet]
+
+ if FrozenSetSubscriptable in co:
+ co[frozenset] = co[FrozenSetSubscriptable] # For 3.8 compatibility.
+
+ # abc.Sequence overrides, if defined, can apply to MutableSequences, lists and
+ # tuples
+ if Sequence in co:
+ if MutableSequence not in co:
+ co[MutableSequence] = co[Sequence]
+ if tuple not in co:
+ co[tuple] = co[Sequence]
+
+ # abc.MutableSequence overrides, if defined, can apply to lists
+ if MutableSequence in co:
+ if list not in co:
+ co[list] = co[MutableSequence]
+ if deque not in co:
+ co[deque] = co[MutableSequence]
+
+ # abc.Mapping overrides, if defined, can apply to MutableMappings
+ if Mapping in co and MutableMapping not in co:
+ co[MutableMapping] = co[Mapping]
+
+ # abc.MutableMapping overrides, if defined, can apply to dicts
+ if MutableMapping in co and dict not in co:
+ co[dict] = co[MutableMapping]
+
+ # builtins.dict overrides, if defined, can apply to counters
+ if dict in co and Counter not in co:
+ co[Counter] = co[dict]
+
+ if unstruct_strat is UnstructureStrategy.AS_DICT:
+ # Override the attrs handler.
+ self.register_unstructure_hook_factory(
+ has_with_generic, self.gen_unstructure_attrs_fromdict
+ )
+ self.register_structure_hook_factory(
+ has_with_generic, self.gen_structure_attrs_fromdict
+ )
+ self.register_unstructure_hook_factory(
+ is_annotated, self.gen_unstructure_annotated
+ )
+ self.register_unstructure_hook_factory(
+ is_hetero_tuple, self.gen_unstructure_hetero_tuple
+ )
+ self.register_unstructure_hook_factory(is_namedtuple)(
+ namedtuple_unstructure_factory
+ )
+ self.register_unstructure_hook_factory(
+ is_sequence, self.gen_unstructure_iterable
+ )
+ self.register_unstructure_hook_factory(is_mapping, self.gen_unstructure_mapping)
+ self.register_unstructure_hook_factory(
+ is_mutable_set,
+ lambda cl: self.gen_unstructure_iterable(cl, unstructure_to=set),
+ )
+ self.register_unstructure_hook_factory(
+ is_frozenset,
+ lambda cl: self.gen_unstructure_iterable(cl, unstructure_to=frozenset),
+ )
+ self.register_unstructure_hook_factory(
+ is_optional, self.gen_unstructure_optional
+ )
+ self.register_unstructure_hook_factory(
+ is_typeddict, self.gen_unstructure_typeddict
+ )
+ self.register_unstructure_hook_factory(
+ lambda t: get_newtype_base(t) is not None,
+ lambda t: self.get_unstructure_hook(get_newtype_base(t)),
+ )
+
+ self.register_structure_hook_factory(is_annotated, self.gen_structure_annotated)
+ self.register_structure_hook_factory(is_mapping, self.gen_structure_mapping)
+ self.register_structure_hook_factory(is_counter, self.gen_structure_counter)
+ self.register_structure_hook_factory(is_typeddict, self.gen_structure_typeddict)
+ self.register_structure_hook_factory(
+ lambda t: get_newtype_base(t) is not None, self.get_structure_newtype
+ )
+
+ # We keep these so we can more correctly copy the hooks.
+ self._struct_copy_skip = self._structure_func.get_num_fns()
+ self._unstruct_copy_skip = self._unstructure_func.get_num_fns()
+
+ @overload
+ def register_unstructure_hook_factory(
+ self, predicate: Predicate
+ ) -> Callable[[AnyUnstructureHookFactory], AnyUnstructureHookFactory]: ...
+
+ @overload
+ def register_unstructure_hook_factory(
+ self, predicate: Predicate, factory: UnstructureHookFactory
+ ) -> UnstructureHookFactory: ...
+
+ @overload
+ def register_unstructure_hook_factory(
+ self, predicate: Predicate, factory: ExtendedUnstructureHookFactory[Converter]
+ ) -> ExtendedUnstructureHookFactory[Converter]: ...
+
+ def register_unstructure_hook_factory(self, predicate, factory=None):
+ # This dummy wrapper is required due to how `@overload` works.
+ return super().register_unstructure_hook_factory(predicate, factory)
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate
+ ) -> Callable[[AnyStructureHookFactory], AnyStructureHookFactory]: ...
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate, factory: StructureHookFactory
+ ) -> StructureHookFactory: ...
+
+ @overload
+ def register_structure_hook_factory(
+ self, predicate: Predicate, factory: ExtendedStructureHookFactory[Converter]
+ ) -> ExtendedStructureHookFactory[Converter]: ...
+
+ def register_structure_hook_factory(self, predicate, factory=None):
+ # This dummy wrapper is required due to how `@overload` works.
+ return super().register_structure_hook_factory(predicate, factory)
+
+ def get_structure_newtype(self, type: type[T]) -> Callable[[Any, Any], T]:
+ base = get_newtype_base(type)
+ handler = self.get_structure_hook(base)
+ return lambda v, _: handler(v, base)
+
+ def gen_unstructure_annotated(self, type):
+ origin = type.__origin__
+ return self.get_unstructure_hook(origin)
+
+ def gen_structure_annotated(self, type) -> Callable:
+ """A hook factory for annotated types."""
+ origin = type.__origin__
+ hook = self.get_structure_hook(origin)
+ return lambda v, _: hook(v, origin)
+
+ def gen_unstructure_typeddict(self, cl: Any) -> Callable[[dict], dict]:
+ """Generate a TypedDict unstructure function.
+
+ Also apply converter-scored modifications.
+ """
+ return make_typeddict_dict_unstruct_fn(cl, self)
+
+ def gen_unstructure_attrs_fromdict(
+ self, cl: type[T]
+ ) -> Callable[[T], dict[str, Any]]:
+ origin = get_origin(cl)
+ attribs = fields(origin or cl)
+ if attrs_has(cl) and any(isinstance(a.type, str) for a in attribs):
+ # PEP 563 annotations - need to be resolved.
+ resolve_types(cl)
+ attrib_overrides = {
+ a.name: self.type_overrides[a.type]
+ for a in attribs
+ if a.type in self.type_overrides
+ }
+
+ return make_dict_unstructure_fn(
+ cl, self, _cattrs_omit_if_default=self.omit_if_default, **attrib_overrides
+ )
+
+ def gen_unstructure_optional(self, cl: type[T]) -> Callable[[T], Any]:
+ """Generate an unstructuring hook for optional types."""
+ union_params = cl.__args__
+ other = union_params[0] if union_params[1] is NoneType else union_params[1]
+
+ if isinstance(other, TypeVar):
+ handler = self.unstructure
+ else:
+ handler = self.get_unstructure_hook(other)
+
+ def unstructure_optional(val, _handler=handler):
+ return None if val is None else _handler(val)
+
+ return unstructure_optional
+
+ def gen_structure_typeddict(self, cl: Any) -> Callable[[dict, Any], dict]:
+ """Generate a TypedDict structure function.
+
+ Also apply converter-scored modifications.
+ """
+ return make_typeddict_dict_struct_fn(
+ cl, self, _cattrs_detailed_validation=self.detailed_validation
+ )
+
+ def gen_structure_attrs_fromdict(
+ self, cl: type[T]
+ ) -> Callable[[Mapping[str, Any], Any], T]:
+ attribs = fields(get_origin(cl) or cl if is_generic(cl) else cl)
+ if attrs_has(cl) and any(isinstance(a.type, str) for a in attribs):
+ # PEP 563 annotations - need to be resolved.
+ resolve_types(cl)
+ attrib_overrides = {
+ a.name: self.type_overrides[a.type]
+ for a in attribs
+ if a.type in self.type_overrides
+ }
+ return make_dict_structure_fn(
+ cl,
+ self,
+ _cattrs_forbid_extra_keys=self.forbid_extra_keys,
+ _cattrs_prefer_attrib_converters=self._prefer_attrib_converters,
+ _cattrs_detailed_validation=self.detailed_validation,
+ **attrib_overrides,
+ )
+
+ def gen_unstructure_iterable(
+ self, cl: Any, unstructure_to: Any = None
+ ) -> IterableUnstructureFn:
+ unstructure_to = self._unstruct_collection_overrides.get(
+ get_origin(cl) or cl, unstructure_to or list
+ )
+ h = iterable_unstructure_factory(cl, self, unstructure_to=unstructure_to)
+ self._unstructure_func.register_cls_list([(cl, h)], direct=True)
+ return h
+
+ def gen_unstructure_hetero_tuple(
+ self, cl: Any, unstructure_to: Any = None
+ ) -> HeteroTupleUnstructureFn:
+ unstructure_to = self._unstruct_collection_overrides.get(
+ get_origin(cl) or cl, unstructure_to or tuple
+ )
+ h = make_hetero_tuple_unstructure_fn(cl, self, unstructure_to=unstructure_to)
+ self._unstructure_func.register_cls_list([(cl, h)], direct=True)
+ return h
+
+ def gen_unstructure_mapping(
+ self,
+ cl: Any,
+ unstructure_to: Any = None,
+ key_handler: Callable[[Any, Any | None], Any] | None = None,
+ ) -> MappingUnstructureFn:
+ unstructure_to = self._unstruct_collection_overrides.get(
+ get_origin(cl) or cl, unstructure_to or dict
+ )
+ h = make_mapping_unstructure_fn(
+ cl, self, unstructure_to=unstructure_to, key_handler=key_handler
+ )
+ self._unstructure_func.register_cls_list([(cl, h)], direct=True)
+ return h
+
+ def gen_structure_counter(self, cl: Any) -> MappingStructureFn[T]:
+ h = make_mapping_structure_fn(
+ cl,
+ self,
+ structure_to=Counter,
+ val_type=int,
+ detailed_validation=self.detailed_validation,
+ )
+ self._structure_func.register_cls_list([(cl, h)], direct=True)
+ return h
+
+ def gen_structure_mapping(self, cl: Any) -> MappingStructureFn[T]:
+ structure_to = get_origin(cl) or cl
+ if structure_to in (
+ MutableMapping,
+ AbcMutableMapping,
+ Mapping,
+ AbcMapping,
+ ): # These default to dicts
+ structure_to = dict
+ h = make_mapping_structure_fn(
+ cl, self, structure_to, detailed_validation=self.detailed_validation
+ )
+ self._structure_func.register_cls_list([(cl, h)], direct=True)
+ return h
+
+ def copy(
+ self,
+ dict_factory: Callable[[], Any] | None = None,
+ unstruct_strat: UnstructureStrategy | None = None,
+ omit_if_default: bool | None = None,
+ forbid_extra_keys: bool | None = None,
+ type_overrides: Mapping[type, AttributeOverride] | None = None,
+ unstruct_collection_overrides: Mapping[type, Callable] | None = None,
+ prefer_attrib_converters: bool | None = None,
+ detailed_validation: bool | None = None,
+ ) -> Converter:
+ """Create a copy of the converter, keeping all existing custom hooks.
+
+ :param detailed_validation: Whether to use a slightly slower mode for detailed
+ validation errors.
+ """
+ res = self.__class__(
+ dict_factory if dict_factory is not None else self._dict_factory,
+ (
+ unstruct_strat
+ if unstruct_strat is not None
+ else (
+ UnstructureStrategy.AS_DICT
+ if self._unstructure_attrs == self.unstructure_attrs_asdict
+ else UnstructureStrategy.AS_TUPLE
+ )
+ ),
+ omit_if_default if omit_if_default is not None else self.omit_if_default,
+ (
+ forbid_extra_keys
+ if forbid_extra_keys is not None
+ else self.forbid_extra_keys
+ ),
+ type_overrides if type_overrides is not None else self.type_overrides,
+ (
+ unstruct_collection_overrides
+ if unstruct_collection_overrides is not None
+ else self._unstruct_collection_overrides
+ ),
+ (
+ prefer_attrib_converters
+ if prefer_attrib_converters is not None
+ else self._prefer_attrib_converters
+ ),
+ (
+ detailed_validation
+ if detailed_validation is not None
+ else self.detailed_validation
+ ),
+ )
+
+ self._unstructure_func.copy_to(
+ res._unstructure_func, skip=self._unstruct_copy_skip
+ )
+ self._structure_func.copy_to(res._structure_func, skip=self._struct_copy_skip)
+
+ return res
+
+
+GenConverter: TypeAlias = Converter
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/disambiguators.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/disambiguators.py
new file mode 100644
index 0000000..ad36ae3
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/disambiguators.py
@@ -0,0 +1,205 @@
+"""Utilities for union (sum type) disambiguation."""
+
+from __future__ import annotations
+
+from collections import defaultdict
+from dataclasses import MISSING
+from functools import reduce
+from operator import or_
+from typing import TYPE_CHECKING, Any, Callable, Literal, Mapping, Union
+
+from attrs import NOTHING, Attribute, AttrsInstance
+
+from ._compat import (
+ NoneType,
+ adapted_fields,
+ fields_dict,
+ get_args,
+ get_origin,
+ has,
+ is_literal,
+ is_union_type,
+)
+from .gen import AttributeOverride
+
+if TYPE_CHECKING:
+ from .converters import BaseConverter
+
+__all__ = ["is_supported_union", "create_default_dis_func"]
+
+
+def is_supported_union(typ: Any) -> bool:
+ """Whether the type is a union of attrs classes."""
+ return is_union_type(typ) and all(
+ e is NoneType or has(get_origin(e) or e) for e in typ.__args__
+ )
+
+
+def create_default_dis_func(
+ converter: BaseConverter,
+ *classes: type[AttrsInstance],
+ use_literals: bool = True,
+ overrides: (
+ dict[str, AttributeOverride] | Literal["from_converter"]
+ ) = "from_converter",
+) -> Callable[[Mapping[Any, Any]], type[Any] | None]:
+ """Given attrs classes or dataclasses, generate a disambiguation function.
+
+ The function is based on unique fields without defaults or unique values.
+
+ :param use_literals: Whether to try using fields annotated as literals for
+ disambiguation.
+ :param overrides: Attribute overrides to apply.
+
+ .. versionchanged:: 24.1.0
+ Dataclasses are now supported.
+ """
+ if len(classes) < 2:
+ raise ValueError("At least two classes required.")
+
+ if overrides == "from_converter":
+ overrides = [
+ getattr(converter.get_structure_hook(c), "overrides", {}) for c in classes
+ ]
+ else:
+ overrides = [overrides for _ in classes]
+
+ # first, attempt for unique values
+ if use_literals:
+ # requirements for a discriminator field:
+ # (... TODO: a single fallback is OK)
+ # - it must always be enumerated
+ cls_candidates = [
+ {
+ at.name
+ for at in adapted_fields(get_origin(cl) or cl)
+ if is_literal(at.type)
+ }
+ for cl in classes
+ ]
+
+ # literal field names common to all members
+ discriminators: set[str] = cls_candidates[0]
+ for possible_discriminators in cls_candidates:
+ discriminators &= possible_discriminators
+
+ best_result = None
+ best_discriminator = None
+ for discriminator in discriminators:
+ # maps Literal values (strings, ints...) to classes
+ mapping = defaultdict(list)
+
+ for cl in classes:
+ for key in get_args(
+ fields_dict(get_origin(cl) or cl)[discriminator].type
+ ):
+ mapping[key].append(cl)
+
+ if best_result is None or max(len(v) for v in mapping.values()) <= max(
+ len(v) for v in best_result.values()
+ ):
+ best_result = mapping
+ best_discriminator = discriminator
+
+ if (
+ best_result
+ and best_discriminator
+ and max(len(v) for v in best_result.values()) != len(classes)
+ ):
+ final_mapping = {
+ k: v[0] if len(v) == 1 else Union[tuple(v)]
+ for k, v in best_result.items()
+ }
+
+ def dis_func(data: Mapping[Any, Any]) -> type | None:
+ if not isinstance(data, Mapping):
+ raise ValueError("Only input mappings are supported.")
+ return final_mapping[data[best_discriminator]]
+
+ return dis_func
+
+ # next, attempt for unique keys
+
+ # NOTE: This could just as well work with just field availability and not
+ # uniqueness, returning Unions ... it doesn't do that right now.
+ cls_and_attrs = [
+ (cl, *_usable_attribute_names(cl, override))
+ for cl, override in zip(classes, overrides)
+ ]
+ # For each class, attempt to generate a single unique required field.
+ uniq_attrs_dict: dict[str, type] = {}
+
+ # We start from classes with the largest number of unique fields
+ # so we can do easy picks first, making later picks easier.
+ cls_and_attrs.sort(key=lambda c_a: len(c_a[1]), reverse=True)
+
+ fallback = None # If none match, try this.
+
+ for cl, cl_reqs, back_map in cls_and_attrs:
+ # We do not have to consider classes we've already processed, since
+ # they will have been eliminated by the match dictionary already.
+ other_classes = [
+ c_and_a
+ for c_and_a in cls_and_attrs
+ if c_and_a[0] is not cl and c_and_a[0] not in uniq_attrs_dict.values()
+ ]
+ other_reqs = reduce(or_, (c_a[1] for c_a in other_classes), set())
+ uniq = cl_reqs - other_reqs
+
+ # We want a unique attribute with no default.
+ cl_fields = fields_dict(get_origin(cl) or cl)
+ for maybe_renamed_attr_name in uniq:
+ orig_name = back_map[maybe_renamed_attr_name]
+ if cl_fields[orig_name].default in (NOTHING, MISSING):
+ break
+ else:
+ if fallback is None:
+ fallback = cl
+ continue
+ raise TypeError(f"{cl} has no usable non-default attributes")
+ uniq_attrs_dict[maybe_renamed_attr_name] = cl
+
+ if fallback is None:
+
+ def dis_func(data: Mapping[Any, Any]) -> type[AttrsInstance] | None:
+ if not isinstance(data, Mapping):
+ raise ValueError("Only input mappings are supported")
+ for k, v in uniq_attrs_dict.items():
+ if k in data:
+ return v
+ raise ValueError("Couldn't disambiguate")
+
+ else:
+
+ def dis_func(data: Mapping[Any, Any]) -> type[AttrsInstance] | None:
+ if not isinstance(data, Mapping):
+ raise ValueError("Only input mappings are supported")
+ for k, v in uniq_attrs_dict.items():
+ if k in data:
+ return v
+ return fallback
+
+ return dis_func
+
+
+create_uniq_field_dis_func = create_default_dis_func
+
+
+def _overriden_name(at: Attribute, override: AttributeOverride | None) -> str:
+ if override is None or override.rename is None:
+ return at.name
+ return override.rename
+
+
+def _usable_attribute_names(
+ cl: type[Any], overrides: dict[str, AttributeOverride]
+) -> tuple[set[str], dict[str, str]]:
+ """Return renamed fields and a mapping to original field names."""
+ res = set()
+ mapping = {}
+
+ for at in adapted_fields(get_origin(cl) or cl):
+ res.add(n := _overriden_name(at, overrides.get(at.name)))
+ mapping[n] = at.name
+
+ return res, mapping
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/dispatch.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/dispatch.py
new file mode 100644
index 0000000..3d746db
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/dispatch.py
@@ -0,0 +1,194 @@
+from __future__ import annotations
+
+from functools import lru_cache, singledispatch
+from typing import TYPE_CHECKING, Any, Callable, Generic, Literal, TypeVar
+
+from attrs import Factory, define
+
+from ._compat import TypeAlias
+from .fns import Predicate
+
+if TYPE_CHECKING:
+ from .converters import BaseConverter
+
+TargetType: TypeAlias = Any
+UnstructuredValue: TypeAlias = Any
+StructuredValue: TypeAlias = Any
+
+StructureHook: TypeAlias = Callable[[UnstructuredValue, TargetType], StructuredValue]
+UnstructureHook: TypeAlias = Callable[[StructuredValue], UnstructuredValue]
+
+Hook = TypeVar("Hook", StructureHook, UnstructureHook)
+HookFactory: TypeAlias = Callable[[TargetType], Hook]
+
+
+@define
+class _DispatchNotFound:
+ """A dummy object to help signify a dispatch not found."""
+
+
+@define
+class FunctionDispatch:
+ """
+ FunctionDispatch is similar to functools.singledispatch, but
+ instead dispatches based on functions that take the type of the
+ first argument in the method, and return True or False.
+
+ objects that help determine dispatch should be instantiated objects.
+
+ :param converter: A converter to be used for factories that require converters.
+
+ .. versionchanged:: 24.1.0
+ Support for factories that require converters, hence this requires a
+ converter when creating.
+ """
+
+ _converter: BaseConverter
+ _handler_pairs: list[tuple[Predicate, Callable[[Any, Any], Any], bool, bool]] = (
+ Factory(list)
+ )
+
+ def register(
+ self,
+ predicate: Predicate,
+ func: Callable[..., Any],
+ is_generator=False,
+ takes_converter=False,
+ ) -> None:
+ self._handler_pairs.insert(0, (predicate, func, is_generator, takes_converter))
+
+ def dispatch(self, typ: Any) -> Callable[..., Any] | None:
+ """
+ Return the appropriate handler for the object passed.
+ """
+ for can_handle, handler, is_generator, takes_converter in self._handler_pairs:
+ # can handle could raise an exception here
+ # such as issubclass being called on an instance.
+ # it's easier to just ignore that case.
+ try:
+ ch = can_handle(typ)
+ except Exception: # noqa: S112
+ continue
+ if ch:
+ if is_generator:
+ if takes_converter:
+ return handler(typ, self._converter)
+ return handler(typ)
+
+ return handler
+ return None
+
+ def get_num_fns(self) -> int:
+ return len(self._handler_pairs)
+
+ def copy_to(self, other: FunctionDispatch, skip: int = 0) -> None:
+ other._handler_pairs = self._handler_pairs[:-skip] + other._handler_pairs
+
+
+@define(init=False)
+class MultiStrategyDispatch(Generic[Hook]):
+ """
+ MultiStrategyDispatch uses a combination of exact-match dispatch,
+ singledispatch, and FunctionDispatch.
+
+ :param converter: A converter to be used for factories that require converters.
+ :param fallback_factory: A hook factory to be called when a hook cannot be
+ produced.
+
+ .. versionchanged:: 23.2.0
+ Fallbacks are now factories.
+ .. versionchanged:: 24.1.0
+ Support for factories that require converters, hence this requires a
+ converter when creating.
+ """
+
+ _fallback_factory: HookFactory[Hook]
+ _converter: BaseConverter
+ _direct_dispatch: dict[TargetType, Hook]
+ _function_dispatch: FunctionDispatch
+ _single_dispatch: Any
+ dispatch: Callable[[TargetType, BaseConverter], Hook]
+
+ def __init__(
+ self, fallback_factory: HookFactory[Hook], converter: BaseConverter
+ ) -> None:
+ self._fallback_factory = fallback_factory
+ self._direct_dispatch = {}
+ self._function_dispatch = FunctionDispatch(converter)
+ self._single_dispatch = singledispatch(_DispatchNotFound)
+ self.dispatch = lru_cache(maxsize=None)(self.dispatch_without_caching)
+
+ def dispatch_without_caching(self, typ: TargetType) -> Hook:
+ """Dispatch on the type but without caching the result."""
+ try:
+ dispatch = self._single_dispatch.dispatch(typ)
+ if dispatch is not _DispatchNotFound:
+ return dispatch
+ except Exception: # noqa: S110
+ pass
+
+ direct_dispatch = self._direct_dispatch.get(typ)
+ if direct_dispatch is not None:
+ return direct_dispatch
+
+ res = self._function_dispatch.dispatch(typ)
+ return res if res is not None else self._fallback_factory(typ)
+
+ def register_cls_list(self, cls_and_handler, direct: bool = False) -> None:
+ """Register a class to direct or singledispatch."""
+ for cls, handler in cls_and_handler:
+ if direct:
+ self._direct_dispatch[cls] = handler
+ else:
+ self._single_dispatch.register(cls, handler)
+ self.clear_direct()
+ self.dispatch.cache_clear()
+
+ def register_func_list(
+ self,
+ pred_and_handler: list[
+ tuple[Predicate, Any]
+ | tuple[Predicate, Any, bool]
+ | tuple[Predicate, Callable[[Any, BaseConverter], Any], Literal["extended"]]
+ ],
+ ):
+ """
+ Register a predicate function to determine if the handler
+ should be used for the type.
+
+ :param pred_and_handler: The list of predicates and their associated
+ handlers. If a handler is registered in `extended` mode, it's a
+ factory that requires a converter.
+ """
+ for tup in pred_and_handler:
+ if len(tup) == 2:
+ func, handler = tup
+ self._function_dispatch.register(func, handler)
+ else:
+ func, handler, is_gen = tup
+ if is_gen == "extended":
+ self._function_dispatch.register(
+ func, handler, is_generator=is_gen, takes_converter=True
+ )
+ else:
+ self._function_dispatch.register(func, handler, is_generator=is_gen)
+ self.clear_direct()
+ self.dispatch.cache_clear()
+
+ def clear_direct(self) -> None:
+ """Clear the direct dispatch."""
+ self._direct_dispatch.clear()
+
+ def clear_cache(self) -> None:
+ """Clear all caches."""
+ self._direct_dispatch.clear()
+ self.dispatch.cache_clear()
+
+ def get_num_fns(self) -> int:
+ return self._function_dispatch.get_num_fns()
+
+ def copy_to(self, other: MultiStrategyDispatch, skip: int = 0) -> None:
+ self._function_dispatch.copy_to(other._function_dispatch, skip=skip)
+ for cls, fn in self._single_dispatch.registry.items():
+ other._single_dispatch.register(cls, fn)
+ other.clear_cache()
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/errors.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/errors.py
new file mode 100644
index 0000000..9148bf1
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/errors.py
@@ -0,0 +1,129 @@
+from typing import Any, List, Optional, Set, Tuple, Type, Union
+
+from cattrs._compat import ExceptionGroup
+
+
+class StructureHandlerNotFoundError(Exception):
+ """
+ Error raised when structuring cannot find a handler for converting inputs into
+ :attr:`type_`.
+ """
+
+ def __init__(self, message: str, type_: Type) -> None:
+ super().__init__(message)
+ self.type_ = type_
+
+
+class BaseValidationError(ExceptionGroup):
+ cl: Type
+
+ def __new__(cls, message, excs, cl: Type):
+ obj = super().__new__(cls, message, excs)
+ obj.cl = cl
+ return obj
+
+ def derive(self, excs):
+ return ClassValidationError(self.message, excs, self.cl)
+
+
+class IterableValidationNote(str):
+ """Attached as a note to an exception when an iterable element fails structuring."""
+
+ index: Union[int, str] # Ints for list indices, strs for dict keys
+ type: Any
+
+ def __new__(
+ cls, string: str, index: Union[int, str], type: Any
+ ) -> "IterableValidationNote":
+ instance = str.__new__(cls, string)
+ instance.index = index
+ instance.type = type
+ return instance
+
+ def __getnewargs__(self) -> Tuple[str, Union[int, str], Any]:
+ return (str(self), self.index, self.type)
+
+
+class IterableValidationError(BaseValidationError):
+ """Raised when structuring an iterable."""
+
+ def group_exceptions(
+ self,
+ ) -> Tuple[List[Tuple[Exception, IterableValidationNote]], List[Exception]]:
+ """Split the exceptions into two groups: with and without validation notes."""
+ excs_with_notes = []
+ other_excs = []
+ for subexc in self.exceptions:
+ if hasattr(subexc, "__notes__"):
+ for note in subexc.__notes__:
+ if note.__class__ is IterableValidationNote:
+ excs_with_notes.append((subexc, note))
+ break
+ else:
+ other_excs.append(subexc)
+ else:
+ other_excs.append(subexc)
+
+ return excs_with_notes, other_excs
+
+
+class AttributeValidationNote(str):
+ """Attached as a note to an exception when an attribute fails structuring."""
+
+ name: str
+ type: Any
+
+ def __new__(cls, string: str, name: str, type: Any) -> "AttributeValidationNote":
+ instance = str.__new__(cls, string)
+ instance.name = name
+ instance.type = type
+ return instance
+
+ def __getnewargs__(self) -> Tuple[str, str, Any]:
+ return (str(self), self.name, self.type)
+
+
+class ClassValidationError(BaseValidationError):
+ """Raised when validating a class if any attributes are invalid."""
+
+ def group_exceptions(
+ self,
+ ) -> Tuple[List[Tuple[Exception, AttributeValidationNote]], List[Exception]]:
+ """Split the exceptions into two groups: with and without validation notes."""
+ excs_with_notes = []
+ other_excs = []
+ for subexc in self.exceptions:
+ if hasattr(subexc, "__notes__"):
+ for note in subexc.__notes__:
+ if note.__class__ is AttributeValidationNote:
+ excs_with_notes.append((subexc, note))
+ break
+ else:
+ other_excs.append(subexc)
+ else:
+ other_excs.append(subexc)
+
+ return excs_with_notes, other_excs
+
+
+class ForbiddenExtraKeysError(Exception):
+ """
+ Raised when `forbid_extra_keys` is activated and such extra keys are detected
+ during structuring.
+
+ The attribute `extra_fields` is a sequence of those extra keys, which were the
+ cause of this error, and `cl` is the class which was structured with those extra
+ keys.
+ """
+
+ def __init__(
+ self, message: Optional[str], cl: Type, extra_fields: Set[str]
+ ) -> None:
+ self.cl = cl
+ self.extra_fields = extra_fields
+ cln = cl.__name__
+
+ super().__init__(
+ message
+ or f"Extra fields in constructor for {cln}: {', '.join(extra_fields)}"
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/fns.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/fns.py
new file mode 100644
index 0000000..748cfb3
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/fns.py
@@ -0,0 +1,22 @@
+"""Useful internal functions."""
+
+from typing import Any, Callable, NoReturn, Type, TypeVar
+
+from ._compat import TypeAlias
+from .errors import StructureHandlerNotFoundError
+
+T = TypeVar("T")
+
+Predicate: TypeAlias = Callable[[Any], bool]
+"""A predicate function determines if a type can be handled."""
+
+
+def identity(obj: T) -> T:
+ """The identity function."""
+ return obj
+
+
+def raise_error(_, cl: Type) -> NoReturn:
+ """At the bottom of the condition stack, we explode if we can't handle it."""
+ msg = f"Unsupported type: {cl!r}. Register a structure hook for it."
+ raise StructureHandlerNotFoundError(msg, type_=cl)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/__init__.py
new file mode 100644
index 0000000..97d2876
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/__init__.py
@@ -0,0 +1,1053 @@
+from __future__ import annotations
+
+import re
+from typing import (
+ TYPE_CHECKING,
+ Any,
+ Callable,
+ Final,
+ Iterable,
+ Literal,
+ Mapping,
+ Tuple,
+ TypeVar,
+)
+
+from attrs import NOTHING, Attribute, Factory, resolve_types
+
+from .._compat import (
+ ANIES,
+ TypeAlias,
+ adapted_fields,
+ get_args,
+ get_origin,
+ is_annotated,
+ is_bare,
+ is_bare_final,
+ is_generic,
+)
+from .._generics import deep_copy_with
+from ..dispatch import UnstructureHook
+from ..errors import (
+ AttributeValidationNote,
+ ClassValidationError,
+ ForbiddenExtraKeysError,
+ IterableValidationError,
+ IterableValidationNote,
+ StructureHandlerNotFoundError,
+)
+from ..fns import identity
+from ._consts import AttributeOverride, already_generating, neutral
+from ._generics import generate_mapping
+from ._lc import generate_unique_filename
+from ._shared import find_structure_handler
+
+if TYPE_CHECKING:
+ from ..converters import BaseConverter
+
+__all__ = [
+ "make_dict_unstructure_fn",
+ "make_dict_structure_fn",
+ "make_iterable_unstructure_fn",
+ "make_hetero_tuple_unstructure_fn",
+ "make_mapping_unstructure_fn",
+ "make_mapping_structure_fn",
+ "make_dict_unstructure_fn_from_attrs",
+ "make_dict_structure_fn_from_attrs",
+]
+
+
+def override(
+ omit_if_default: bool | None = None,
+ rename: str | None = None,
+ omit: bool | None = None,
+ struct_hook: Callable[[Any, Any], Any] | None = None,
+ unstruct_hook: Callable[[Any], Any] | None = None,
+) -> AttributeOverride:
+ """Override how a particular field is handled.
+
+ :param omit: Whether to skip the field or not. `None` means apply default handling.
+ """
+ return AttributeOverride(omit_if_default, rename, omit, struct_hook, unstruct_hook)
+
+
+T = TypeVar("T")
+
+
+def make_dict_unstructure_fn_from_attrs(
+ attrs: list[Attribute],
+ cl: type,
+ converter: BaseConverter,
+ typevar_map: dict[str, Any] = {},
+ _cattrs_omit_if_default: bool = False,
+ _cattrs_use_linecache: bool = True,
+ _cattrs_use_alias: bool = False,
+ _cattrs_include_init_false: bool = False,
+ **kwargs: AttributeOverride,
+) -> Callable[[T], dict[str, Any]]:
+ """
+ Generate a specialized dict unstructuring function for a list of attributes.
+
+ Usually used as a building block by more specialized hook factories.
+
+ Any provided overrides are attached to the generated function under the
+ `overrides` attribute.
+
+ :param cl: The class for which the function is generated; used mostly for its name,
+ module name and qualname.
+ :param _cattrs_omit_if_default: if true, attributes equal to their default values
+ will be omitted in the result dictionary.
+ :param _cattrs_use_alias: If true, the attribute alias will be used as the
+ dictionary key by default.
+ :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False`
+ will be included.
+
+ .. versionadded:: 24.1.0
+ """
+
+ fn_name = "unstructure_" + cl.__name__
+ globs = {}
+ lines = []
+ invocation_lines = []
+ internal_arg_parts = {}
+
+ for a in attrs:
+ attr_name = a.name
+ override = kwargs.get(attr_name, neutral)
+ if override.omit:
+ continue
+ if override.omit is None and not a.init and not _cattrs_include_init_false:
+ continue
+ if override.rename is None:
+ kn = attr_name if not _cattrs_use_alias else a.alias
+ else:
+ kn = override.rename
+ d = a.default
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ handler = None
+ if override.unstruct_hook is not None:
+ handler = override.unstruct_hook
+ else:
+ if a.type is not None:
+ t = a.type
+ if isinstance(t, TypeVar):
+ if t.__name__ in typevar_map:
+ t = typevar_map[t.__name__]
+ else:
+ handler = converter.unstructure
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, typevar_map)
+
+ if handler is None:
+ if (
+ is_bare_final(t)
+ and a.default is not NOTHING
+ and not isinstance(a.default, Factory)
+ ):
+ # This is a special case where we can use the
+ # type of the default to dispatch on.
+ t = a.default.__class__
+ try:
+ handler = converter.get_unstructure_hook(t, cache_result=False)
+ except RecursionError:
+ # There's a circular reference somewhere down the line
+ handler = converter.unstructure
+ else:
+ handler = converter.unstructure
+
+ is_identity = handler == identity
+
+ if not is_identity:
+ unstruct_handler_name = f"__c_unstr_{attr_name}"
+ globs[unstruct_handler_name] = handler
+ internal_arg_parts[unstruct_handler_name] = handler
+ invoke = f"{unstruct_handler_name}(instance.{attr_name})"
+ else:
+ invoke = f"instance.{attr_name}"
+
+ if d is not NOTHING and (
+ (_cattrs_omit_if_default and override.omit_if_default is not False)
+ or override.omit_if_default
+ ):
+ def_name = f"__c_def_{attr_name}"
+
+ if isinstance(d, Factory):
+ globs[def_name] = d.factory
+ internal_arg_parts[def_name] = d.factory
+ if d.takes_self:
+ lines.append(f" if instance.{attr_name} != {def_name}(instance):")
+ else:
+ lines.append(f" if instance.{attr_name} != {def_name}():")
+ lines.append(f" res['{kn}'] = {invoke}")
+ else:
+ globs[def_name] = d
+ internal_arg_parts[def_name] = d
+ lines.append(f" if instance.{attr_name} != {def_name}:")
+ lines.append(f" res['{kn}'] = {invoke}")
+
+ else:
+ # No default or no override.
+ invocation_lines.append(f"'{kn}': {invoke},")
+
+ internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts])
+ if internal_arg_line:
+ internal_arg_line = f", {internal_arg_line}"
+ for k, v in internal_arg_parts.items():
+ globs[k] = v
+
+ total_lines = (
+ [f"def {fn_name}(instance{internal_arg_line}):"]
+ + [" res = {"]
+ + [f" {line}" for line in invocation_lines]
+ + [" }"]
+ + lines
+ + [" return res"]
+ )
+ script = "\n".join(total_lines)
+ fname = generate_unique_filename(
+ cl, "unstructure", lines=total_lines if _cattrs_use_linecache else []
+ )
+
+ eval(compile(script, fname, "exec"), globs)
+
+ res = globs[fn_name]
+ res.overrides = kwargs
+
+ return res
+
+
+def make_dict_unstructure_fn(
+ cl: type[T],
+ converter: BaseConverter,
+ _cattrs_omit_if_default: bool = False,
+ _cattrs_use_linecache: bool = True,
+ _cattrs_use_alias: bool = False,
+ _cattrs_include_init_false: bool = False,
+ **kwargs: AttributeOverride,
+) -> Callable[[T], dict[str, Any]]:
+ """
+ Generate a specialized dict unstructuring function for an attrs class or a
+ dataclass.
+
+ Any provided overrides are attached to the generated function under the
+ `overrides` attribute.
+
+ :param _cattrs_omit_if_default: if true, attributes equal to their default values
+ will be omitted in the result dictionary.
+ :param _cattrs_use_alias: If true, the attribute alias will be used as the
+ dictionary key by default.
+ :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False`
+ will be included.
+
+ .. versionadded:: 23.2.0 *_cattrs_use_alias*
+ .. versionadded:: 23.2.0 *_cattrs_include_init_false*
+ """
+ origin = get_origin(cl)
+ attrs = adapted_fields(origin or cl) # type: ignore
+
+ if any(isinstance(a.type, str) for a in attrs):
+ # PEP 563 annotations - need to be resolved.
+ resolve_types(cl)
+
+ mapping = {}
+ if is_generic(cl):
+ mapping = generate_mapping(cl, mapping)
+
+ for base in getattr(origin, "__orig_bases__", ()):
+ if is_generic(base) and not str(base).startswith("typing.Generic"):
+ mapping = generate_mapping(base, mapping)
+ break
+ if origin is not None:
+ cl = origin
+
+ # We keep track of what we're generating to help with recursive
+ # class graphs.
+ try:
+ working_set = already_generating.working_set
+ except AttributeError:
+ working_set = set()
+ already_generating.working_set = working_set
+ if cl in working_set:
+ raise RecursionError()
+
+ working_set.add(cl)
+
+ try:
+ return make_dict_unstructure_fn_from_attrs(
+ attrs,
+ cl,
+ converter,
+ mapping,
+ _cattrs_omit_if_default=_cattrs_omit_if_default,
+ _cattrs_use_linecache=_cattrs_use_linecache,
+ _cattrs_use_alias=_cattrs_use_alias,
+ _cattrs_include_init_false=_cattrs_include_init_false,
+ **kwargs,
+ )
+ finally:
+ working_set.remove(cl)
+ if not working_set:
+ del already_generating.working_set
+
+
+DictStructureFn = Callable[[Mapping[str, Any], Any], T]
+
+
+def make_dict_structure_fn_from_attrs(
+ attrs: list[Attribute],
+ cl: type,
+ converter: BaseConverter,
+ typevar_map: dict[str, Any] = {},
+ _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter",
+ _cattrs_use_linecache: bool = True,
+ _cattrs_prefer_attrib_converters: (
+ bool | Literal["from_converter"]
+ ) = "from_converter",
+ _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter",
+ _cattrs_use_alias: bool = False,
+ _cattrs_include_init_false: bool = False,
+ **kwargs: AttributeOverride,
+) -> DictStructureFn[T]:
+ """
+ Generate a specialized dict structuring function for a list of attributes.
+
+ Usually used as a building block by more specialized hook factories.
+
+ Any provided overrides are attached to the generated function under the
+ `overrides` attribute.
+
+ :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a
+ `ForbiddenExtraKeysError` if unknown keys are encountered.
+ :param _cattrs_use_linecache: Whether to store the source code in the Python
+ linecache.
+ :param _cattrs_prefer_attrib_converters: If an _attrs_ converter is present on a
+ field, use it instead of processing the field normally.
+ :param _cattrs_detailed_validation: Whether to use a slower mode that produces
+ more detailed errors.
+ :param _cattrs_use_alias: If true, the attribute alias will be used as the
+ dictionary key by default.
+ :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False`
+ will be included.
+
+ .. versionadded:: 24.1.0
+ """
+
+ cl_name = cl.__name__
+ fn_name = "structure_" + cl_name
+
+ # We have generic parameters and need to generate a unique name for the function
+ for p in getattr(cl, "__parameters__", ()):
+ # This is nasty, I am not sure how best to handle `typing.List[str]` or
+ # `TClass[int, int]` as a parameter type here
+ try:
+ name_base = typevar_map[p.__name__]
+ except KeyError:
+ pn = p.__name__
+ raise StructureHandlerNotFoundError(
+ f"Missing type for generic argument {pn}, specify it when structuring.",
+ p,
+ ) from None
+ name = getattr(name_base, "__name__", None) or str(name_base)
+ # `<>` can be present in lambdas
+ # `|` can be present in unions
+ name = re.sub(r"[\[\.\] ,<>]", "_", name)
+ name = re.sub(r"\|", "u", name)
+ fn_name += f"_{name}"
+
+ internal_arg_parts = {"__cl": cl}
+ globs = {}
+ lines = []
+ post_lines = []
+ pi_lines = [] # post instantiation lines
+ invocation_lines = []
+
+ allowed_fields = set()
+ if _cattrs_forbid_extra_keys == "from_converter":
+ # BaseConverter doesn't have it so we're careful.
+ _cattrs_forbid_extra_keys = getattr(converter, "forbid_extra_keys", False)
+ if _cattrs_detailed_validation == "from_converter":
+ _cattrs_detailed_validation = converter.detailed_validation
+ if _cattrs_prefer_attrib_converters == "from_converter":
+ _cattrs_prefer_attrib_converters = converter._prefer_attrib_converters
+
+ if _cattrs_forbid_extra_keys:
+ globs["__c_a"] = allowed_fields
+ globs["__c_feke"] = ForbiddenExtraKeysError
+
+ if _cattrs_detailed_validation:
+ lines.append(" res = {}")
+ lines.append(" errors = []")
+ invocation_lines.append("**res,")
+ internal_arg_parts["__c_cve"] = ClassValidationError
+ internal_arg_parts["__c_avn"] = AttributeValidationNote
+ for a in attrs:
+ an = a.name
+ override = kwargs.get(an, neutral)
+ if override.omit:
+ continue
+ if override.omit is None and not a.init and not _cattrs_include_init_false:
+ continue
+ t = a.type
+ if isinstance(t, TypeVar):
+ t = typevar_map.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, typevar_map)
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ if override.struct_hook is not None:
+ # If the user has requested an override, just use that.
+ handler = override.struct_hook
+ else:
+ handler = find_structure_handler(
+ a, t, converter, _cattrs_prefer_attrib_converters
+ )
+
+ struct_handler_name = f"__c_structure_{an}"
+ if handler is not None:
+ internal_arg_parts[struct_handler_name] = handler
+
+ ian = a.alias
+ if override.rename is None:
+ kn = an if not _cattrs_use_alias else a.alias
+ else:
+ kn = override.rename
+
+ allowed_fields.add(kn)
+ i = " "
+
+ if not a.init:
+ if a.default is not NOTHING:
+ pi_lines.append(f"{i}if '{kn}' in o:")
+ i = f"{i} "
+ pi_lines.append(f"{i}try:")
+ i = f"{i} "
+ type_name = f"__c_type_{an}"
+ internal_arg_parts[type_name] = t
+ if handler is not None:
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ pi_lines.append(
+ f"{i}instance.{an} = {struct_handler_name}(o['{kn}'])"
+ )
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ pi_lines.append(
+ f"{i}instance.{an} = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ else:
+ pi_lines.append(f"{i}instance.{an} = o['{kn}']")
+ i = i[:-2]
+ pi_lines.append(f"{i}except Exception as e:")
+ i = f"{i} "
+ pi_lines.append(
+ f'{i}e.__notes__ = getattr(e, \'__notes__\', []) + [__c_avn("Structuring class {cl.__qualname__} @ attribute {an}", "{an}", __c_type_{an})]'
+ )
+ pi_lines.append(f"{i}errors.append(e)")
+
+ else:
+ if a.default is not NOTHING:
+ lines.append(f"{i}if '{kn}' in o:")
+ i = f"{i} "
+ lines.append(f"{i}try:")
+ i = f"{i} "
+ type_name = f"__c_type_{an}"
+ internal_arg_parts[type_name] = t
+ if handler:
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ lines.append(
+ f"{i}res['{ian}'] = {struct_handler_name}(o['{kn}'])"
+ )
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ lines.append(
+ f"{i}res['{ian}'] = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ else:
+ lines.append(f"{i}res['{ian}'] = o['{kn}']")
+ i = i[:-2]
+ lines.append(f"{i}except Exception as e:")
+ i = f"{i} "
+ lines.append(
+ f'{i}e.__notes__ = getattr(e, \'__notes__\', []) + [__c_avn("Structuring class {cl.__qualname__} @ attribute {an}", "{an}", __c_type_{an})]'
+ )
+ lines.append(f"{i}errors.append(e)")
+
+ if _cattrs_forbid_extra_keys:
+ post_lines += [
+ " unknown_fields = set(o.keys()) - __c_a",
+ " if unknown_fields:",
+ " errors.append(__c_feke('', __cl, unknown_fields))",
+ ]
+
+ post_lines.append(
+ f" if errors: raise __c_cve('While structuring ' + {cl_name!r}, errors, __cl)"
+ )
+ if not pi_lines:
+ instantiation_lines = (
+ [" try:"]
+ + [" return __cl("]
+ + [f" {line}" for line in invocation_lines]
+ + [" )"]
+ + [
+ f" except Exception as exc: raise __c_cve('While structuring ' + {cl_name!r}, [exc], __cl)"
+ ]
+ )
+ else:
+ instantiation_lines = (
+ [" try:"]
+ + [" instance = __cl("]
+ + [f" {line}" for line in invocation_lines]
+ + [" )"]
+ + [
+ f" except Exception as exc: raise __c_cve('While structuring ' + {cl_name!r}, [exc], __cl)"
+ ]
+ )
+ pi_lines.append(" return instance")
+ else:
+ non_required = []
+ # The first loop deals with required args.
+ for a in attrs:
+ an = a.name
+ override = kwargs.get(an, neutral)
+ if override.omit:
+ continue
+ if override.omit is None and not a.init and not _cattrs_include_init_false:
+ continue
+ if a.default is not NOTHING:
+ non_required.append(a)
+ continue
+ t = a.type
+ if isinstance(t, TypeVar):
+ t = typevar_map.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, typevar_map)
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ if override.struct_hook is not None:
+ # If the user has requested an override, just use that.
+ handler = override.struct_hook
+ else:
+ handler = find_structure_handler(
+ a, t, converter, _cattrs_prefer_attrib_converters
+ )
+
+ if override.rename is None:
+ kn = an if not _cattrs_use_alias else a.alias
+ else:
+ kn = override.rename
+ allowed_fields.add(kn)
+
+ if not a.init:
+ if handler is not None:
+ struct_handler_name = f"__c_structure_{an}"
+ internal_arg_parts[struct_handler_name] = handler
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ pi_line = f" instance.{an} = {struct_handler_name}(o['{kn}'])"
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ pi_line = (
+ f" instance.{an} = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ else:
+ pi_line = f" instance.{an} = o['{kn}']"
+
+ pi_lines.append(pi_line)
+ else:
+ if handler:
+ struct_handler_name = f"__c_structure_{an}"
+ internal_arg_parts[struct_handler_name] = handler
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ invocation_line = f"{struct_handler_name}(o['{kn}']),"
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ invocation_line = f"{struct_handler_name}(o['{kn}'], {tn}),"
+ else:
+ invocation_line = f"o['{kn}'],"
+
+ if a.kw_only:
+ invocation_line = f"{a.alias}={invocation_line}"
+ invocation_lines.append(invocation_line)
+
+ # The second loop is for optional args.
+ if non_required:
+ invocation_lines.append("**res,")
+ lines.append(" res = {}")
+
+ for a in non_required:
+ an = a.name
+ override = kwargs.get(an, neutral)
+ t = a.type
+ if isinstance(t, TypeVar):
+ t = typevar_map.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, typevar_map)
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ if override.struct_hook is not None:
+ # If the user has requested an override, just use that.
+ handler = override.struct_hook
+ else:
+ handler = find_structure_handler(
+ a, t, converter, _cattrs_prefer_attrib_converters
+ )
+
+ struct_handler_name = f"__c_structure_{an}"
+ internal_arg_parts[struct_handler_name] = handler
+
+ if override.rename is None:
+ kn = an if not _cattrs_use_alias else a.alias
+ else:
+ kn = override.rename
+ allowed_fields.add(kn)
+ if not a.init:
+ pi_lines.append(f" if '{kn}' in o:")
+ if handler:
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ pi_lines.append(
+ f" instance.{an} = {struct_handler_name}(o['{kn}'])"
+ )
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ pi_lines.append(
+ f" instance.{an} = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ else:
+ pi_lines.append(f" instance.{an} = o['{kn}']")
+ else:
+ post_lines.append(f" if '{kn}' in o:")
+ if handler:
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ post_lines.append(
+ f" res['{a.alias}'] = {struct_handler_name}(o['{kn}'])"
+ )
+ else:
+ tn = f"__c_type_{an}"
+ internal_arg_parts[tn] = t
+ post_lines.append(
+ f" res['{a.alias}'] = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ else:
+ post_lines.append(f" res['{a.alias}'] = o['{kn}']")
+ if not pi_lines:
+ instantiation_lines = (
+ [" return __cl("]
+ + [f" {line}" for line in invocation_lines]
+ + [" )"]
+ )
+ else:
+ instantiation_lines = (
+ [" instance = __cl("]
+ + [f" {line}" for line in invocation_lines]
+ + [" )"]
+ )
+ pi_lines.append(" return instance")
+
+ if _cattrs_forbid_extra_keys:
+ post_lines += [
+ " unknown_fields = set(o.keys()) - __c_a",
+ " if unknown_fields:",
+ " raise __c_feke('', __cl, unknown_fields)",
+ ]
+
+ # At the end, we create the function header.
+ internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts])
+ for k, v in internal_arg_parts.items():
+ globs[k] = v
+
+ total_lines = [
+ f"def {fn_name}(o, _, {internal_arg_line}):",
+ *lines,
+ *post_lines,
+ *instantiation_lines,
+ *pi_lines,
+ ]
+
+ script = "\n".join(total_lines)
+ fname = generate_unique_filename(
+ cl, "structure", lines=total_lines if _cattrs_use_linecache else []
+ )
+
+ eval(compile(script, fname, "exec"), globs)
+
+ res = globs[fn_name]
+ res.overrides = kwargs
+
+ return res
+
+
+def make_dict_structure_fn(
+ cl: type[T],
+ converter: BaseConverter,
+ _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter",
+ _cattrs_use_linecache: bool = True,
+ _cattrs_prefer_attrib_converters: (
+ bool | Literal["from_converter"]
+ ) = "from_converter",
+ _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter",
+ _cattrs_use_alias: bool = False,
+ _cattrs_include_init_false: bool = False,
+ **kwargs: AttributeOverride,
+) -> DictStructureFn[T]:
+ """
+ Generate a specialized dict structuring function for an attrs class or
+ dataclass.
+
+ Any provided overrides are attached to the generated function under the
+ `overrides` attribute.
+
+ :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a
+ `ForbiddenExtraKeysError` if unknown keys are encountered.
+ :param _cattrs_use_linecache: Whether to store the source code in the Python
+ linecache.
+ :param _cattrs_prefer_attrib_converters: If an _attrs_ converter is present on a
+ field, use it instead of processing the field normally.
+ :param _cattrs_detailed_validation: Whether to use a slower mode that produces
+ more detailed errors.
+ :param _cattrs_use_alias: If true, the attribute alias will be used as the
+ dictionary key by default.
+ :param _cattrs_include_init_false: If true, _attrs_ fields marked as `init=False`
+ will be included.
+
+ .. versionadded:: 23.2.0 *_cattrs_use_alias*
+ .. versionadded:: 23.2.0 *_cattrs_include_init_false*
+ .. versionchanged:: 23.2.0
+ The `_cattrs_forbid_extra_keys` and `_cattrs_detailed_validation` parameters
+ take their values from the given converter by default.
+ .. versionchanged:: 24.1.0
+ The `_cattrs_prefer_attrib_converters` parameter takes its value from the given
+ converter by default.
+ """
+
+ mapping = {}
+ if is_generic(cl):
+ base = get_origin(cl)
+ mapping = generate_mapping(cl, mapping)
+ if base is not None:
+ cl = base
+
+ for base in getattr(cl, "__orig_bases__", ()):
+ if is_generic(base) and not str(base).startswith("typing.Generic"):
+ mapping = generate_mapping(base, mapping)
+ break
+
+ attrs = adapted_fields(cl)
+
+ if any(isinstance(a.type, str) for a in attrs):
+ # PEP 563 annotations - need to be resolved.
+ resolve_types(cl)
+
+ # We keep track of what we're generating to help with recursive
+ # class graphs.
+ try:
+ working_set = already_generating.working_set
+ except AttributeError:
+ working_set = set()
+ already_generating.working_set = working_set
+ else:
+ if cl in working_set:
+ raise RecursionError()
+
+ working_set.add(cl)
+
+ try:
+ return make_dict_structure_fn_from_attrs(
+ attrs,
+ cl,
+ converter,
+ mapping,
+ _cattrs_forbid_extra_keys=_cattrs_forbid_extra_keys,
+ _cattrs_use_linecache=_cattrs_use_linecache,
+ _cattrs_prefer_attrib_converters=_cattrs_prefer_attrib_converters,
+ _cattrs_detailed_validation=_cattrs_detailed_validation,
+ _cattrs_use_alias=_cattrs_use_alias,
+ _cattrs_include_init_false=_cattrs_include_init_false,
+ **kwargs,
+ )
+ finally:
+ working_set.remove(cl)
+ if not working_set:
+ del already_generating.working_set
+
+
+IterableUnstructureFn = Callable[[Iterable[Any]], Any]
+
+
+#: A type alias for heterogeneous tuple unstructure hooks.
+HeteroTupleUnstructureFn: TypeAlias = Callable[[Tuple[Any, ...]], Any]
+
+
+def make_hetero_tuple_unstructure_fn(
+ cl: Any,
+ converter: BaseConverter,
+ unstructure_to: Any = None,
+ type_args: tuple | None = None,
+) -> HeteroTupleUnstructureFn:
+ """Generate a specialized unstructure function for a heterogenous tuple.
+
+ :param type_args: If provided, override the type arguments.
+ """
+ fn_name = "unstructure_tuple"
+
+ type_args = get_args(cl) if type_args is None else type_args
+
+ # We can do the dispatch here and now.
+ handlers = [converter.get_unstructure_hook(type_arg) for type_arg in type_args]
+
+ globs = {f"__cattr_u_{i}": h for i, h in enumerate(handlers)}
+ if unstructure_to is not tuple:
+ globs["__cattr_seq_cl"] = unstructure_to or cl
+ lines = []
+
+ lines.append(f"def {fn_name}(tup):")
+ if unstructure_to is not tuple:
+ lines.append(" res = __cattr_seq_cl((")
+ else:
+ lines.append(" res = (")
+ for i in range(len(handlers)):
+ if handlers[i] == identity:
+ lines.append(f" tup[{i}],")
+ else:
+ lines.append(f" __cattr_u_{i}(tup[{i}]),")
+
+ if unstructure_to is not tuple:
+ lines.append(" ))")
+ else:
+ lines.append(" )")
+
+ total_lines = [*lines, " return res"]
+
+ eval(compile("\n".join(total_lines), "", "exec"), globs)
+
+ return globs[fn_name]
+
+
+MappingUnstructureFn = Callable[[Mapping[Any, Any]], Any]
+
+
+def make_mapping_unstructure_fn(
+ cl: Any,
+ converter: BaseConverter,
+ unstructure_to: Any = None,
+ key_handler: Callable[[Any, Any | None], Any] | None = None,
+) -> MappingUnstructureFn:
+ """Generate a specialized unstructure function for a mapping."""
+ kh = key_handler or converter.unstructure
+ val_handler = converter.unstructure
+
+ fn_name = "unstructure_mapping"
+
+ # Let's try fishing out the type args.
+ if getattr(cl, "__args__", None) is not None:
+ args = get_args(cl)
+ if len(args) == 2:
+ key_arg, val_arg = args
+ else:
+ # Probably a Counter
+ key_arg, val_arg = args, Any
+ # We can do the dispatch here and now.
+ kh = key_handler or converter.get_unstructure_hook(key_arg, cache_result=False)
+ if kh == identity:
+ kh = None
+
+ val_handler = converter.get_unstructure_hook(val_arg, cache_result=False)
+ if val_handler == identity:
+ val_handler = None
+
+ globs = {
+ "__cattr_mapping_cl": unstructure_to or cl,
+ "__cattr_k_u": kh,
+ "__cattr_v_u": val_handler,
+ }
+
+ k_u = "__cattr_k_u(k)" if kh is not None else "k"
+ v_u = "__cattr_v_u(v)" if val_handler is not None else "v"
+
+ lines = []
+
+ lines.append(f"def {fn_name}(mapping):")
+ lines.append(
+ f" res = __cattr_mapping_cl(({k_u}, {v_u}) for k, v in mapping.items())"
+ )
+
+ total_lines = [*lines, " return res"]
+
+ eval(compile("\n".join(total_lines), "", "exec"), globs)
+
+ return globs[fn_name]
+
+
+MappingStructureFn = Callable[[Mapping[Any, Any], Any], T]
+
+
+# This factory is here for backwards compatibility and circular imports.
+def mapping_structure_factory(
+ cl: type[T],
+ converter: BaseConverter,
+ structure_to: type = dict,
+ key_type=NOTHING,
+ val_type=NOTHING,
+ detailed_validation: bool = True,
+) -> MappingStructureFn[T]:
+ """Generate a specialized structure function for a mapping."""
+ fn_name = "structure_mapping"
+
+ globs: dict[str, type] = {"__cattr_mapping_cl": structure_to}
+
+ lines = []
+ internal_arg_parts = {}
+
+ # Let's try fishing out the type args.
+ if not is_bare(cl):
+ args = get_args(cl)
+ if len(args) == 2:
+ key_arg_cand, val_arg_cand = args
+ if key_type is NOTHING:
+ key_type = key_arg_cand
+ if val_type is NOTHING:
+ val_type = val_arg_cand
+ else:
+ if key_type is not NOTHING and val_type is NOTHING:
+ (val_type,) = args
+ elif key_type is NOTHING and val_type is not NOTHING:
+ (key_type,) = args
+ else:
+ # Probably a Counter
+ (key_type,) = args
+ val_type = Any
+
+ is_bare_dict = val_type in ANIES and key_type in ANIES
+ if not is_bare_dict:
+ # We can do the dispatch here and now.
+ key_handler = converter.get_structure_hook(key_type, cache_result=False)
+ if key_handler == converter._structure_call:
+ key_handler = key_type
+
+ val_handler = converter.get_structure_hook(val_type, cache_result=False)
+ if val_handler == converter._structure_call:
+ val_handler = val_type
+
+ globs["__cattr_k_t"] = key_type
+ globs["__cattr_v_t"] = val_type
+ globs["__cattr_k_s"] = key_handler
+ globs["__cattr_v_s"] = val_handler
+ k_s = (
+ "__cattr_k_s(k, __cattr_k_t)"
+ if key_handler != key_type
+ else "__cattr_k_s(k)"
+ )
+ v_s = (
+ "__cattr_v_s(v, __cattr_v_t)"
+ if val_handler != val_type
+ else "__cattr_v_s(v)"
+ )
+ else:
+ is_bare_dict = True
+
+ if is_bare_dict:
+ # No args, it's a bare dict.
+ lines.append(" res = dict(mapping)")
+ else:
+ if detailed_validation:
+ internal_arg_parts["IterableValidationError"] = IterableValidationError
+ internal_arg_parts["IterableValidationNote"] = IterableValidationNote
+ internal_arg_parts["val_type"] = (
+ val_type if val_type is not NOTHING else Any
+ )
+ internal_arg_parts["key_type"] = (
+ key_type if key_type is not NOTHING else Any
+ )
+ globs["enumerate"] = enumerate
+
+ lines.append(" res = {}; errors = []")
+ lines.append(" for k, v in mapping.items():")
+ lines.append(" try:")
+ lines.append(f" value = {v_s}")
+ lines.append(" except Exception as e:")
+ lines.append(
+ " e.__notes__ = getattr(e, '__notes__', []) + [IterableValidationNote(f'Structuring mapping value @ key {k!r}', k, val_type)]"
+ )
+ lines.append(" errors.append(e)")
+ lines.append(" continue")
+ lines.append(" try:")
+ lines.append(f" key = {k_s}")
+ lines.append(" res[key] = value")
+ lines.append(" except Exception as e:")
+ lines.append(
+ " e.__notes__ = getattr(e, '__notes__', []) + [IterableValidationNote(f'Structuring mapping key @ key {k!r}', k, key_type)]"
+ )
+ lines.append(" errors.append(e)")
+ lines.append(" if errors:")
+ lines.append(
+ f" raise IterableValidationError('While structuring ' + {repr(cl)!r}, errors, __cattr_mapping_cl)"
+ )
+ else:
+ lines.append(f" res = {{{k_s}: {v_s} for k, v in mapping.items()}}")
+ if structure_to is not dict:
+ lines.append(" res = __cattr_mapping_cl(res)")
+
+ internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts])
+ if internal_arg_line:
+ internal_arg_line = f", {internal_arg_line}"
+ for k, v in internal_arg_parts.items():
+ globs[k] = v
+
+ def_line = f"def {fn_name}(mapping, _{internal_arg_line}):"
+ total_lines = [def_line, *lines, " return res"]
+ script = "\n".join(total_lines)
+
+ eval(compile(script, "", "exec"), globs)
+
+ return globs[fn_name]
+
+
+make_mapping_structure_fn: Final = mapping_structure_factory
+
+
+# This factory is here for backwards compatibility and circular imports.
+def iterable_unstructure_factory(
+ cl: Any, converter: BaseConverter, unstructure_to: Any = None
+) -> UnstructureHook:
+ """A hook factory for unstructuring iterables.
+
+ :param unstructure_to: Force unstructuring to this type, if provided.
+ """
+ handler = converter.unstructure
+
+ # Let's try fishing out the type args
+ # Unspecified tuples have `__args__` as empty tuples, so guard
+ # against IndexError.
+ if getattr(cl, "__args__", None) not in (None, ()):
+ type_arg = cl.__args__[0]
+ if isinstance(type_arg, TypeVar):
+ type_arg = getattr(type_arg, "__default__", Any)
+ handler = converter.get_unstructure_hook(type_arg, cache_result=False)
+ if handler == identity:
+ # Save ourselves the trouble of iterating over it all.
+ return unstructure_to or cl
+
+ def unstructure_iterable(iterable, _seq_cl=unstructure_to or cl, _hook=handler):
+ return _seq_cl(_hook(i) for i in iterable)
+
+ return unstructure_iterable
+
+
+make_iterable_unstructure_fn: Final = iterable_unstructure_factory
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_consts.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_consts.py
new file mode 100644
index 0000000..a6dcd03
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_consts.py
@@ -0,0 +1,19 @@
+from __future__ import annotations
+
+from threading import local
+from typing import Any, Callable
+
+from attrs import frozen
+
+
+@frozen
+class AttributeOverride:
+ omit_if_default: bool | None = None
+ rename: str | None = None
+ omit: bool | None = None # Omit the field completely.
+ struct_hook: Callable[[Any, Any], Any] | None = None # Structure hook to use.
+ unstruct_hook: Callable[[Any], Any] | None = None # Structure hook to use.
+
+
+neutral = AttributeOverride()
+already_generating = local()
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_generics.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_generics.py
new file mode 100644
index 0000000..069c48c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_generics.py
@@ -0,0 +1,79 @@
+from __future__ import annotations
+
+from typing import TypeVar
+
+from .._compat import get_args, get_origin, is_generic
+
+
+def _tvar_has_default(tvar) -> bool:
+ """Does `tvar` have a default?
+
+ In CPython 3.13+ and typing_extensions>=4.12.0:
+ - TypeVars have a `no_default()` method for detecting
+ if a TypeVar has a default
+ - TypeVars with `default=None` have `__default__` set to `None`
+ - TypeVars with no `default` parameter passed
+ have `__default__` set to `typing(_extensions).NoDefault
+
+ On typing_exensions<4.12.0:
+ - TypeVars do not have a `no_default()` method for detecting
+ if a TypeVar has a default
+ - TypeVars with `default=None` have `__default__` set to `NoneType`
+ - TypeVars with no `default` parameter passed
+ have `__default__` set to `typing(_extensions).NoDefault
+ """
+ try:
+ return tvar.has_default()
+ except AttributeError:
+ # compatibility for typing_extensions<4.12.0
+ return getattr(tvar, "__default__", None) is not None
+
+
+def generate_mapping(cl: type, old_mapping: dict[str, type] = {}) -> dict[str, type]:
+ """Generate a mapping of typevars to actual types for a generic class."""
+ mapping = dict(old_mapping)
+
+ origin = get_origin(cl)
+
+ if origin is not None:
+ # To handle the cases where classes in the typing module are using
+ # the GenericAlias structure but aren't a Generic and hence
+ # end up in this function but do not have an `__parameters__`
+ # attribute. These classes are interface types, for example
+ # `typing.Hashable`.
+ parameters = getattr(get_origin(cl), "__parameters__", None)
+ if parameters is None:
+ return dict(old_mapping)
+
+ for p, t in zip(parameters, get_args(cl)):
+ if isinstance(t, TypeVar):
+ continue
+ mapping[p.__name__] = t
+
+ elif is_generic(cl):
+ # Origin is None, so this may be a subclass of a generic class.
+ orig_bases = cl.__orig_bases__
+ for base in orig_bases:
+ if not hasattr(base, "__args__"):
+ continue
+ base_args = base.__args__
+ if hasattr(base.__origin__, "__parameters__"):
+ base_params = base.__origin__.__parameters__
+ elif any(_tvar_has_default(base_arg) for base_arg in base_args):
+ # TypeVar with a default e.g. PEP 696
+ # https://www.python.org/dev/peps/pep-0696/
+ # Extract the defaults for the TypeVars and insert
+ # them into the mapping
+ mapping_params = [
+ (base_arg, base_arg.__default__)
+ for base_arg in base_args
+ if _tvar_has_default(base_arg)
+ ]
+ base_params, base_args = zip(*mapping_params)
+ else:
+ continue
+
+ for param, arg in zip(base_params, base_args):
+ mapping[param.__name__] = arg
+
+ return mapping
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_lc.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_lc.py
new file mode 100644
index 0000000..04843cd
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_lc.py
@@ -0,0 +1,29 @@
+"""Line-cache functionality."""
+
+import linecache
+from typing import List
+
+
+def generate_unique_filename(cls: type, func_name: str, lines: List[str] = []) -> str:
+ """
+ Create a "filename" suitable for a function being generated.
+
+ If *lines* are provided, insert them in the first free spot or stop
+ if a duplicate is found.
+ """
+ extra = ""
+ count = 1
+
+ while True:
+ unique_filename = "".format(
+ func_name, cls.__module__, getattr(cls, "__qualname__", cls.__name__), extra
+ )
+ if not lines:
+ return unique_filename
+ cache_line = (len("\n".join(lines)), None, lines, unique_filename)
+ if linecache.cache.setdefault(unique_filename, cache_line) == cache_line:
+ return unique_filename
+
+ # Looks like this spot is taken. Try again.
+ count += 1
+ extra = f"-{count}"
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_shared.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_shared.py
new file mode 100644
index 0000000..4e63143
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/_shared.py
@@ -0,0 +1,58 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any
+
+from attrs import NOTHING, Attribute, Factory
+
+from .._compat import is_bare_final
+from ..dispatch import StructureHook
+from ..fns import raise_error
+
+if TYPE_CHECKING:
+ from ..converters import BaseConverter
+
+
+def find_structure_handler(
+ a: Attribute, type: Any, c: BaseConverter, prefer_attrs_converters: bool = False
+) -> StructureHook | None:
+ """Find the appropriate structure handler to use.
+
+ Return `None` if no handler should be used.
+ """
+ try:
+ if a.converter is not None and prefer_attrs_converters:
+ # If the user as requested to use attrib converters, use nothing
+ # so it falls back to that.
+ handler = None
+ elif (
+ a.converter is not None and not prefer_attrs_converters and type is not None
+ ):
+ handler = c.get_structure_hook(type, cache_result=False)
+ if handler == raise_error:
+ handler = None
+ elif type is not None:
+ if (
+ is_bare_final(type)
+ and a.default is not NOTHING
+ and not isinstance(a.default, Factory)
+ ):
+ # This is a special case where we can use the
+ # type of the default to dispatch on.
+ type = a.default.__class__
+ handler = c.get_structure_hook(type, cache_result=False)
+ if handler == c._structure_call:
+ # Finals can't really be used with _structure_call, so
+ # we wrap it so the rest of the toolchain doesn't get
+ # confused.
+
+ def handler(v, _, _h=handler):
+ return _h(v, type)
+
+ else:
+ handler = c.get_structure_hook(type, cache_result=False)
+ else:
+ handler = c.structure
+ return handler
+ except RecursionError:
+ # This means we're dealing with a reference cycle, so use late binding.
+ return c.structure
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/typeddicts.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/typeddicts.py
new file mode 100644
index 0000000..5614d6f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/gen/typeddicts.py
@@ -0,0 +1,611 @@
+from __future__ import annotations
+
+import re
+import sys
+from typing import TYPE_CHECKING, Any, Callable, Literal, TypeVar
+
+from attrs import NOTHING, Attribute
+
+try:
+ from inspect import get_annotations
+
+ def get_annots(cl) -> dict[str, Any]:
+ return get_annotations(cl, eval_str=True)
+
+except ImportError:
+ # https://docs.python.org/3/howto/annotations.html#accessing-the-annotations-dict-of-an-object-in-python-3-9-and-older
+ def get_annots(cl) -> dict[str, Any]:
+ if isinstance(cl, type):
+ ann = cl.__dict__.get("__annotations__", {})
+ else:
+ ann = getattr(cl, "__annotations__", {})
+ return ann
+
+
+try:
+ from typing_extensions import _TypedDictMeta
+except ImportError:
+ _TypedDictMeta = None
+
+from .._compat import (
+ TypedDict,
+ get_full_type_hints,
+ get_notrequired_base,
+ get_origin,
+ is_annotated,
+ is_bare,
+ is_generic,
+)
+from .._generics import deep_copy_with
+from ..errors import (
+ AttributeValidationNote,
+ ClassValidationError,
+ ForbiddenExtraKeysError,
+ StructureHandlerNotFoundError,
+)
+from ..fns import identity
+from . import AttributeOverride
+from ._consts import already_generating, neutral
+from ._generics import generate_mapping
+from ._lc import generate_unique_filename
+from ._shared import find_structure_handler
+
+if TYPE_CHECKING:
+ from ..converters import BaseConverter
+
+__all__ = ["make_dict_unstructure_fn", "make_dict_structure_fn"]
+
+T = TypeVar("T", bound=TypedDict)
+
+
+def make_dict_unstructure_fn(
+ cl: type[T],
+ converter: BaseConverter,
+ _cattrs_use_linecache: bool = True,
+ **kwargs: AttributeOverride,
+) -> Callable[[T], dict[str, Any]]:
+ """
+ Generate a specialized dict unstructuring function for a TypedDict.
+
+ :param cl: A `TypedDict` class.
+ :param converter: A Converter instance to use for unstructuring nested fields.
+ :param kwargs: A mapping of field names to an `AttributeOverride`, for
+ customization.
+ :param _cattrs_detailed_validation: Whether to store the generated code in the
+ _linecache_, for easier debugging and better stack traces.
+ """
+ origin = get_origin(cl)
+ attrs = _adapted_fields(origin or cl) # type: ignore
+ req_keys = _required_keys(origin or cl)
+
+ mapping = {}
+ if is_generic(cl):
+ mapping = generate_mapping(cl, mapping)
+
+ for base in getattr(origin, "__orig_bases__", ()):
+ if is_generic(base) and not str(base).startswith("typing.Generic"):
+ mapping = generate_mapping(base, mapping)
+ break
+
+ # It's possible for origin to be None if this is a subclass
+ # of a generic class.
+ if origin is not None:
+ cl = origin
+
+ cl_name = cl.__name__
+ fn_name = "unstructure_typeddict_" + cl_name
+ globs = {}
+ lines = []
+ internal_arg_parts = {}
+
+ # We keep track of what we're generating to help with recursive
+ # class graphs.
+ try:
+ working_set = already_generating.working_set
+ except AttributeError:
+ working_set = set()
+ already_generating.working_set = working_set
+ if cl in working_set:
+ raise RecursionError()
+ working_set.add(cl)
+
+ try:
+ # We want to short-circuit in certain cases and return the identity
+ # function.
+ # We short-circuit if all of these are true:
+ # * no attributes have been overridden
+ # * all attributes resolve to `converter._unstructure_identity`
+ for a in attrs:
+ attr_name = a.name
+ override = kwargs.get(attr_name, neutral)
+ if override != neutral:
+ break
+ handler = None
+ t = a.type
+
+ if isinstance(t, TypeVar):
+ if t.__name__ in mapping:
+ t = mapping[t.__name__]
+ else:
+ # Unbound typevars use late binding.
+ handler = converter.unstructure
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ if handler is None:
+ nrb = get_notrequired_base(t)
+ if nrb is not NOTHING:
+ t = nrb
+ try:
+ handler = converter.get_unstructure_hook(t)
+ except RecursionError:
+ # There's a circular reference somewhere down the line
+ handler = converter.unstructure
+ is_identity = handler == identity
+ if not is_identity:
+ break
+ else:
+ # We've not broken the loop.
+ return identity
+
+ for ix, a in enumerate(attrs):
+ attr_name = a.name
+ override = kwargs.get(attr_name, neutral)
+ if override.omit:
+ lines.append(f" res.pop('{attr_name}', None)")
+ continue
+ if override.rename is not None:
+ # We also need to pop when renaming, since we're copying
+ # the original.
+ lines.append(f" res.pop('{attr_name}', None)")
+ kn = attr_name if override.rename is None else override.rename
+ attr_required = attr_name in req_keys
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ handler = None
+ if override.unstruct_hook is not None:
+ handler = override.unstruct_hook
+ else:
+ t = a.type
+
+ if isinstance(t, TypeVar):
+ if t.__name__ in mapping:
+ t = mapping[t.__name__]
+ else:
+ handler = converter.unstructure
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ if handler is None:
+ nrb = get_notrequired_base(t)
+ if nrb is not NOTHING:
+ t = nrb
+ try:
+ handler = converter.get_unstructure_hook(t)
+ except RecursionError:
+ # There's a circular reference somewhere down the line
+ handler = converter.unstructure
+
+ is_identity = handler == identity
+
+ if not is_identity:
+ unstruct_handler_name = f"__c_unstr_{ix}"
+ globs[unstruct_handler_name] = handler
+ internal_arg_parts[unstruct_handler_name] = handler
+ invoke = f"{unstruct_handler_name}(instance['{attr_name}'])"
+ elif override.rename is None:
+ # We're not doing anything to this attribute, so
+ # it'll already be present in the input dict.
+ continue
+ else:
+ # Probably renamed, we just fetch it.
+ invoke = f"instance['{attr_name}']"
+
+ if attr_required:
+ # No default or no override.
+ lines.append(f" res['{kn}'] = {invoke}")
+ else:
+ lines.append(f" if '{attr_name}' in instance: res['{kn}'] = {invoke}")
+
+ internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts])
+ if internal_arg_line:
+ internal_arg_line = f", {internal_arg_line}"
+ for k, v in internal_arg_parts.items():
+ globs[k] = v
+
+ total_lines = [
+ f"def {fn_name}(instance{internal_arg_line}):",
+ " res = instance.copy()",
+ *lines,
+ " return res",
+ ]
+ script = "\n".join(total_lines)
+
+ fname = generate_unique_filename(
+ cl, "unstructure", lines=total_lines if _cattrs_use_linecache else []
+ )
+
+ eval(compile(script, fname, "exec"), globs)
+ finally:
+ working_set.remove(cl)
+ if not working_set:
+ del already_generating.working_set
+
+ return globs[fn_name]
+
+
+def make_dict_structure_fn(
+ cl: Any,
+ converter: BaseConverter,
+ _cattrs_forbid_extra_keys: bool | Literal["from_converter"] = "from_converter",
+ _cattrs_use_linecache: bool = True,
+ _cattrs_detailed_validation: bool | Literal["from_converter"] = "from_converter",
+ **kwargs: AttributeOverride,
+) -> Callable[[dict, Any], Any]:
+ """Generate a specialized dict structuring function for typed dicts.
+
+ :param cl: A `TypedDict` class.
+ :param converter: A Converter instance to use for structuring nested fields.
+ :param kwargs: A mapping of field names to an `AttributeOverride`, for
+ customization.
+ :param _cattrs_detailed_validation: Whether to use a slower mode that produces
+ more detailed errors.
+ :param _cattrs_forbid_extra_keys: Whether the structuring function should raise a
+ `ForbiddenExtraKeysError` if unknown keys are encountered.
+ :param _cattrs_detailed_validation: Whether to store the generated code in the
+ _linecache_, for easier debugging and better stack traces.
+
+ .. versionchanged:: 23.2.0
+ The `_cattrs_forbid_extra_keys` and `_cattrs_detailed_validation` parameters
+ take their values from the given converter by default.
+ """
+
+ mapping = {}
+ if is_generic(cl):
+ base = get_origin(cl)
+ mapping = generate_mapping(cl, mapping)
+ if base is not None:
+ # It's possible for this to be a subclass of a generic,
+ # so no origin.
+ cl = base
+
+ for base in getattr(cl, "__orig_bases__", ()):
+ if is_generic(base) and not str(base).startswith("typing.Generic"):
+ mapping = generate_mapping(base, mapping)
+ break
+
+ cl_name = cl.__name__
+ fn_name = "structure_" + cl_name
+
+ # We have generic parameters and need to generate a unique name for the function
+ for p in getattr(cl, "__parameters__", ()):
+ try:
+ name_base = mapping[p.__name__]
+ except KeyError:
+ pn = p.__name__
+ raise StructureHandlerNotFoundError(
+ f"Missing type for generic argument {pn}, specify it when structuring.",
+ p,
+ ) from None
+ name = getattr(name_base, "__name__", None) or str(name_base)
+ # `<>` can be present in lambdas
+ # `|` can be present in unions
+ name = re.sub(r"[\[\.\] ,<>]", "_", name)
+ name = re.sub(r"\|", "u", name)
+ fn_name += f"_{name}"
+
+ internal_arg_parts = {"__cl": cl}
+ globs = {}
+ lines = []
+ post_lines = []
+
+ attrs = _adapted_fields(cl)
+ req_keys = _required_keys(cl)
+
+ allowed_fields = set()
+ if _cattrs_forbid_extra_keys == "from_converter":
+ # BaseConverter doesn't have it so we're careful.
+ _cattrs_forbid_extra_keys = getattr(converter, "forbid_extra_keys", False)
+ if _cattrs_detailed_validation == "from_converter":
+ _cattrs_detailed_validation = converter.detailed_validation
+
+ if _cattrs_forbid_extra_keys:
+ globs["__c_a"] = allowed_fields
+ globs["__c_feke"] = ForbiddenExtraKeysError
+
+ lines.append(" res = o.copy()")
+
+ if _cattrs_detailed_validation:
+ lines.append(" errors = []")
+ internal_arg_parts["__c_cve"] = ClassValidationError
+ internal_arg_parts["__c_avn"] = AttributeValidationNote
+ for ix, a in enumerate(attrs):
+ an = a.name
+ attr_required = an in req_keys
+ override = kwargs.get(an, neutral)
+ if override.omit:
+ continue
+ t = a.type
+
+ if isinstance(t, TypeVar):
+ t = mapping.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ nrb = get_notrequired_base(t)
+ if nrb is not NOTHING:
+ t = nrb
+
+ if is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ if override.struct_hook is not None:
+ # If the user has requested an override, just use that.
+ handler = override.struct_hook
+ else:
+ handler = find_structure_handler(a, t, converter)
+
+ struct_handler_name = f"__c_structure_{ix}"
+ internal_arg_parts[struct_handler_name] = handler
+
+ kn = an if override.rename is None else override.rename
+ allowed_fields.add(kn)
+ i = " "
+ if not attr_required:
+ lines.append(f"{i}if '{kn}' in o:")
+ i = f"{i} "
+ lines.append(f"{i}try:")
+ i = f"{i} "
+
+ tn = f"__c_type_{ix}"
+ internal_arg_parts[tn] = t
+
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ lines.append(f"{i}res['{an}'] = {struct_handler_name}(o['{kn}'])")
+ else:
+ lines.append(f"{i}res['{an}'] = {struct_handler_name}(o['{kn}'], {tn})")
+ if override.rename is not None:
+ lines.append(f"{i}del res['{kn}']")
+ i = i[:-2]
+ lines.append(f"{i}except Exception as e:")
+ i = f"{i} "
+ lines.append(
+ f'{i}e.__notes__ = [*getattr(e, \'__notes__\', []), __c_avn("Structuring typeddict {cl.__qualname__} @ attribute {an}", "{an}", {tn})]'
+ )
+ lines.append(f"{i}errors.append(e)")
+
+ if _cattrs_forbid_extra_keys:
+ post_lines += [
+ " unknown_fields = o.keys() - __c_a",
+ " if unknown_fields:",
+ " errors.append(__c_feke('', __cl, unknown_fields))",
+ ]
+
+ post_lines.append(
+ f" if errors: raise __c_cve('While structuring ' + {cl.__name__!r}, errors, __cl)"
+ )
+ else:
+ non_required = []
+
+ # The first loop deals with required args.
+ for ix, a in enumerate(attrs):
+ an = a.name
+ attr_required = an in req_keys
+ override = kwargs.get(an, neutral)
+ if override.omit:
+ continue
+ if not attr_required:
+ non_required.append((ix, a))
+ continue
+
+ t = a.type
+
+ if isinstance(t, TypeVar):
+ t = mapping.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ nrb = get_notrequired_base(t)
+ if nrb is not NOTHING:
+ t = nrb
+
+ if override.struct_hook is not None:
+ handler = override.struct_hook
+ else:
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ handler = converter.get_structure_hook(t)
+
+ kn = an if override.rename is None else override.rename
+ allowed_fields.add(kn)
+
+ struct_handler_name = f"__c_structure_{ix}"
+ internal_arg_parts[struct_handler_name] = handler
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ invocation_line = f" res['{an}'] = {struct_handler_name}(o['{kn}'])"
+ else:
+ tn = f"__c_type_{ix}"
+ internal_arg_parts[tn] = t
+ invocation_line = (
+ f" res['{an}'] = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+
+ lines.append(invocation_line)
+ if override.rename is not None:
+ lines.append(f" del res['{override.rename}']")
+
+ # The second loop is for optional args.
+ if non_required:
+ for ix, a in non_required:
+ an = a.name
+ override = kwargs.get(an, neutral)
+ t = a.type
+
+ nrb = get_notrequired_base(t)
+ if nrb is not NOTHING:
+ t = nrb
+
+ if isinstance(t, TypeVar):
+ t = mapping.get(t.__name__, t)
+ elif is_generic(t) and not is_bare(t) and not is_annotated(t):
+ t = deep_copy_with(t, mapping)
+
+ if override.struct_hook is not None:
+ handler = override.struct_hook
+ else:
+ # For each attribute, we try resolving the type here and now.
+ # If a type is manually overwritten, this function should be
+ # regenerated.
+ handler = converter.get_structure_hook(t)
+
+ struct_handler_name = f"__c_structure_{ix}"
+ internal_arg_parts[struct_handler_name] = handler
+
+ ian = an
+ kn = an if override.rename is None else override.rename
+ allowed_fields.add(kn)
+ post_lines.append(f" if '{kn}' in o:")
+ if handler == converter._structure_call:
+ internal_arg_parts[struct_handler_name] = t
+ post_lines.append(
+ f" res['{ian}'] = {struct_handler_name}(o['{kn}'])"
+ )
+ else:
+ tn = f"__c_type_{ix}"
+ internal_arg_parts[tn] = t
+ post_lines.append(
+ f" res['{ian}'] = {struct_handler_name}(o['{kn}'], {tn})"
+ )
+ if override.rename is not None:
+ lines.append(f" res.pop('{override.rename}', None)")
+
+ if _cattrs_forbid_extra_keys:
+ post_lines += [
+ " unknown_fields = o.keys() - __c_a",
+ " if unknown_fields:",
+ " raise __c_feke('', __cl, unknown_fields)",
+ ]
+
+ # At the end, we create the function header.
+ internal_arg_line = ", ".join([f"{i}={i}" for i in internal_arg_parts])
+ for k, v in internal_arg_parts.items():
+ globs[k] = v
+
+ total_lines = [
+ f"def {fn_name}(o, _, {internal_arg_line}):",
+ *lines,
+ *post_lines,
+ " return res",
+ ]
+
+ script = "\n".join(total_lines)
+ fname = generate_unique_filename(
+ cl, "structure", lines=total_lines if _cattrs_use_linecache else []
+ )
+
+ eval(compile(script, fname, "exec"), globs)
+ return globs[fn_name]
+
+
+def _adapted_fields(cls: Any) -> list[Attribute]:
+ annotations = get_annots(cls)
+ hints = get_full_type_hints(cls)
+ return [
+ Attribute(
+ n,
+ NOTHING,
+ None,
+ False,
+ False,
+ False,
+ False,
+ False,
+ type=hints[n] if n in hints else annotations[n],
+ )
+ for n, a in annotations.items()
+ ]
+
+
+def _is_extensions_typeddict(cls) -> bool:
+ if _TypedDictMeta is None:
+ return False
+ return cls.__class__ is _TypedDictMeta or (
+ is_generic(cls) and (cls.__origin__.__class__ is _TypedDictMeta)
+ )
+
+
+if sys.version_info >= (3, 11):
+
+ def _required_keys(cls: type) -> set[str]:
+ return cls.__required_keys__
+
+elif sys.version_info >= (3, 9):
+ from typing_extensions import Annotated, NotRequired, Required, get_args
+
+ # Note that there is no `typing.Required` on 3.9 and 3.10, only in
+ # `typing_extensions`. Therefore, `typing.TypedDict` will not honor this
+ # annotation, only `typing_extensions.TypedDict`.
+
+ def _required_keys(cls: type) -> set[str]:
+ """Our own processor for required keys."""
+ if _is_extensions_typeddict(cls):
+ return cls.__required_keys__
+
+ # We vendor a part of the typing_extensions logic for
+ # gathering required keys. *sigh*
+ own_annotations = cls.__dict__.get("__annotations__", {})
+ required_keys = set()
+ # On 3.8 - 3.10, typing.TypedDict doesn't put typeddict superclasses
+ # in the MRO, therefore we cannot handle non-required keys properly
+ # in some situations. Oh well.
+ for key in getattr(cls, "__required_keys__", []):
+ annotation_type = own_annotations[key]
+ annotation_origin = get_origin(annotation_type)
+ if annotation_origin is Annotated:
+ annotation_args = get_args(annotation_type)
+ if annotation_args:
+ annotation_type = annotation_args[0]
+ annotation_origin = get_origin(annotation_type)
+
+ if annotation_origin is NotRequired:
+ pass
+ elif cls.__total__:
+ required_keys.add(key)
+ return required_keys
+
+else:
+ from typing_extensions import Annotated, NotRequired, Required, get_args
+
+ # On 3.8, typing.TypedDicts do not have __required_keys__.
+
+ def _required_keys(cls: type) -> set[str]:
+ """Our own processor for required keys."""
+ if _is_extensions_typeddict(cls):
+ return cls.__required_keys__
+
+ own_annotations = cls.__dict__.get("__annotations__", {})
+ required_keys = set()
+ for key in own_annotations:
+ annotation_type = own_annotations[key]
+
+ if is_annotated(annotation_type):
+ # If this is `Annotated`, we need to get the origin twice.
+ annotation_type = get_origin(annotation_type)
+
+ annotation_origin = get_origin(annotation_type)
+
+ if annotation_origin is Required:
+ required_keys.add(key)
+ elif annotation_origin is NotRequired:
+ pass
+ elif cls.__total__:
+ required_keys.add(key)
+ return required_keys
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/__init__.py
new file mode 100644
index 0000000..876576d
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/__init__.py
@@ -0,0 +1,27 @@
+import sys
+from datetime import datetime
+from typing import Any, Callable, TypeVar
+
+if sys.version_info[:2] < (3, 10):
+ from typing_extensions import ParamSpec
+else:
+ from typing import ParamSpec
+
+
+def validate_datetime(v, _):
+ if not isinstance(v, datetime):
+ raise Exception(f"Expected datetime, got {v}")
+ return v
+
+
+T = TypeVar("T")
+P = ParamSpec("P")
+
+
+def wrap(_: Callable[P, Any]) -> Callable[[Callable[..., T]], Callable[P, T]]:
+ """Wrap a `Converter` `__init__` in a type-safe way."""
+
+ def impl(x: Callable[..., T]) -> Callable[P, T]:
+ return x
+
+ return impl
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/bson.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/bson.py
new file mode 100644
index 0000000..e73d131
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/bson.py
@@ -0,0 +1,106 @@
+"""Preconfigured converters for bson."""
+
+from base64 import b85decode, b85encode
+from datetime import date, datetime
+from typing import Any, Type, TypeVar, Union
+
+from bson import DEFAULT_CODEC_OPTIONS, CodecOptions, Int64, ObjectId, decode, encode
+
+from cattrs._compat import AbstractSet, is_mapping
+from cattrs.gen import make_mapping_structure_fn
+
+from ..converters import BaseConverter, Converter
+from ..dispatch import StructureHook
+from ..strategies import configure_union_passthrough
+from . import validate_datetime, wrap
+
+T = TypeVar("T")
+
+
+class Base85Bytes(bytes):
+ """A subclass to help with binary key encoding/decoding."""
+
+
+class BsonConverter(Converter):
+ def dumps(
+ self,
+ obj: Any,
+ unstructure_as: Any = None,
+ check_keys: bool = False,
+ codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS,
+ ) -> bytes:
+ return encode(
+ self.unstructure(obj, unstructure_as=unstructure_as),
+ check_keys=check_keys,
+ codec_options=codec_options,
+ )
+
+ def loads(
+ self,
+ data: bytes,
+ cl: Type[T],
+ codec_options: CodecOptions = DEFAULT_CODEC_OPTIONS,
+ ) -> T:
+ return self.structure(decode(data, codec_options=codec_options), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the bson library.
+
+ * sets are serialized as lists
+ * byte mapping keys are base85-encoded into strings when unstructuring, and reverse
+ * non-string, non-byte mapping keys are coerced into strings when unstructuring
+ * a deserialization hook is registered for bson.ObjectId by default
+ """
+
+ def gen_unstructure_mapping(cl: Any, unstructure_to=None):
+ key_handler = str
+ args = getattr(cl, "__args__", None)
+ if args:
+ if issubclass(args[0], str):
+ key_handler = None
+ elif issubclass(args[0], bytes):
+
+ def key_handler(k):
+ return b85encode(k).decode("utf8")
+
+ return converter.gen_unstructure_mapping(
+ cl, unstructure_to=unstructure_to, key_handler=key_handler
+ )
+
+ def gen_structure_mapping(cl: Any) -> StructureHook:
+ args = getattr(cl, "__args__", None)
+ if args and issubclass(args[0], bytes):
+ h = make_mapping_structure_fn(cl, converter, key_type=Base85Bytes)
+ else:
+ h = make_mapping_structure_fn(cl, converter)
+ return h
+
+ converter.register_structure_hook(Base85Bytes, lambda v, _: b85decode(v))
+ converter.register_unstructure_hook_factory(is_mapping, gen_unstructure_mapping)
+ converter.register_structure_hook_factory(is_mapping, gen_structure_mapping)
+
+ converter.register_structure_hook(ObjectId, lambda v, _: ObjectId(v))
+ configure_union_passthrough(
+ Union[str, bool, int, float, None, bytes, datetime, ObjectId, Int64], converter
+ )
+
+ # datetime inherits from date, so identity unstructure hook used
+ # here to prevent the date unstructure hook running.
+ converter.register_unstructure_hook(datetime, lambda v: v)
+ converter.register_structure_hook(datetime, validate_datetime)
+ converter.register_unstructure_hook(date, lambda v: v.isoformat())
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+
+
+@wrap(BsonConverter)
+def make_converter(*args: Any, **kwargs: Any) -> BsonConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = BsonConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/cbor2.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/cbor2.py
new file mode 100644
index 0000000..73a9a97
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/cbor2.py
@@ -0,0 +1,50 @@
+"""Preconfigured converters for cbor2."""
+
+from datetime import date, datetime, timezone
+from typing import Any, Type, TypeVar, Union
+
+from cbor2 import dumps, loads
+
+from cattrs._compat import AbstractSet
+
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+
+class Cbor2Converter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: bytes, cl: Type[T], **kwargs: Any) -> T:
+ return self.structure(loads(data, **kwargs), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the cbor2 library.
+
+ * datetimes are serialized as timestamp floats
+ * sets are serialized as lists
+ """
+ converter.register_unstructure_hook(datetime, lambda v: v.timestamp())
+ converter.register_structure_hook(
+ datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc)
+ )
+ converter.register_unstructure_hook(date, lambda v: v.isoformat())
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+ configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter)
+
+
+@wrap(Cbor2Converter)
+def make_converter(*args: Any, **kwargs: Any) -> Cbor2Converter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = Cbor2Converter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/json.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/json.py
new file mode 100644
index 0000000..acc82ae
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/json.py
@@ -0,0 +1,56 @@
+"""Preconfigured converters for the stdlib json."""
+
+from base64 import b85decode, b85encode
+from datetime import date, datetime
+from json import dumps, loads
+from typing import Any, Type, TypeVar, Union
+
+from .._compat import AbstractSet, Counter
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+
+class JsonConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: Union[bytes, str], cl: Type[T], **kwargs: Any) -> T:
+ return self.structure(loads(data, **kwargs), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the stdlib json module.
+
+ * bytes are serialized as base85 strings
+ * datetimes are serialized as ISO 8601
+ * counters are serialized as dicts
+ * sets are serialized as lists
+ * union passthrough is configured for unions of strings, bools, ints,
+ floats and None
+ """
+ converter.register_unstructure_hook(
+ bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
+ )
+ converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
+ converter.register_unstructure_hook(datetime, lambda v: v.isoformat())
+ converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
+ converter.register_unstructure_hook(date, lambda v: v.isoformat())
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+ configure_union_passthrough(Union[str, bool, int, float, None], converter)
+
+
+@wrap(JsonConverter)
+def make_converter(*args: Any, **kwargs: Any) -> JsonConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ Counter: dict,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = JsonConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgpack.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgpack.py
new file mode 100644
index 0000000..dd7c369
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgpack.py
@@ -0,0 +1,54 @@
+"""Preconfigured converters for msgpack."""
+
+from datetime import date, datetime, time, timezone
+from typing import Any, Type, TypeVar, Union
+
+from msgpack import dumps, loads
+
+from cattrs._compat import AbstractSet
+
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+
+class MsgpackConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: bytes, cl: Type[T], **kwargs: Any) -> T:
+ return self.structure(loads(data, **kwargs), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the msgpack library.
+
+ * datetimes are serialized as timestamp floats
+ * sets are serialized as lists
+ """
+ converter.register_unstructure_hook(datetime, lambda v: v.timestamp())
+ converter.register_structure_hook(
+ datetime, lambda v, _: datetime.fromtimestamp(v, timezone.utc)
+ )
+ converter.register_unstructure_hook(
+ date, lambda v: datetime.combine(v, time(tzinfo=timezone.utc)).timestamp()
+ )
+ converter.register_structure_hook(
+ date, lambda v, _: datetime.fromtimestamp(v, timezone.utc).date()
+ )
+ configure_union_passthrough(Union[str, bool, int, float, None, bytes], converter)
+
+
+@wrap(MsgpackConverter)
+def make_converter(*args: Any, **kwargs: Any) -> MsgpackConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = MsgpackConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgspec.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgspec.py
new file mode 100644
index 0000000..6ef84d7
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/msgspec.py
@@ -0,0 +1,185 @@
+"""Preconfigured converters for msgspec."""
+
+from __future__ import annotations
+
+from base64 import b64decode
+from datetime import date, datetime
+from enum import Enum
+from functools import partial
+from typing import Any, Callable, TypeVar, Union, get_type_hints
+
+from attrs import has as attrs_has
+from attrs import resolve_types
+from msgspec import Struct, convert, to_builtins
+from msgspec.json import Encoder, decode
+
+from .._compat import (
+ fields,
+ get_args,
+ get_origin,
+ has,
+ is_bare,
+ is_mapping,
+ is_sequence,
+)
+from ..cols import is_namedtuple
+from ..converters import BaseConverter, Converter
+from ..dispatch import UnstructureHook
+from ..fns import identity
+from ..gen import make_hetero_tuple_unstructure_fn
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+__all__ = ["MsgspecJsonConverter", "configure_converter", "make_converter"]
+
+
+class MsgspecJsonConverter(Converter):
+ """A converter specialized for the _msgspec_ library."""
+
+ #: The msgspec encoder for dumping.
+ encoder: Encoder = Encoder()
+
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
+ """Unstructure and encode `obj` into JSON bytes."""
+ return self.encoder.encode(
+ self.unstructure(obj, unstructure_as=unstructure_as), **kwargs
+ )
+
+ def get_dumps_hook(
+ self, unstructure_as: Any, **kwargs: Any
+ ) -> Callable[[Any], bytes]:
+ """Produce a `dumps` hook for the given type."""
+ unstruct_hook = self.get_unstructure_hook(unstructure_as)
+ if unstruct_hook in (identity, to_builtins):
+ return self.encoder.encode
+ return self.dumps
+
+ def loads(self, data: bytes, cl: type[T], **kwargs: Any) -> T:
+ """Decode and structure `cl` from the provided JSON bytes."""
+ return self.structure(decode(data, **kwargs), cl)
+
+ def get_loads_hook(self, cl: type[T]) -> Callable[[bytes], T]:
+ """Produce a `loads` hook for the given type."""
+ return partial(self.loads, cl=cl)
+
+
+def configure_converter(converter: Converter) -> None:
+ """Configure the converter for the msgspec library.
+
+ * bytes are serialized as base64 strings, directly by msgspec
+ * datetimes and dates are passed through to be serialized as RFC 3339 directly
+ * enums are passed through to msgspec directly
+ * union passthrough configured for str, bool, int, float and None
+ """
+ configure_passthroughs(converter)
+
+ converter.register_unstructure_hook(Struct, to_builtins)
+ converter.register_unstructure_hook(Enum, to_builtins)
+
+ converter.register_structure_hook(Struct, convert)
+ converter.register_structure_hook(bytes, lambda v, _: b64decode(v))
+ converter.register_structure_hook(datetime, lambda v, _: convert(v, datetime))
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+ configure_union_passthrough(Union[str, bool, int, float, None], converter)
+
+
+@wrap(MsgspecJsonConverter)
+def make_converter(*args: Any, **kwargs: Any) -> MsgspecJsonConverter:
+ res = MsgspecJsonConverter(*args, **kwargs)
+ configure_converter(res)
+ return res
+
+
+def configure_passthroughs(converter: Converter) -> None:
+ """Configure optimizing passthroughs.
+
+ A passthrough is when we let msgspec handle something automatically.
+ """
+ converter.register_unstructure_hook(bytes, to_builtins)
+ converter.register_unstructure_hook_factory(is_mapping, mapping_unstructure_factory)
+ converter.register_unstructure_hook_factory(is_sequence, seq_unstructure_factory)
+ converter.register_unstructure_hook_factory(has, attrs_unstructure_factory)
+ converter.register_unstructure_hook_factory(
+ is_namedtuple, namedtuple_unstructure_factory
+ )
+
+
+def seq_unstructure_factory(type, converter: Converter) -> UnstructureHook:
+ """The msgspec unstructure hook factory for sequences."""
+ if is_bare(type):
+ type_arg = Any
+ else:
+ args = get_args(type)
+ type_arg = args[0]
+ handler = converter.get_unstructure_hook(type_arg, cache_result=False)
+
+ if handler in (identity, to_builtins):
+ return handler
+ return converter.gen_unstructure_iterable(type)
+
+
+def mapping_unstructure_factory(type, converter: BaseConverter) -> UnstructureHook:
+ """The msgspec unstructure hook factory for mappings."""
+ if is_bare(type):
+ key_arg = Any
+ val_arg = Any
+ key_handler = converter.get_unstructure_hook(key_arg, cache_result=False)
+ value_handler = converter.get_unstructure_hook(val_arg, cache_result=False)
+ else:
+ args = get_args(type)
+ if len(args) == 2:
+ key_arg, val_arg = args
+ else:
+ # Probably a Counter
+ key_arg, val_arg = args, Any
+ key_handler = converter.get_unstructure_hook(key_arg, cache_result=False)
+ value_handler = converter.get_unstructure_hook(val_arg, cache_result=False)
+
+ if key_handler in (identity, to_builtins) and value_handler in (
+ identity,
+ to_builtins,
+ ):
+ return to_builtins
+ return converter.gen_unstructure_mapping(type)
+
+
+def attrs_unstructure_factory(type: Any, converter: Converter) -> UnstructureHook:
+ """Choose whether to use msgspec handling or our own."""
+ origin = get_origin(type)
+ attribs = fields(origin or type)
+ if attrs_has(type) and any(isinstance(a.type, str) for a in attribs):
+ resolve_types(type)
+ attribs = fields(origin or type)
+
+ if any(
+ attr.name.startswith("_")
+ or (
+ converter.get_unstructure_hook(attr.type, cache_result=False)
+ not in (identity, to_builtins)
+ )
+ for attr in attribs
+ ):
+ return converter.gen_unstructure_attrs_fromdict(type)
+
+ return to_builtins
+
+
+def namedtuple_unstructure_factory(
+ type: type[tuple], converter: BaseConverter
+) -> UnstructureHook:
+ """A hook factory for unstructuring namedtuples, modified for msgspec."""
+
+ if all(
+ converter.get_unstructure_hook(t) in (identity, to_builtins)
+ for t in get_type_hints(type).values()
+ ):
+ return identity
+
+ return make_hetero_tuple_unstructure_fn(
+ type,
+ converter,
+ unstructure_to=tuple,
+ type_args=tuple(get_type_hints(type).values()),
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/orjson.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/orjson.py
new file mode 100644
index 0000000..4b595bc
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/orjson.py
@@ -0,0 +1,95 @@
+"""Preconfigured converters for orjson."""
+
+from base64 import b85decode, b85encode
+from datetime import date, datetime
+from enum import Enum
+from functools import partial
+from typing import Any, Type, TypeVar, Union
+
+from orjson import dumps, loads
+
+from .._compat import AbstractSet, is_mapping
+from ..cols import is_namedtuple, namedtuple_unstructure_factory
+from ..converters import BaseConverter, Converter
+from ..fns import identity
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+
+class OrjsonConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> bytes:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: Union[bytes, bytearray, memoryview, str], cl: Type[T]) -> T:
+ return self.structure(loads(data), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the orjson library.
+
+ * bytes are serialized as base85 strings
+ * datetimes and dates are passed through to be serialized as RFC 3339 by orjson
+ * typed namedtuples are serialized as lists
+ * sets are serialized as lists
+ * string enum mapping keys have special handling
+ * mapping keys are coerced into strings when unstructuring
+
+ .. versionchanged: 24.1.0
+ Add support for typed namedtuples.
+ """
+ converter.register_unstructure_hook(
+ bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
+ )
+ converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
+
+ converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+
+ def gen_unstructure_mapping(cl: Any, unstructure_to=None):
+ key_handler = str
+ args = getattr(cl, "__args__", None)
+ if args:
+ if issubclass(args[0], str) and issubclass(args[0], Enum):
+
+ def key_handler(v):
+ return v.value
+
+ else:
+ # It's possible the handler for the key type has been overridden.
+ # (For example base85 encoding for bytes.)
+ # In that case, we want to use the override.
+
+ kh = converter.get_unstructure_hook(args[0])
+ if kh != identity:
+ key_handler = kh
+
+ return converter.gen_unstructure_mapping(
+ cl, unstructure_to=unstructure_to, key_handler=key_handler
+ )
+
+ converter._unstructure_func.register_func_list(
+ [
+ (is_mapping, gen_unstructure_mapping, True),
+ (
+ is_namedtuple,
+ partial(namedtuple_unstructure_factory, unstructure_to=tuple),
+ "extended",
+ ),
+ ]
+ )
+ configure_union_passthrough(Union[str, bool, int, float, None], converter)
+
+
+@wrap(OrjsonConverter)
+def make_converter(*args: Any, **kwargs: Any) -> OrjsonConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = OrjsonConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/pyyaml.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/pyyaml.py
new file mode 100644
index 0000000..7374625
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/pyyaml.py
@@ -0,0 +1,72 @@
+"""Preconfigured converters for pyyaml."""
+
+from datetime import date, datetime
+from functools import partial
+from typing import Any, Type, TypeVar, Union
+
+from yaml import safe_dump, safe_load
+
+from .._compat import FrozenSetSubscriptable
+from ..cols import is_namedtuple, namedtuple_unstructure_factory
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import validate_datetime, wrap
+
+T = TypeVar("T")
+
+
+def validate_date(v, _):
+ if not isinstance(v, date):
+ raise ValueError(f"Expected date, got {v}")
+ return v
+
+
+class PyyamlConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
+ return safe_dump(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: str, cl: Type[T]) -> T:
+ return self.structure(safe_load(data), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the pyyaml library.
+
+ * frozensets are serialized as lists
+ * string enums are converted into strings explicitly
+ * datetimes and dates are validated
+ * typed namedtuples are serialized as lists
+
+ .. versionchanged: 24.1.0
+ Add support for typed namedtuples.
+ """
+ converter.register_unstructure_hook(
+ str, lambda v: v if v.__class__ is str else v.value
+ )
+
+ # datetime inherits from date, so identity unstructure hook used
+ # here to prevent the date unstructure hook running.
+ converter.register_unstructure_hook(datetime, lambda v: v)
+ converter.register_structure_hook(datetime, validate_datetime)
+ converter.register_structure_hook(date, validate_date)
+
+ converter.register_unstructure_hook_factory(is_namedtuple)(
+ partial(namedtuple_unstructure_factory, unstructure_to=tuple)
+ )
+
+ configure_union_passthrough(
+ Union[str, bool, int, float, None, bytes, datetime, date], converter
+ )
+
+
+@wrap(PyyamlConverter)
+def make_converter(*args: Any, **kwargs: Any) -> PyyamlConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ FrozenSetSubscriptable: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = PyyamlConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/tomlkit.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/tomlkit.py
new file mode 100644
index 0000000..0d0180b
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/tomlkit.py
@@ -0,0 +1,87 @@
+"""Preconfigured converters for tomlkit."""
+
+from base64 import b85decode, b85encode
+from datetime import date, datetime
+from enum import Enum
+from operator import attrgetter
+from typing import Any, Type, TypeVar, Union
+
+from tomlkit import dumps, loads
+from tomlkit.items import Float, Integer, String
+
+from cattrs._compat import AbstractSet, is_mapping
+
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import validate_datetime, wrap
+
+T = TypeVar("T")
+_enum_value_getter = attrgetter("_value_")
+
+
+class TomlkitConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: str, cl: Type[T]) -> T:
+ return self.structure(loads(data), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the tomlkit library.
+
+ * bytes are serialized as base85 strings
+ * sets are serialized as lists
+ * tuples are serializas as lists
+ * mapping keys are coerced into strings when unstructuring
+ """
+ converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
+ converter.register_unstructure_hook(
+ bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
+ )
+
+ def gen_unstructure_mapping(cl: Any, unstructure_to=None):
+ key_handler = str
+ args = getattr(cl, "__args__", None)
+ if args:
+ # Currently, tomlkit has inconsistent behavior on 3.11
+ # so we paper over it here.
+ # https://github.com/sdispater/tomlkit/issues/237
+ if issubclass(args[0], str):
+ key_handler = _enum_value_getter if issubclass(args[0], Enum) else None
+ elif issubclass(args[0], bytes):
+
+ def key_handler(k: bytes):
+ return b85encode(k).decode("utf8")
+
+ return converter.gen_unstructure_mapping(
+ cl, unstructure_to=unstructure_to, key_handler=key_handler
+ )
+
+ converter._unstructure_func.register_func_list(
+ [(is_mapping, gen_unstructure_mapping, True)]
+ )
+
+ # datetime inherits from date, so identity unstructure hook used
+ # here to prevent the date unstructure hook running.
+ converter.register_unstructure_hook(datetime, lambda v: v)
+ converter.register_structure_hook(datetime, validate_datetime)
+ converter.register_unstructure_hook(date, lambda v: v.isoformat())
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+ configure_union_passthrough(
+ Union[str, String, bool, int, Integer, float, Float], converter
+ )
+
+
+@wrap(TomlkitConverter)
+def make_converter(*args: Any, **kwargs: Any) -> TomlkitConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ tuple: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = TomlkitConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/ujson.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/ujson.py
new file mode 100644
index 0000000..7256d52
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/preconf/ujson.py
@@ -0,0 +1,55 @@
+"""Preconfigured converters for ujson."""
+
+from base64 import b85decode, b85encode
+from datetime import date, datetime
+from typing import Any, AnyStr, Type, TypeVar, Union
+
+from ujson import dumps, loads
+
+from cattrs._compat import AbstractSet
+
+from ..converters import BaseConverter, Converter
+from ..strategies import configure_union_passthrough
+from . import wrap
+
+T = TypeVar("T")
+
+
+class UjsonConverter(Converter):
+ def dumps(self, obj: Any, unstructure_as: Any = None, **kwargs: Any) -> str:
+ return dumps(self.unstructure(obj, unstructure_as=unstructure_as), **kwargs)
+
+ def loads(self, data: AnyStr, cl: Type[T], **kwargs: Any) -> T:
+ return self.structure(loads(data, **kwargs), cl)
+
+
+def configure_converter(converter: BaseConverter):
+ """
+ Configure the converter for use with the ujson library.
+
+ * bytes are serialized as base64 strings
+ * datetimes are serialized as ISO 8601
+ * sets are serialized as lists
+ """
+ converter.register_unstructure_hook(
+ bytes, lambda v: (b85encode(v) if v else b"").decode("utf8")
+ )
+ converter.register_structure_hook(bytes, lambda v, _: b85decode(v))
+
+ converter.register_unstructure_hook(datetime, lambda v: v.isoformat())
+ converter.register_structure_hook(datetime, lambda v, _: datetime.fromisoformat(v))
+ converter.register_unstructure_hook(date, lambda v: v.isoformat())
+ converter.register_structure_hook(date, lambda v, _: date.fromisoformat(v))
+ configure_union_passthrough(Union[str, bool, int, float, None], converter)
+
+
+@wrap(UjsonConverter)
+def make_converter(*args: Any, **kwargs: Any) -> UjsonConverter:
+ kwargs["unstruct_collection_overrides"] = {
+ AbstractSet: list,
+ **kwargs.get("unstruct_collection_overrides", {}),
+ }
+ res = UjsonConverter(*args, **kwargs)
+ configure_converter(res)
+
+ return res
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/py.typed b/lambdas/aws-dd-forwarder-3.127.0/cattrs/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/__init__.py
new file mode 100644
index 0000000..9caf073
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/__init__.py
@@ -0,0 +1,12 @@
+"""High level strategies for converters."""
+
+from ._class_methods import use_class_methods
+from ._subclasses import include_subclasses
+from ._unions import configure_tagged_union, configure_union_passthrough
+
+__all__ = [
+ "configure_tagged_union",
+ "configure_union_passthrough",
+ "include_subclasses",
+ "use_class_methods",
+]
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_class_methods.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_class_methods.py
new file mode 100644
index 0000000..c2b6325
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_class_methods.py
@@ -0,0 +1,64 @@
+"""Strategy for using class-specific (un)structuring methods."""
+
+from inspect import signature
+from typing import Any, Callable, Optional, Type, TypeVar
+
+from .. import BaseConverter
+
+T = TypeVar("T")
+
+
+def use_class_methods(
+ converter: BaseConverter,
+ structure_method_name: Optional[str] = None,
+ unstructure_method_name: Optional[str] = None,
+) -> None:
+ """
+ Configure the converter such that dedicated methods are used for (un)structuring
+ the instance of a class if such methods are available. The default (un)structuring
+ will be applied if such an (un)structuring methods cannot be found.
+
+ :param converter: The `Converter` on which this strategy is applied. You can use
+ :class:`cattrs.BaseConverter` or any other derived class.
+ :param structure_method_name: Optional string with the name of the class method
+ which should be used for structuring. If not provided, no class method will be
+ used for structuring.
+ :param unstructure_method_name: Optional string with the name of the class method
+ which should be used for unstructuring. If not provided, no class method will
+ be used for unstructuring.
+
+ If you want to (un)structured nested objects, just append a converter parameter
+ to your (un)structuring methods and you will receive the converter there.
+
+ .. versionadded:: 23.2.0
+ """
+
+ if structure_method_name:
+
+ def make_class_method_structure(cl: Type[T]) -> Callable[[Any, Type[T]], T]:
+ fn = getattr(cl, structure_method_name)
+ n_parameters = len(signature(fn).parameters)
+ if n_parameters == 1:
+ return lambda v, _: fn(v)
+ if n_parameters == 2:
+ return lambda v, _: fn(v, converter)
+ raise TypeError("Provide a class method with one or two arguments.")
+
+ converter.register_structure_hook_factory(
+ lambda t: hasattr(t, structure_method_name), make_class_method_structure
+ )
+
+ if unstructure_method_name:
+
+ def make_class_method_unstructure(cl: Type[T]) -> Callable[[T], T]:
+ fn = getattr(cl, unstructure_method_name)
+ n_parameters = len(signature(fn).parameters)
+ if n_parameters == 1:
+ return fn
+ if n_parameters == 2:
+ return lambda self_: fn(self_, converter)
+ raise TypeError("Provide a method with no or one argument.")
+
+ converter.register_unstructure_hook_factory(
+ lambda t: hasattr(t, unstructure_method_name), make_class_method_unstructure
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_subclasses.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_subclasses.py
new file mode 100644
index 0000000..06a92af
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_subclasses.py
@@ -0,0 +1,238 @@
+"""Strategies for customizing subclass behaviors."""
+
+from __future__ import annotations
+
+from gc import collect
+from typing import Any, Callable, TypeVar, Union
+
+from ..converters import BaseConverter
+from ..gen import AttributeOverride, make_dict_structure_fn, make_dict_unstructure_fn
+from ..gen._consts import already_generating
+
+
+def _make_subclasses_tree(cl: type) -> list[type]:
+ return [cl] + [
+ sscl for scl in cl.__subclasses__() for sscl in _make_subclasses_tree(scl)
+ ]
+
+
+def _has_subclasses(cl: type, given_subclasses: tuple[type, ...]) -> bool:
+ """Whether the given class has subclasses from `given_subclasses`."""
+ actual = set(cl.__subclasses__())
+ given = set(given_subclasses)
+ return bool(actual & given)
+
+
+def _get_union_type(cl: type, given_subclasses_tree: tuple[type]) -> type | None:
+ actual_subclass_tree = tuple(_make_subclasses_tree(cl))
+ class_tree = tuple(set(actual_subclass_tree) & set(given_subclasses_tree))
+ return Union[class_tree] if len(class_tree) >= 2 else None
+
+
+C = TypeVar("C", bound=BaseConverter)
+
+
+def include_subclasses(
+ cl: type,
+ converter: C,
+ subclasses: tuple[type, ...] | None = None,
+ union_strategy: Callable[[Any, C], Any] | None = None,
+ overrides: dict[str, AttributeOverride] | None = None,
+) -> None:
+ """
+ Configure the converter so that the attrs/dataclass `cl` is un/structured as if it
+ was a union of itself and all its subclasses that are defined at the time when this
+ strategy is applied.
+
+ :param cl: A base `attrs` or `dataclass` class.
+ :param converter: The `Converter` on which this strategy is applied. Do note that
+ the strategy does not work for a :class:`cattrs.BaseConverter`.
+ :param subclasses: A tuple of sublcasses whose ancestor is `cl`. If left as `None`,
+ subclasses are detected using recursively the `__subclasses__` method of `cl`
+ and its descendents.
+ :param union_strategy: A callable of two arguments passed by position
+ (`subclass_union`, `converter`) that defines the union strategy to use to
+ disambiguate the subclasses union. If `None` (the default), the automatic unique
+ field disambiguation is used which means that every single subclass
+ participating in the union must have an attribute name that does not exist in
+ any other sibling class.
+ :param overrides: a mapping of `cl` attribute names to overrides (instantiated with
+ :func:`cattrs.gen.override`) to customize un/structuring.
+
+ .. versionadded:: 23.1.0
+ .. versionchanged:: 24.1.0
+ When overrides are not provided, hooks for individual classes are retrieved from
+ the converter instead of generated with no overrides, using converter defaults.
+ """
+ # Due to https://github.com/python-attrs/attrs/issues/1047
+ collect()
+ if subclasses is not None:
+ parent_subclass_tree = (cl, *subclasses)
+ else:
+ parent_subclass_tree = tuple(_make_subclasses_tree(cl))
+
+ if union_strategy is None:
+ _include_subclasses_without_union_strategy(
+ cl, converter, parent_subclass_tree, overrides
+ )
+ else:
+ _include_subclasses_with_union_strategy(
+ converter, parent_subclass_tree, union_strategy, overrides
+ )
+
+
+def _include_subclasses_without_union_strategy(
+ cl,
+ converter: BaseConverter,
+ parent_subclass_tree: tuple[type],
+ overrides: dict[str, AttributeOverride] | None,
+):
+ # The iteration approach is required if subclasses are more than one level deep:
+ for cl in parent_subclass_tree:
+ # We re-create a reduced union type to handle the following case:
+ #
+ # converter.structure(d, as=Child)
+ #
+ # In the above, the `as=Child` argument will be transformed to a union type of
+ # itself and its subtypes, that way we guarantee that the returned object will
+ # not be the parent.
+ subclass_union = _get_union_type(cl, parent_subclass_tree)
+
+ def cls_is_cl(cls, _cl=cl):
+ return cls is _cl
+
+ if overrides is not None:
+ base_struct_hook = make_dict_structure_fn(cl, converter, **overrides)
+ base_unstruct_hook = make_dict_unstructure_fn(cl, converter, **overrides)
+ else:
+ base_struct_hook = converter.get_structure_hook(cl)
+ base_unstruct_hook = converter.get_unstructure_hook(cl)
+
+ if subclass_union is None:
+
+ def struct_hook(val: dict, _, _cl=cl, _base_hook=base_struct_hook) -> cl:
+ return _base_hook(val, _cl)
+
+ else:
+ dis_fn = converter._get_dis_func(subclass_union, overrides=overrides)
+
+ def struct_hook(
+ val: dict,
+ _,
+ _c=converter,
+ _cl=cl,
+ _base_hook=base_struct_hook,
+ _dis_fn=dis_fn,
+ ) -> cl:
+ """
+ If val is disambiguated to the class `cl`, use its base hook.
+
+ If val is disambiguated to a subclass, dispatch on its exact runtime
+ type.
+ """
+ dis_cl = _dis_fn(val)
+ if dis_cl is _cl:
+ return _base_hook(val, _cl)
+ return _c.structure(val, dis_cl)
+
+ def unstruct_hook(
+ val: parent_subclass_tree[0],
+ _c=converter,
+ _cl=cl,
+ _base_hook=base_unstruct_hook,
+ ) -> dict:
+ """
+ If val is an instance of the class `cl`, use the hook.
+
+ If val is an instance of a subclass, dispatch on its exact runtime type.
+ """
+ if val.__class__ is _cl:
+ return _base_hook(val)
+ return _c.unstructure(val, unstructure_as=val.__class__)
+
+ # This needs to use function dispatch, using singledispatch will again
+ # match A and all subclasses, which is not what we want.
+ converter.register_structure_hook_func(cls_is_cl, struct_hook)
+ converter.register_unstructure_hook_func(cls_is_cl, unstruct_hook)
+
+
+def _include_subclasses_with_union_strategy(
+ converter: C,
+ union_classes: tuple[type, ...],
+ union_strategy: Callable[[Any, C], Any],
+ overrides: dict[str, AttributeOverride] | None,
+):
+ """
+ This function is tricky because we're dealing with what is essentially a circular
+ reference.
+
+ We need to generate a structure hook for a class that is both:
+ * specific for that particular class and its own fields
+ * but should handle specific functions for all its descendants too
+
+ Hence the dance with registering below.
+ """
+
+ parent_classes = [cl for cl in union_classes if _has_subclasses(cl, union_classes)]
+ if not parent_classes:
+ return
+
+ original_unstruct_hooks = {}
+ original_struct_hooks = {}
+ for cl in union_classes:
+ # In the first pass, every class gets its own unstructure function according to
+ # the overrides.
+ # We just generate the hooks, and do not register them. This allows us to
+ # manipulate the _already_generating set to force runtime dispatch.
+ already_generating.working_set = set(union_classes) - {cl}
+ try:
+ if overrides is not None:
+ unstruct_hook = make_dict_unstructure_fn(cl, converter, **overrides)
+ struct_hook = make_dict_structure_fn(cl, converter, **overrides)
+ else:
+ unstruct_hook = converter.get_unstructure_hook(cl, cache_result=False)
+ struct_hook = converter.get_structure_hook(cl, cache_result=False)
+ finally:
+ already_generating.working_set = set()
+ original_unstruct_hooks[cl] = unstruct_hook
+ original_struct_hooks[cl] = struct_hook
+
+ # Now that's done, we can register all the hooks and generate the
+ # union handler. The union handler needs them.
+ final_union = Union[union_classes] # type: ignore
+
+ for cl, hook in original_unstruct_hooks.items():
+
+ def cls_is_cl(cls, _cl=cl):
+ return cls is _cl
+
+ converter.register_unstructure_hook_func(cls_is_cl, hook)
+
+ for cl, hook in original_struct_hooks.items():
+
+ def cls_is_cl(cls, _cl=cl):
+ return cls is _cl
+
+ converter.register_structure_hook_func(cls_is_cl, hook)
+
+ union_strategy(final_union, converter)
+ unstruct_hook = converter.get_unstructure_hook(final_union)
+ struct_hook = converter.get_structure_hook(final_union)
+
+ for cl in union_classes:
+ # In the second pass, we overwrite the hooks with the union hook.
+
+ def cls_is_cl(cls, _cl=cl):
+ return cls is _cl
+
+ converter.register_unstructure_hook_func(cls_is_cl, unstruct_hook)
+ subclasses = tuple([c for c in union_classes if issubclass(c, cl)])
+ if len(subclasses) > 1:
+ u = Union[subclasses] # type: ignore
+ union_strategy(u, converter)
+ struct_hook = converter.get_structure_hook(u)
+
+ def sh(payload: dict, _, _u=u, _s=struct_hook) -> cl:
+ return _s(payload, _u)
+
+ converter.register_structure_hook_func(cls_is_cl, sh)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_unions.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_unions.py
new file mode 100644
index 0000000..f0d270d
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/strategies/_unions.py
@@ -0,0 +1,258 @@
+from collections import defaultdict
+from typing import Any, Callable, Dict, Literal, Type, Union
+
+from attrs import NOTHING
+
+from cattrs import BaseConverter
+from cattrs._compat import get_newtype_base, is_literal, is_subclass, is_union_type
+
+__all__ = [
+ "default_tag_generator",
+ "configure_tagged_union",
+ "configure_union_passthrough",
+]
+
+
+def default_tag_generator(typ: Type) -> str:
+ """Return the class name."""
+ return typ.__name__
+
+
+def configure_tagged_union(
+ union: Any,
+ converter: BaseConverter,
+ tag_generator: Callable[[Type], str] = default_tag_generator,
+ tag_name: str = "_type",
+ default: Union[Type, Literal[NOTHING]] = NOTHING,
+) -> None:
+ """
+ Configure the converter so that `union` (which should be a union) is
+ un/structured with the help of an additional piece of data in the
+ unstructured payload, the tag.
+
+ :param converter: The converter to apply the strategy to.
+ :param tag_generator: A `tag_generator` function is used to map each
+ member of the union to a tag, which is then included in the
+ unstructured payload. The default tag generator returns the name of
+ the class.
+ :param tag_name: The key under which the tag will be set in the
+ unstructured payload. By default, `'_type'`.
+ :param default: An optional class to be used if the tag information
+ is not present when structuring.
+
+ The tagged union strategy currently only works with the dict
+ un/structuring base strategy.
+
+ .. versionadded:: 23.1.0
+ """
+ args = union.__args__
+ tag_to_hook = {}
+ exact_cl_unstruct_hooks = {}
+ for cl in args:
+ tag = tag_generator(cl)
+ struct_handler = converter.get_structure_hook(cl)
+ unstruct_handler = converter.get_unstructure_hook(cl)
+
+ def structure_union_member(val: dict, _cl=cl, _h=struct_handler) -> cl:
+ return _h(val, _cl)
+
+ def unstructure_union_member(val: union, _h=unstruct_handler) -> dict:
+ return _h(val)
+
+ tag_to_hook[tag] = structure_union_member
+ exact_cl_unstruct_hooks[cl] = unstructure_union_member
+
+ cl_to_tag = {cl: tag_generator(cl) for cl in args}
+
+ if default is not NOTHING:
+ default_handler = converter.get_structure_hook(default)
+
+ def structure_default(val: dict, _cl=default, _h=default_handler):
+ return _h(val, _cl)
+
+ tag_to_hook = defaultdict(lambda: structure_default, tag_to_hook)
+ cl_to_tag = defaultdict(lambda: default, cl_to_tag)
+
+ def unstructure_tagged_union(
+ val: union,
+ _exact_cl_unstruct_hooks=exact_cl_unstruct_hooks,
+ _cl_to_tag=cl_to_tag,
+ _tag_name=tag_name,
+ ) -> Dict:
+ res = _exact_cl_unstruct_hooks[val.__class__](val)
+ res[_tag_name] = _cl_to_tag[val.__class__]
+ return res
+
+ if default is NOTHING:
+ if getattr(converter, "forbid_extra_keys", False):
+
+ def structure_tagged_union(
+ val: dict, _, _tag_to_cl=tag_to_hook, _tag_name=tag_name
+ ) -> union:
+ val = val.copy()
+ return _tag_to_cl[val.pop(_tag_name)](val)
+
+ else:
+
+ def structure_tagged_union(
+ val: dict, _, _tag_to_cl=tag_to_hook, _tag_name=tag_name
+ ) -> union:
+ return _tag_to_cl[val[_tag_name]](val)
+
+ else:
+ if getattr(converter, "forbid_extra_keys", False):
+
+ def structure_tagged_union(
+ val: dict,
+ _,
+ _tag_to_hook=tag_to_hook,
+ _tag_name=tag_name,
+ _dh=default_handler,
+ _default=default,
+ ) -> union:
+ if _tag_name in val:
+ val = val.copy()
+ return _tag_to_hook[val.pop(_tag_name)](val)
+ return _dh(val, _default)
+
+ else:
+
+ def structure_tagged_union(
+ val: dict,
+ _,
+ _tag_to_hook=tag_to_hook,
+ _tag_name=tag_name,
+ _dh=default_handler,
+ _default=default,
+ ) -> union:
+ if _tag_name in val:
+ return _tag_to_hook[val[_tag_name]](val)
+ return _dh(val, _default)
+
+ converter.register_unstructure_hook(union, unstructure_tagged_union)
+ converter.register_structure_hook(union, structure_tagged_union)
+
+
+def configure_union_passthrough(union: Any, converter: BaseConverter) -> None:
+ """
+ Configure the converter to support validating and passing through unions of the
+ provided types and their subsets.
+
+ For example, all mature JSON libraries natively support producing unions of ints,
+ floats, Nones, and strings. Using this strategy, a converter can be configured
+ to efficiently validate and pass through unions containing these types.
+
+ The most important point is that another library (in this example the JSON
+ library) handles producing the union, and the converter is configured to just
+ validate it.
+
+ Literals of provided types are also supported, and are checked by value.
+
+ NewTypes of provided types are also supported.
+
+ The strategy is designed to be O(1) in execution time, and independent of the
+ ordering of types in the union.
+
+ If the union contains a class and one or more of its subclasses, the subclasses
+ will also be included when validating the superclass.
+
+ .. versionadded:: 23.2.0
+ """
+ args = set(union.__args__)
+
+ def make_structure_native_union(exact_type: Any) -> Callable:
+ # `exact_type` is likely to be a subset of the entire configured union (`args`).
+ literal_values = {
+ v for t in exact_type.__args__ if is_literal(t) for v in t.__args__
+ }
+
+ # We have no idea what the actual type of `val` will be, so we can't
+ # use it blindly with an `in` check since it might not be hashable.
+ # So we do an additional check when handling literals.
+ # Note: do no use `literal_values` here, since {0, False} gets reduced to {0}
+ literal_classes = {
+ v.__class__
+ for t in exact_type.__args__
+ if is_literal(t)
+ for v in t.__args__
+ }
+
+ non_literal_classes = {
+ get_newtype_base(t) or t
+ for t in exact_type.__args__
+ if not is_literal(t) and ((get_newtype_base(t) or t) in args)
+ }
+
+ # We augment the set of allowed classes with any configured subclasses of
+ # the exact subclasses.
+ non_literal_classes |= {
+ a for a in args if any(is_subclass(a, c) for c in non_literal_classes)
+ }
+
+ # We check for spillover - union types not handled by the strategy.
+ # If spillover exists and we fail to validate our types, we call
+ # further into the converter with the rest.
+ spillover = {
+ a
+ for a in exact_type.__args__
+ if (get_newtype_base(a) or a) not in non_literal_classes
+ and not is_literal(a)
+ }
+
+ if spillover:
+ spillover_type = (
+ Union[tuple(spillover)] if len(spillover) > 1 else next(iter(spillover))
+ )
+
+ def structure_native_union(
+ val: Any,
+ _: Any,
+ classes=non_literal_classes,
+ vals=literal_values,
+ converter=converter,
+ spillover=spillover_type,
+ ) -> exact_type:
+ if val.__class__ in literal_classes and val in vals:
+ return val
+ if val.__class__ in classes:
+ return val
+ return converter.structure(val, spillover)
+
+ else:
+
+ def structure_native_union(
+ val: Any, _: Any, classes=non_literal_classes, vals=literal_values
+ ) -> exact_type:
+ if val.__class__ in literal_classes and val in vals:
+ return val
+ if val.__class__ in classes:
+ return val
+ raise TypeError(f"{val} ({val.__class__}) not part of {_}")
+
+ return structure_native_union
+
+ def contains_native_union(exact_type: Any) -> bool:
+ """Can we handle this type?"""
+ if is_union_type(exact_type):
+ type_args = set(exact_type.__args__)
+ # We special case optionals, since they are very common
+ # and are handled a little more efficiently by default.
+ if len(type_args) == 2 and type(None) in type_args:
+ return False
+
+ literal_classes = {
+ lit_arg.__class__
+ for t in type_args
+ if is_literal(t)
+ for lit_arg in t.__args__
+ }
+ non_literal_types = {
+ get_newtype_base(t) or t for t in type_args if not is_literal(t)
+ }
+
+ return (literal_classes | non_literal_types) & args
+ return False
+
+ converter.register_structure_hook_factory(
+ contains_native_union, make_structure_native_union
+ )
diff --git a/lambdas/aws-dd-forwarder-3.127.0/cattrs/v.py b/lambdas/aws-dd-forwarder-3.127.0/cattrs/v.py
new file mode 100644
index 0000000..c3ab18c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/cattrs/v.py
@@ -0,0 +1,112 @@
+"""Cattrs validation."""
+
+from typing import Callable, List, Union
+
+from .errors import (
+ ClassValidationError,
+ ForbiddenExtraKeysError,
+ IterableValidationError,
+)
+
+__all__ = ["format_exception", "transform_error"]
+
+
+def format_exception(exc: BaseException, type: Union[type, None]) -> str:
+ """The default exception formatter, handling the most common exceptions.
+
+ The following exceptions are handled specially:
+
+ * `KeyErrors` (`required field missing`)
+ * `ValueErrors` (`invalid value for type, expected ` or just `invalid value`)
+ * `TypeErrors` (`invalid value for type, expected ` and a couple special
+ cases for iterables)
+ * `cattrs.ForbiddenExtraKeysError`
+ * some `AttributeErrors` (special cased for structing mappings)
+ """
+ if isinstance(exc, KeyError):
+ res = "required field missing"
+ elif isinstance(exc, ValueError):
+ if type is not None:
+ tn = type.__name__ if hasattr(type, "__name__") else repr(type)
+ res = f"invalid value for type, expected {tn}"
+ else:
+ res = "invalid value"
+ elif isinstance(exc, TypeError):
+ if type is None:
+ if exc.args[0].endswith("object is not iterable"):
+ res = "invalid value for type, expected an iterable"
+ else:
+ res = f"invalid type ({exc})"
+ else:
+ tn = type.__name__ if hasattr(type, "__name__") else repr(type)
+ res = f"invalid value for type, expected {tn}"
+ elif isinstance(exc, ForbiddenExtraKeysError):
+ res = f"extra fields found ({', '.join(exc.extra_fields)})"
+ elif isinstance(exc, AttributeError) and exc.args[0].endswith(
+ "object has no attribute 'items'"
+ ):
+ # This was supposed to be a mapping (and have .items()) but it something else.
+ res = "expected a mapping"
+ elif isinstance(exc, AttributeError) and exc.args[0].endswith(
+ "object has no attribute 'copy'"
+ ):
+ # This was supposed to be a mapping (and have .copy()) but it something else.
+ # Used for TypedDicts.
+ res = "expected a mapping"
+ else:
+ res = f"unknown error ({exc})"
+
+ return res
+
+
+def transform_error(
+ exc: Union[ClassValidationError, IterableValidationError, BaseException],
+ path: str = "$",
+ format_exception: Callable[
+ [BaseException, Union[type, None]], str
+ ] = format_exception,
+) -> List[str]:
+ """Transform an exception into a list of error messages.
+
+ To get detailed error messages, the exception should be produced by a converter
+ with `detailed_validation` set.
+
+ By default, the error messages are in the form of `{description} @ {path}`.
+
+ While traversing the exception and subexceptions, the path is formed:
+
+ * by appending `.{field_name}` for fields in classes
+ * by appending `[{int}]` for indices in iterables, like lists
+ * by appending `[{str}]` for keys in mappings, like dictionaries
+
+ :param exc: The exception to transform into error messages.
+ :param path: The root path to use.
+ :param format_exception: A callable to use to transform `Exceptions` into
+ string descriptions of errors.
+
+ .. versionadded:: 23.1.0
+ """
+ errors = []
+ if isinstance(exc, IterableValidationError):
+ with_notes, without = exc.group_exceptions()
+ for exc, note in with_notes:
+ p = f"{path}[{note.index!r}]"
+ if isinstance(exc, (ClassValidationError, IterableValidationError)):
+ errors.extend(transform_error(exc, p, format_exception))
+ else:
+ errors.append(f"{format_exception(exc, note.type)} @ {p}")
+ for exc in without:
+ errors.append(f"{format_exception(exc, None)} @ {path}")
+ elif isinstance(exc, ClassValidationError):
+ with_notes, without = exc.group_exceptions()
+ for exc, note in with_notes:
+ p = f"{path}.{note.name}"
+ if isinstance(exc, (ClassValidationError, IterableValidationError)):
+ errors.extend(transform_error(exc, p, format_exception))
+ else:
+ errors.append(f"{format_exception(exc, note.type)} @ {p}")
+ for exc in without:
+ errors.append(f"{format_exception(exc, None)} @ {path}")
+ else:
+ errors.append(f"{format_exception(exc, None)} @ {path}")
+ return errors
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/LICENSE b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/LICENSE
new file mode 100644
index 0000000..62b076c
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/LICENSE
@@ -0,0 +1,20 @@
+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/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/METADATA
new file mode 100644
index 0000000..0a3a772
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/METADATA
@@ -0,0 +1,67 @@
+Metadata-Version: 2.1
+Name: certifi
+Version: 2024.8.30
+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/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/RECORD
new file mode 100644
index 0000000..7393811
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/RECORD
@@ -0,0 +1,15 @@
+certifi-2024.8.30.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+certifi-2024.8.30.dist-info/LICENSE,sha256=6TcW2mucDVpKHfYP5pWzcPBpVgPSH2-D8FPkLPwQyvc,989
+certifi-2024.8.30.dist-info/METADATA,sha256=GhBHRVUN6a4ZdUgE_N5wmukJfyuoE-QyIl8Y3ifNQBM,2222
+certifi-2024.8.30.dist-info/RECORD,,
+certifi-2024.8.30.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+certifi-2024.8.30.dist-info/WHEEL,sha256=UvcQYKBHoFqaQd6LKyqHw9fxEolWLQnlzP0h_LgJAfI,91
+certifi-2024.8.30.dist-info/top_level.txt,sha256=KMu4vUCfsjLrkPbSNdgdekS-pVJzBAJFO__nI8NF6-U,8
+certifi/__init__.py,sha256=p_GYZrjUwPBUhpLlCZoGb0miKBKSqDAyZC5DvIuqbHQ,94
+certifi/__main__.py,sha256=xBBoj905TUWBLRGANOcf7oi6e-3dMP4cEoG9OyMs11g,243
+certifi/__pycache__/__init__.cpython-311.pyc,,
+certifi/__pycache__/__main__.cpython-311.pyc,,
+certifi/__pycache__/core.cpython-311.pyc,,
+certifi/cacert.pem,sha256=lO3rZukXdPyuk6BWUJFOKQliWaXH6HGh9l1GGrUgG0c,299427
+certifi/core.py,sha256=qRDDFyXVJwTB_EmoGppaXU_R9qCZvhl-EzxPMuV3nTA,4426
+certifi/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/WHEEL
new file mode 100644
index 0000000..57e56b7
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/WHEEL
@@ -0,0 +1,5 @@
+Wheel-Version: 1.0
+Generator: setuptools (74.0.0)
+Root-Is-Purelib: true
+Tag: py3-none-any
+
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/top_level.txt b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/top_level.txt
new file mode 100644
index 0000000..963eac5
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi-2024.8.30.dist-info/top_level.txt
@@ -0,0 +1 @@
+certifi
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/certifi/__init__.py
new file mode 100644
index 0000000..f61d77f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi/__init__.py
@@ -0,0 +1,4 @@
+from .core import contents, where
+
+__all__ = ["contents", "where"]
+__version__ = "2024.08.30"
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi/__main__.py b/lambdas/aws-dd-forwarder-3.127.0/certifi/__main__.py
new file mode 100644
index 0000000..8945b5d
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi/__main__.py
@@ -0,0 +1,12 @@
+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/lambdas/aws-dd-forwarder-3.127.0/certifi/cacert.pem b/lambdas/aws-dd-forwarder-3.127.0/certifi/cacert.pem
new file mode 100644
index 0000000..3c165a1
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi/cacert.pem
@@ -0,0 +1,4929 @@
+
+# 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-----
+
+# Issuer: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA
+# Subject: CN=TWCA CYBER Root CA O=TAIWAN-CA OU=Root CA
+# Label: "TWCA CYBER Root CA"
+# Serial: 85076849864375384482682434040119489222
+# MD5 Fingerprint: 0b:33:a0:97:52:95:d4:a9:fd:bb:db:6e:a3:55:5b:51
+# SHA1 Fingerprint: f6:b1:1c:1a:83:38:e9:7b:db:b3:a8:c8:33:24:e0:2d:9c:7f:26:66
+# SHA256 Fingerprint: 3f:63:bb:28:14:be:17:4e:c8:b6:43:9c:f0:8d:6d:56:f0:b7:c4:05:88:3a:56:48:a3:34:42:4d:6b:3e:c5:58
+-----BEGIN CERTIFICATE-----
+MIIFjTCCA3WgAwIBAgIQQAE0jMIAAAAAAAAAATzyxjANBgkqhkiG9w0BAQwFADBQ
+MQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FOLUNBMRAwDgYDVQQLEwdSb290
+IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3QgQ0EwHhcNMjIxMTIyMDY1NDI5
+WhcNNDcxMTIyMTU1OTU5WjBQMQswCQYDVQQGEwJUVzESMBAGA1UEChMJVEFJV0FO
+LUNBMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJUV0NBIENZQkVSIFJvb3Qg
+Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDG+Moe2Qkgfh1sTs6P
+40czRJzHyWmqOlt47nDSkvgEs1JSHWdyKKHfi12VCv7qze33Kc7wb3+szT3vsxxF
+avcokPFhV8UMxKNQXd7UtcsZyoC5dc4pztKFIuwCY8xEMCDa6pFbVuYdHNWdZsc/
+34bKS1PE2Y2yHer43CdTo0fhYcx9tbD47nORxc5zb87uEB8aBs/pJ2DFTxnk684i
+JkXXYJndzk834H/nY62wuFm40AZoNWDTNq5xQwTxaWV4fPMf88oon1oglWa0zbfu
+j3ikRRjpJi+NmykosaS3Om251Bw4ckVYsV7r8Cibt4LK/c/WMw+f+5eesRycnupf
+Xtuq3VTpMCEobY5583WSjCb+3MX2w7DfRFlDo7YDKPYIMKoNM+HvnKkHIuNZW0CP
+2oi3aQiotyMuRAlZN1vH4xfyIutuOVLF3lSnmMlLIJXcRolftBL5hSmO68gnFSDA
+S9TMfAxsNAwmmyYxpjyn9tnQS6Jk/zuZQXLB4HCX8SS7K8R0IrGsayIyJNN4KsDA
+oS/xUgXJP+92ZuJF2A09rZXIx4kmyA+upwMu+8Ff+iDhcK2wZSA3M2Cw1a/XDBzC
+kHDXShi8fgGwsOsVHkQGzaRP6AzRwyAQ4VRlnrZR0Bp2a0JaWHY06rc3Ga4udfmW
+5cFZ95RXKSWNOkyrTZpB0F8mAwIDAQABo2MwYTAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAfBgNVHSMEGDAWgBSdhWEUfMFib5do5E83QOGt4A1WNzAd
+BgNVHQ4EFgQUnYVhFHzBYm+XaORPN0DhreANVjcwDQYJKoZIhvcNAQEMBQADggIB
+AGSPesRiDrWIzLjHhg6hShbNcAu3p4ULs3a2D6f/CIsLJc+o1IN1KriWiLb73y0t
+tGlTITVX1olNc79pj3CjYcya2x6a4CD4bLubIp1dhDGaLIrdaqHXKGnK/nZVekZn
+68xDiBaiA9a5F/gZbG0jAn/xX9AKKSM70aoK7akXJlQKTcKlTfjF/biBzysseKNn
+TKkHmvPfXvt89YnNdJdhEGoHK4Fa0o635yDRIG4kqIQnoVesqlVYL9zZyvpoBJ7t
+RCT5dEA7IzOrg1oYJkK2bVS1FmAwbLGg+LhBoF1JSdJlBTrq/p1hvIbZv97Tujqx
+f36SNI7JAG7cmL3c7IAFrQI932XtCwP39xaEBDG6k5TY8hL4iuO/Qq+n1M0RFxbI
+Qh0UqEL20kCGoE8jypZFVmAGzbdVAaYBlGX+bgUJurSkquLvWL69J1bY73NxW0Qz
+8ppy6rBePm6pUlvscG21h483XjyMnM7k8M4MZ0HMzvaAq07MTFb1wWFZk7Q+ptq4
+NxKfKjLji7gh7MMrZQzvIt6IKTtM1/r+t+FHvpw+PoP7UV31aPcuIYXcv/Fa4nzX
+xeSDwWrruoBa3lwtcHb4yOWHh8qgnaHlIhInD0Q9HWzq1MKLL295q39QpsQZp6F6
+t5b5wR9iWqJDB0BeJsas7a5wFsWqynKKTbDPAYsDP27X
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA12 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA12"
+# Serial: 587887345431707215246142177076162061960426065942
+# MD5 Fingerprint: c6:89:ca:64:42:9b:62:08:49:0b:1e:7f:e9:07:3d:e8
+# SHA1 Fingerprint: 7a:22:1e:3d:de:1b:06:ac:9e:c8:47:70:16:8e:3c:e5:f7:6b:06:f4
+# SHA256 Fingerprint: 3f:03:4b:b5:70:4d:44:b2:d0:85:45:a0:20:57:de:93:eb:f3:90:5f:ce:72:1a:cb:c7:30:c0:6d:da:ee:90:4e
+-----BEGIN CERTIFICATE-----
+MIIDcjCCAlqgAwIBAgIUZvnHwa/swlG07VOX5uaCwysckBYwDQYJKoZIhvcNAQEL
+BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u
+LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExMjAeFw0yMDA0MDgw
+NTM2NDZaFw00MDA0MDgwNTM2NDZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD
+eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS
+b290IENBMTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC6OcE3emhF
+KxS06+QT61d1I02PJC0W6K6OyX2kVzsqdiUzg2zqMoqUm048luT9Ub+ZyZN+v/mt
+p7JIKwccJ/VMvHASd6SFVLX9kHrko+RRWAPNEHl57muTH2SOa2SroxPjcf59q5zd
+J1M3s6oYwlkm7Fsf0uZlfO+TvdhYXAvA42VvPMfKWeP+bl+sg779XSVOKik71gur
+FzJ4pOE+lEa+Ym6b3kaosRbnhW70CEBFEaCeVESE99g2zvVQR9wsMJvuwPWW0v4J
+hscGWa5Pro4RmHvzC1KqYiaqId+OJTN5lxZJjfU+1UefNzFJM3IFTQy2VYzxV4+K
+h9GtxRESOaCtAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQD
+AgEGMB0GA1UdDgQWBBRXNPN0zwRL1SXm8UC2LEzZLemgrTANBgkqhkiG9w0BAQsF
+AAOCAQEAPrvbFxbS8hQBICw4g0utvsqFepq2m2um4fylOqyttCg6r9cBg0krY6Ld
+mmQOmFxv3Y67ilQiLUoT865AQ9tPkbeGGuwAtEGBpE/6aouIs3YIcipJQMPTw4WJ
+mBClnW8Zt7vPemVV2zfrPIpyMpcemik+rY3moxtt9XUa5rBouVui7mlHJzWhhpmA
+8zNL4WukJsPvdFlseqJkth5Ew1DgDzk9qTPxpfPSvWKErI4cqc1avTc7bgoitPQV
+55FYxTpE05Uo2cBl6XLK0A+9H7MV2anjpEcJnuDLN/v9vZfVvhgaaaI5gdka9at/
+yOPiZwud9AzqVN/Ssq+xIvEg37xEHA==
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA14 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA14"
+# Serial: 575790784512929437950770173562378038616896959179
+# MD5 Fingerprint: 71:0d:72:fa:92:19:65:5e:89:04:ac:16:33:f0:bc:d5
+# SHA1 Fingerprint: dd:50:c0:f7:79:b3:64:2e:74:a2:b8:9d:9f:d3:40:dd:bb:f0:f2:4f
+# SHA256 Fingerprint: 4b:00:9c:10:34:49:4f:9a:b5:6b:ba:3b:a1:d6:27:31:fc:4d:20:d8:95:5a:dc:ec:10:a9:25:60:72:61:e3:38
+-----BEGIN CERTIFICATE-----
+MIIFcjCCA1qgAwIBAgIUZNtaDCBO6Ncpd8hQJ6JaJ90t8sswDQYJKoZIhvcNAQEM
+BQAwUTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28u
+LCBMdGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNDAeFw0yMDA0MDgw
+NzA2MTlaFw00NTA0MDgwNzA2MTlaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpD
+eWJlcnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBS
+b290IENBMTQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDF0nqh1oq/
+FjHQmNE6lPxauG4iwWL3pwon71D2LrGeaBLwbCRjOfHw3xDG3rdSINVSW0KZnvOg
+vlIfX8xnbacuUKLBl422+JX1sLrcneC+y9/3OPJH9aaakpUqYllQC6KxNedlsmGy
+6pJxaeQp8E+BgQQ8sqVb1MWoWWd7VRxJq3qdwudzTe/NCcLEVxLbAQ4jeQkHO6Lo
+/IrPj8BGJJw4J+CDnRugv3gVEOuGTgpa/d/aLIJ+7sr2KeH6caH3iGicnPCNvg9J
+kdjqOvn90Ghx2+m1K06Ckm9mH+Dw3EzsytHqunQG+bOEkJTRX45zGRBdAuVwpcAQ
+0BB8b8VYSbSwbprafZX1zNoCr7gsfXmPvkPx+SgojQlD+Ajda8iLLCSxjVIHvXib
+y8posqTdDEx5YMaZ0ZPxMBoH064iwurO8YQJzOAUbn8/ftKChazcqRZOhaBgy/ac
+18izju3Gm5h1DVXoX+WViwKkrkMpKBGk5hIwAUt1ax5mnXkvpXYvHUC0bcl9eQjs
+0Wq2XSqypWa9a4X0dFbD9ed1Uigspf9mR6XU/v6eVL9lfgHWMI+lNpyiUBzuOIAB
+SMbHdPTGrMNASRZhdCyvjG817XsYAFs2PJxQDcqSMxDxJklt33UkN4Ii1+iW/RVL
+ApY+B3KVfqs9TC7XyvDf4Fg/LS8EmjijAQIDAQABo0IwQDAPBgNVHRMBAf8EBTAD
+AQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUBpOjCl4oaTeqYR3r6/wtbyPk
+86AwDQYJKoZIhvcNAQEMBQADggIBAJaAcgkGfpzMkwQWu6A6jZJOtxEaCnFxEM0E
+rX+lRVAQZk5KQaID2RFPeje5S+LGjzJmdSX7684/AykmjbgWHfYfM25I5uj4V7Ib
+ed87hwriZLoAymzvftAj63iP/2SbNDefNWWipAA9EiOWWF3KY4fGoweITedpdopT
+zfFP7ELyk+OZpDc8h7hi2/DsHzc/N19DzFGdtfCXwreFamgLRB7lUe6TzktuhsHS
+DCRZNhqfLJGP4xjblJUK7ZGqDpncllPjYYPGFrojutzdfhrGe0K22VoF3Jpf1d+4
+2kd92jjbrDnVHmtsKheMYc2xbXIBw8MgAGJoFjHVdqqGuw6qnsb58Nn4DSEC5MUo
+FlkRudlpcyqSeLiSV5sI8jrlL5WwWLdrIBRtFO8KvH7YVdiI2i/6GaX7i+B/OfVy
+K4XELKzvGUWSTLNhB9xNH27SgRNcmvMSZ4PPmz+Ln52kuaiWA3rF7iDeM9ovnhp6
+dB7h7sxaOgTdsxoEqBRjrLdHEoOabPXm6RUVkRqEGQ6UROcSjiVbgGcZ3GOTEAtl
+Lor6CZpO2oYofaphNdgOpygau1LgePhsumywbrmHXumZNTfxPWQrqaA0k89jL9WB
+365jJ6UeTo3cKXhZ+PmhIIynJkBugnLNeLLIjzwec+fBH7/PzqUqm9tEZDKgu39c
+JRNItX+S
+-----END CERTIFICATE-----
+
+# Issuer: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd.
+# Subject: CN=SecureSign Root CA15 O=Cybertrust Japan Co., Ltd.
+# Label: "SecureSign Root CA15"
+# Serial: 126083514594751269499665114766174399806381178503
+# MD5 Fingerprint: 13:30:fc:c4:62:a6:a9:de:b5:c1:68:af:b5:d2:31:47
+# SHA1 Fingerprint: cb:ba:83:c8:c1:5a:5d:f1:f9:73:6f:ca:d7:ef:28:13:06:4a:07:7d
+# SHA256 Fingerprint: e7:78:f0:f0:95:fe:84:37:29:cd:1a:00:82:17:9e:53:14:a9:c2:91:44:28:05:e1:fb:1d:8f:b6:b8:88:6c:3a
+-----BEGIN CERTIFICATE-----
+MIICIzCCAamgAwIBAgIUFhXHw9hJp75pDIqI7fBw+d23PocwCgYIKoZIzj0EAwMw
+UTELMAkGA1UEBhMCSlAxIzAhBgNVBAoTGkN5YmVydHJ1c3QgSmFwYW4gQ28uLCBM
+dGQuMR0wGwYDVQQDExRTZWN1cmVTaWduIFJvb3QgQ0ExNTAeFw0yMDA0MDgwODMy
+NTZaFw00NTA0MDgwODMyNTZaMFExCzAJBgNVBAYTAkpQMSMwIQYDVQQKExpDeWJl
+cnRydXN0IEphcGFuIENvLiwgTHRkLjEdMBsGA1UEAxMUU2VjdXJlU2lnbiBSb290
+IENBMTUwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQLUHSNZDKZmbPSYAi4Io5GdCx4
+wCtELW1fHcmuS1Iggz24FG1Th2CeX2yF2wYUleDHKP+dX+Sq8bOLbe1PL0vJSpSR
+ZHX+AezB2Ot6lHhWGENfa4HL9rzatAy2KZMIaY+jQjBAMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBTrQciu/NWeUUj1vYv0hyCTQSvT
+9DAKBggqhkjOPQQDAwNoADBlAjEA2S6Jfl5OpBEHvVnCB96rMjhTKkZEBhd6zlHp
+4P9mLQlO4E/0BdGF9jVg3PVys0Z9AjBEmEYagoUeYWmJSwdLZrWeqrqgHkHZAXQ6
+bkU6iYAZezKYVWOr62Nuk22rGwlgMU4=
+-----END CERTIFICATE-----
diff --git a/lambdas/aws-dd-forwarder-3.127.0/certifi/core.py b/lambdas/aws-dd-forwarder-3.127.0/certifi/core.py
new file mode 100644
index 0000000..91f538b
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/certifi/core.py
@@ -0,0 +1,114 @@
+"""
+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/lambdas/aws-dd-forwarder-3.127.0/certifi/py.typed b/lambdas/aws-dd-forwarder-3.127.0/certifi/py.typed
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/INSTALLER b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/INSTALLER
new file mode 100644
index 0000000..a1b589e
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/INSTALLER
@@ -0,0 +1 @@
+pip
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/LICENSE b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/LICENSE
new file mode 100644
index 0000000..ad82355
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/LICENSE
@@ -0,0 +1,21 @@
+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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/METADATA b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/METADATA
new file mode 100644
index 0000000..b19096b
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/METADATA
@@ -0,0 +1,695 @@
+Metadata-Version: 2.1
+Name: charset-normalizer
+Version: 3.4.0
+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: tahri.ahmed@proton.me
+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 :: 3.13
+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.4.0](https://github.com/Ousret/charset_normalizer/compare/3.3.2...3.4.0) (2024-10-08)
+
+### Added
+- Argument `--no-preemptive` in the CLI to prevent the detector to search for hints.
+- Support for Python 3.13 (#512)
+
+### Fixed
+- Relax the TypeError exception thrown when trying to compare a CharsetMatch with anything else than a CharsetMatch.
+- Improved the general reliability of the detector based on user feedbacks. (#520) (#509) (#498) (#407) (#537)
+- Declared charset in content (preemptive detection) not changed when converting to utf-8 bytes. (#381)
+
+## [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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/RECORD b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/RECORD
new file mode 100644
index 0000000..9b31b27
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/RECORD
@@ -0,0 +1,36 @@
+../../bin/normalizer,sha256=d64Y2GlBYzj4fRL5WK1WS-VHgezegWBH89IcZpevMig,242
+charset_normalizer-3.4.0.dist-info/INSTALLER,sha256=zuuue4knoyJ-UwPPXg8fezS7VCrXJQrAP7zeNuwvFQg,4
+charset_normalizer-3.4.0.dist-info/LICENSE,sha256=6zGgxaT7Cbik4yBV0lweX5w1iidS_vPNcgIT0cz-4kE,1070
+charset_normalizer-3.4.0.dist-info/METADATA,sha256=WGbEW9ehh2spNJxo1M6sEGGZWmsQ-oj2DsMjV29zoms,34159
+charset_normalizer-3.4.0.dist-info/RECORD,,
+charset_normalizer-3.4.0.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+charset_normalizer-3.4.0.dist-info/WHEEL,sha256=XihS4yPLFu_eB7R4sl7jUHiEAA7zQ3q0-_CuIzkpFkk,151
+charset_normalizer-3.4.0.dist-info/entry_points.txt,sha256=ADSTKrkXZ3hhdOVFi6DcUEHQRS0xfxDIE_pEz4wLIXA,65
+charset_normalizer-3.4.0.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-311.pyc,,
+charset_normalizer/__pycache__/__main__.cpython-311.pyc,,
+charset_normalizer/__pycache__/api.cpython-311.pyc,,
+charset_normalizer/__pycache__/cd.cpython-311.pyc,,
+charset_normalizer/__pycache__/constant.cpython-311.pyc,,
+charset_normalizer/__pycache__/legacy.cpython-311.pyc,,
+charset_normalizer/__pycache__/md.cpython-311.pyc,,
+charset_normalizer/__pycache__/models.cpython-311.pyc,,
+charset_normalizer/__pycache__/utils.cpython-311.pyc,,
+charset_normalizer/__pycache__/version.cpython-311.pyc,,
+charset_normalizer/api.py,sha256=kMyNUqrfBZU22PP0pYKrSldtYUGA24wsGlXGLAKra7c,22559
+charset_normalizer/cd.py,sha256=xwZliZcTQFA3jU0c00PRiu9MNxXTFxQkFLWmMW24ZzI,12560
+charset_normalizer/cli/__init__.py,sha256=D5ERp8P62llm2FuoMzydZ7d9rs8cvvLXqE-1_6oViPc,100
+charset_normalizer/cli/__main__.py,sha256=zX9sV_ApU1d96Wb0cS04vulstdB4F0Eh7kLn-gevfw4,10411
+charset_normalizer/cli/__pycache__/__init__.cpython-311.pyc,,
+charset_normalizer/cli/__pycache__/__main__.cpython-311.pyc,,
+charset_normalizer/constant.py,sha256=uwoW87NicWZDTLviX7le0wdoYBbhBQDA4n1JtJo77ts,40499
+charset_normalizer/legacy.py,sha256=XJjkT0hejMH8qfAKz1ts8OUiBT18t2FJP3tJgLwUWwc,2327
+charset_normalizer/md.cpython-311-x86_64-linux-gnu.so,sha256=Y7QSLD5QLoSFAWys0-tL7R6QB7oi5864zM6zr7RWek4,16064
+charset_normalizer/md.py,sha256=SIIZcENrslI7h3v4GigbFN61fRyE_wiCN1z9Ii3fBRo,20138
+charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so,sha256=xDjCrj9MzdH8kW7d-HbtvIaOcrX6SFiV7SrBv4QgGEI,272696
+charset_normalizer/models.py,sha256=oAMAcBSEY7CngbUXJp34Wc4Rl9NKJJjGmUwW3EPtk6g,12425
+charset_normalizer/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+charset_normalizer/utils.py,sha256=teiosMqzKjXyAHXnGdjSBOgnBZwx-SkBbCLrx0UXy8M,11894
+charset_normalizer/version.py,sha256=AX66S4ytQFdd6F5jbVU2OPMqYwFS5M3BkMvyX-3BKF8,79
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/REQUESTED b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/REQUESTED
new file mode 100644
index 0000000..e69de29
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/WHEEL b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/WHEEL
new file mode 100644
index 0000000..d9c3682
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/WHEEL
@@ -0,0 +1,6 @@
+Wheel-Version: 1.0
+Generator: setuptools (75.1.0)
+Root-Is-Purelib: false
+Tag: cp311-cp311-manylinux_2_17_x86_64
+Tag: cp311-cp311-manylinux2014_x86_64
+
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/entry_points.txt b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/entry_points.txt
new file mode 100644
index 0000000..65619e7
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/entry_points.txt
@@ -0,0 +1,2 @@
+[console_scripts]
+normalizer = charset_normalizer.cli:cli_detect
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/top_level.txt b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/top_level.txt
new file mode 100644
index 0000000..66958f0
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer-3.4.0.dist-info/top_level.txt
@@ -0,0 +1 @@
+charset_normalizer
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/.DS_Store b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/.DS_Store
new file mode 100644
index 0000000000000000000000000000000000000000..7e52a6c1f31dfebafd29d3ff8a2840c29e06eb70
GIT binary patch
literal 6148
zcmeHKy-veG47S@2MIGqKcq?Py;HbhAbVUj@MJ-aIWMN>tM`Pl-_oju8e*;Q@ReM@`7vuTTBU$=XBV!w2HfB3kY-nVHFzwqu(qb%mgv!<6}
zez(^+(JW{A94(*TIynE#Iy^68Qx|8z8E^(Jjsetck>yI!XJ^0}a0Yq?>!|6!0nIRnnXMKQpOVpnYON>*D(FDJD&U_4@oh+k6d
jL$JuD7`{@9Z!oezA7lZHhDi|`i2n#=8hmmF{*-}Fxz9*q
literal 0
HcmV?d00001
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__init__.py
new file mode 100644
index 0000000..55991fc
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__init__.py
@@ -0,0 +1,46 @@
+# -*- 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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__main__.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__main__.py
new file mode 100644
index 0000000..beae2ef
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/__main__.py
@@ -0,0 +1,4 @@
+from .cli import cli_detect
+
+if __name__ == "__main__":
+ cli_detect()
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/api.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/api.py
new file mode 100644
index 0000000..e3f2283
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/api.py
@@ -0,0 +1,668 @@
+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()
+
+ early_stop_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,
+ preemptive_declaration=specified_encoding,
+ )
+ 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
+ ),
+ )
+
+ current_match = CharsetMatch(
+ sequences,
+ encoding_iana,
+ mean_mess_ratio,
+ bom_or_sig_available,
+ cd_ratios_merged,
+ (
+ decoded_payload
+ if (
+ is_too_large_sequence is False
+ or encoding_iana in [specified_encoding, "ascii", "utf_8"]
+ )
+ else None
+ ),
+ preemptive_declaration=specified_encoding,
+ )
+
+ results.append(current_match)
+
+ if (
+ encoding_iana in [specified_encoding, "ascii", "utf_8"]
+ and mean_mess_ratio < 0.1
+ ):
+ # If md says nothing to worry about, then... stop immediately!
+ if mean_mess_ratio == 0.0:
+ logger.debug(
+ "Encoding detection: %s is most likely the one.",
+ current_match.encoding,
+ )
+ if explain:
+ logger.removeHandler(explain_handler)
+ logger.setLevel(previous_logger_level)
+ return CharsetMatches([current_match])
+
+ early_stop_results.append(current_match)
+
+ if (
+ len(early_stop_results)
+ and (specified_encoding is None or specified_encoding in tested)
+ and "ascii" in tested
+ and "utf_8" in tested
+ ):
+ probable_result: CharsetMatch = early_stop_results.best() # type: ignore[assignment]
+ logger.debug(
+ "Encoding detection: %s is most likely the one.",
+ probable_result.encoding,
+ )
+ if explain:
+ logger.removeHandler(explain_handler)
+ logger.setLevel(previous_logger_level)
+
+ return CharsetMatches([probable_result])
+
+ 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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cd.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cd.py
new file mode 100644
index 0000000..4ea6760
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cd.py
@@ -0,0 +1,395 @@
+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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__init__.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__init__.py
new file mode 100644
index 0000000..d95fedf
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__init__.py
@@ -0,0 +1,6 @@
+from .__main__ import cli_detect, query_yes_no
+
+__all__ = (
+ "cli_detect",
+ "query_yes_no",
+)
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__main__.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__main__.py
new file mode 100644
index 0000000..e7edd0f
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/cli/__main__.py
@@ -0,0 +1,320 @@
+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(
+ "-i",
+ "--no-preemptive",
+ action="store_true",
+ default=False,
+ dest="no_preemptive",
+ help="Disable looking at a charset declaration to hint the detector.",
+ )
+ 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:
+ if args.files:
+ for my_file in args.files:
+ my_file.close()
+ print("Use --replace in addition of --normalize only.", file=sys.stderr)
+ return 1
+
+ if args.force is True and args.replace is False:
+ if args.files:
+ for my_file in args.files:
+ my_file.close()
+ print("Use --force in addition of --replace only.", file=sys.stderr)
+ return 1
+
+ if args.threshold < 0.0 or args.threshold > 1.0:
+ if args.files:
+ for my_file in args.files:
+ my_file.close()
+ 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,
+ preemptive_behaviour=args.no_preemptive is False,
+ )
+
+ 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, "wb") as fp:
+ fp.write(best_guess.output())
+ 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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/constant.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/constant.py
new file mode 100644
index 0000000..f8f2a81
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/constant.py
@@ -0,0 +1,1997 @@
+# -*- 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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/legacy.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/legacy.py
new file mode 100644
index 0000000..3f6d490
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/legacy.py
@@ -0,0 +1,65 @@
+from __future__ import annotations
+
+from typing import TYPE_CHECKING, Any, Optional
+from warnings import warn
+
+from .api import from_bytes
+from .constant import CHARDET_CORRESPONDENCE
+
+# TODO: remove this check when dropping Python 3.7 support
+if TYPE_CHECKING:
+ from typing_extensions import TypedDict
+
+ class ResultDict(TypedDict):
+ encoding: Optional[str]
+ language: str
+ confidence: Optional[float]
+
+
+def detect(
+ byte_str: bytes, should_rename_legacy: bool = False, **kwargs: Any
+) -> ResultDict:
+ """
+ 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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md.cpython-311-x86_64-linux-gnu.so b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md.cpython-311-x86_64-linux-gnu.so
new file mode 100755
index 0000000000000000000000000000000000000000..3824a428ffd621958e1f1f22dfd105c58417ffd0
GIT binary patch
literal 16064
zcmeHOZ)_Y_5r3D9n`<3x6Ph-Sk-Uu(DM937yCkFpH|O}@8tl{?%Bt)gEUl64ds70bGAW+gqCE^P$Ab~1XvVc@}i%3F4Wxn{Bd2fE}
z-Ss&jA@QaAEbq+xX6C)w*?oI+x9@$uZ>WD$BB9Wd>ORHNLW@B%P#gxMR7M?Ex6-jy
z?bNoL*Hr7dTLc1?etC=rR*4*?7bPT6=o!}IS?o;B(np`JhzJ_=;}BN%8-tauFdf-s
z;Rw->O~~
zdofqfXuMIqAh@10taO}{#d681dTzyY9OX=vraa|L5K+$H*szn!SMn#Ps$RY_Hr!Jv
zm-1uocp-0e^)*g**5wY|!ql0(8krlU9-U&2x#D!0Mloc#oSUJJM&^3l=_+voD`#ZR
z>CL-^LOBa(M@L1`6{g0gy~#@6&84g5bUVvg<_@WWp}}K4PG`C^eGsQCbQ9e(=8pm9
zenk}5W@hIUC2^CwEY_IMn131MQRXXfC3q@=LtZ>;I^=tm?-8`60FF7wx@!SEIR91x
z_!e|RbVtSrjLFo}fEB=b&Y@0O~{Z&>D%cKHP@zrr$?vdhnE`R6Qi3A?;N
zvVFemMFQ;e4bL;Vcg5RI;T>Y0!n?J$*xWWxw(3=(WdE49KX``8zE%6&HT&YDC^6hh1ysgyjJ0DkS>0t_K
zX_5}FHQYsZiH9*R=<-)dIgxH|dz_^PW>GSBm<@UnO14IZknIdM?X8H`Ay2oujkf
z!Xf`0`6gPEM=YZJ<^R&vTJ6(BZ(OU@ST}aPR^xBD{0^C0;>@T@%(f(2w{A%-(60%*
z3FCLY^W-81Z~Qos5gYj0D_qqjAsKHK;}
z6TkoB_k}#(Wzq-VlMxiRI0JD8;ta$Yh%*ppAkILXfj9$k2I35SATr>ukBqE`#G1z+
zOBNvW+DmR*4e=LZen@1jTfIwUtjBB>8EX-D!e7>3^7l7x(EoF_R%ZDTeuGR6-`QT~
zFOk%+#`3$O=k>$f{$L2LxHWBuP;sLLkOmMpwIF(Y|HPWeI|ZMXfq`G%Y!ry|IkBTf
zsJdZ1dONG*e@^V_6|k0(NBSD7<)=jdFOmH?rN93d!Fu-Sc!y-6ZNJb5giZ)OE%X~g
z2YPxwW$mSv;QOqOc3REbVRg25cC>fg({Ak@&F3uJ^+d71qhnumw6L6{mA6oApUr?QTiF!uE~+
zev2@^em%J9hi07>v^0EDHTnAng4(2NR`Yf3TNLJL*q$B=GC#xkHidQ4Vf-Vi-hGs$
zUw5#cI&8n)pO0bu4rOP8h~bk8vvN(x^J%lX&PyRejh|1O=qZ5xD^Sv!3yoih&Z(ny^-Vz+oRT6c3kB*jML&s)1u}JE*
zzLoH8^r?c+4>;Yufqf_87K{S4djtCi39q*g!xcQbui{a{>-GO6;kyFkf&GE*r_OxO
zR=lb=Gcl3Qs)%f;zJ-pl7`lSEw$
zy~D$CD;0On$(Ov!oSLY(#k`Z7DHi9*B_Ns27eUivj-qj#{?YE?KBw<^FYg<1a@Ddk
z>6UW5Ii&Xs$Ge9IdkCc`xzlHhsogtD5bYy@)4Lb)&=z#ZS
zam@#R)B&It%};JTF0=4Qy_O-2`-VU21yIzLWTKmN2T|F?ag7Im)D@r@2l2xW^aS~H
z%?KIw2dE_@MdKG(zuRCP{86WX^5+0Ij2}J!66x6g7#mSTJp;O6VC}!1_^AIZVVo1x
z<^Drn9`=5{Fa7XX!B!<9=x>Q1=ycGScv1WGYY~5Z?t|`$Trl{f+s7mR_#6U7eGmI+
z{NED)P8e9i2>l{(p~xS?;(d$ECuL!Cy|p$KfBOxc7V`VrHeoMM)fgujj9AhzHL#o*#&vSie1V(6B$kK%$9=
Uy6mp!-@pYpwHt=`$Eg3m0k}Z)kN^Mx
literal 0
HcmV?d00001
diff --git a/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md.py b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md.py
new file mode 100644
index 0000000..d834db0
--- /dev/null
+++ b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md.py
@@ -0,0 +1,628 @@
+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 <= 13:
+ 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
+ self._buffer_glyph_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
+ if (
+ is_cjk(character)
+ or is_hangul(character)
+ or is_katakana(character)
+ or is_hiragana(character)
+ or is_thai(character)
+ ):
+ self._buffer_glyph_count += 1
+ 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.5:
+ 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.
+ elif (
+ 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
+ elif self._buffer_glyph_count == 1:
+ self._is_current_word_bad = True
+ self._foreign_long_count += 1
+ 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
+ self._buffer_glyph_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/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so b/lambdas/aws-dd-forwarder-3.127.0/charset_normalizer/md__mypyc.cpython-311-x86_64-linux-gnu.so
new file mode 100755
index 0000000000000000000000000000000000000000..38d5e703c023b509774c050c1c7b6bda963e10e1
GIT binary patch
literal 272696
zcmeFad3;mV_V<5U1}jq|idGy5ShXTzz^RC63N55qATnr0y-g{B7CXc?)q(?oQf;V}
zh*Pg)oGV_vb-buo4WLlxh!Z%*IR%vn4iy!CYwf*uva-n$?(2EJ-{<$oJ-&`7pZ8g3
z?X}0V&pshtTu?MIJuS^pTMy$*1C{R!N$hkYcUVvQWEgfM*VrHaf4Fg&uuYtao5Vka
zUzZ=%(XdF3Y4pO6VX5`wk85O1>d3DX=>^l}h1xOqT8Y(>U)LLxJFSN>2v15r<~rnc
ztDW+wuESLDy5`fRee>kxW0;Cg9W&^1j1l)-3R6F3lbt%EEpE=Qy>sz%!#naq{W!P3
zFf-IqU3UhjH%fM%7?Ur}WIq#YP!YN6N0q+d+^Rmd2#1vy8=)Fa6@v?7w?kcAk0o
z^p7q-z3gB8H)1UN!37_|(F%KC*pFG=b6~~YK38^+mBt(6Py6Jy!97-ISKK&uyglQ3
zyOD9w^bF@i1y83BOiwqgtxu#4UD@OAo?uYsmpaCih&|)7SI#bgO+!#`uG+`y0kVmV*t?nvBQldLQ5#
zY_YDLI66NgJvWefM(;G=#DRvjmoLY#+ORA>gFOQK=dgbPyV|~l4`0FlHSFKQ9)%sZ
zE%K1`|81atgnc{gzry|-?7zeQ2kf}*mInhnXb;$N>j}qRu=ggN0mnYD_k(=^>=xJ$
zfPEnBgJ9=d7U)A^9}N3pupa^Y5ZJA-9|ij{u;X?t9gm0O2>OhCBz+!5$CKcAGVHmq
zkAZzG>}S9}4tCt^bR18|33M!g<0RM}uon`W49BzS^HexG>GL^ooDTcBu%Ab)7>=`H
z{~PHNI%1kG_*};HT=?uJJr9l*uwM*&6|rhKdSJf<_IlVGU|$IP<*?&+B^aK#%@&>JxTY1V{h2^gS`*zePQQY
zf6$q*AHeuP_8Dyt1bq;(gW-4x>?_|Ydtl`HUmvwK6|7inzpm}e2bLW7$m-4S6g<&?
z)NA)zCloyS@sL;gY^;BC=NlLOIAP;Y{SP1Y!&fzzo_XNJ`nN0}*n9SS;FCN4xcRub>Huw
z51e6R4flWg{f}?Dtvzig
z*9~}}@uo{7Yd6o{zyGqsnpdxHs-LxF(60Bt=u>xW_@nVJR$Sck*JJw>9CP=I<97AR
zcrzB-JYaU2#dXx^e{Gt*t>x%FZ
zH{Mk{|MDHf?>(S?)GvQzJUaNRL@O3!aO;oWm?
ziJf=d<0n46%CdRU)_1lI*c@3j^r9OlmoEzTY3Q+E)$ZFp4;_B>rZcT$)=ybA;_TB0
zJ=6N*fFEzVt?jj@6CQrtKkAs`9aYcnxblt}zEwT1A7@)KqURURth;XSd+8T5zQ61^
z%XbHzRhQ?VR_2~H#NYSQ>VIFgYs1#-uDW^rkp4g3dyD79b8ee)#ka5frysQAhj+Tq
za6dP7LerbJ{1t)baP0ZeT{91U=lkhj_dDy*g3~6{PdxLXhbG)H`rwNWIPuSdYbSqn
zRB7F=L6_ARyng@k*=4?7TP~06cl__!i$8Y0Z#&yI^_RaYIFmU-&JAFkbg)}3d**Z-$;Cf5}#+IH`@mqw5Gv8oPN8EAJ
z%6?N9+~7H{qx4G<94c|9Dxq8!@>%%*HecLjpt5?4VAGz_-
z*2pi9tbc5&FR<1Cr|y8XT%KUs5Q_a*HG
zZ=HTj?t_o~`E=c!FW1ef`1g;W_X*f0{`~NZ*N=E>eg02R@AvaXZ*{-($3KVOyEyR7
zf_Hj6cf#e1ezShlZU6Dz-wIowaOda!c}Lm&*RK4sw?E5OdBfQSE1rJ#g`VkK-yHqc
z&x4N6{9yG7iyTi@eg4k3!)!Ibe|b$=Y3zY_8jm~eqxI{)UjO6Lbw6(0dc(2di@aal
z`JDe>lUi$ftVtXGkG4?{7H0gLkDdDG7))^0T$P`zJ2o|6J}@?dR@;VZO!-hCat2(NyUk4(F{Y?0cK|KXfSE
z$5PneG(5HcFHOp=!X#e#D68sQ&QE-yT_#FPn*Q^F*K@F
ze*S6FPHZOrpEDT;o;2yFn@#$A*rdL~(0)?I={2br1Nvhs`-_I9=HpHH*YGf(%1@n1
z`&j{v{^k-Xs%00h4}RZZfVuZPHGP
zGE(R3`K;7@o=LjTnzYYXpqx{+!~Q1i;U$xJI!x-T-o(D$q?~)0#Q&Q~yZr)!PgU;^
znv6ehnB?ngll#J*CiOeRB%U!Q>HcWqKWb7AHyf$*l?EJ&Xpb$|q(81QX;<%?q`S>z
zJRc4DO4UxL!D3^o^0z{esd$M=Ib@lPdp?tP)oC(rJY_OIH}01@o<@^6r<`D7Z&JUd
zChg>26aTd)@!)!Ms&ac9#^F?arHP+gp}(i9uft91Jqj%tUrpwRZ<&n48_oKo$vE@8
zNt}Fn4em0tv!^_hH<@28Gr7-RVA4)*F&XF2GAZYsCga0Y6JBFd4xgL!#}eh9=^kNHKG#CJ
z;A)TUTa$V`#U#HUo3z^)jAH}gO|_*cO{8I!2jd>_gWTp$7yLTn$HO>-+&5f;1r*tU
zY{?_^a_Cm*54dGPJ)*tyJ87@pFP6c5AGvtZ2X=1?Yj|%8^@}`+FR);Hf%u1T-$x#U
z_tm)lOniPH@}Dj3;c-lC&y&54?9U~BC&d%QmuIlm%Y$(s#Ebqzhf6Szc-j$^?zIv$
zk)NY_V7(k-cmnVNHp;GXIebRmtno*nQy>p&d@!^(Q4ZzO|24uJyrYKpfZQ69d=~L~
z%2)7ASq`dvGQdCDJO3^1L-Js}2K@_p$7vEkcEq-k>M=4xa(qXOn+Mt_+WS6{V57u_
z3mPHvFush24TdAJ?ND*jOGtbtkK03(FJFzcSMB6IDrfOB9qbMj*6>bksk;3YYTn>0k&4+GpXGMswJmn3@?>W>{Q7w
zCHtF*d$e*(r}i21N_*9h-cbEzi{z@m3>r-3ut;*%o_|-|C%Nhu*AVyNmo8va!3nUt>|s6W~tmi)N=~E!dv|ca$sB-(7`dtve
z3<29tc@WY7|@Uh#z?~e`ETz-obE5+R%}nfizT#=EtmGH{Y<5P5!U*}
zt5jc+tCH`6c8
zRNAZZd6DdG_=OPI{E$!FK8M8zw6_&VuF82B$C$v>9|qnx;n#<4ME
z-zfUaAx5W`?it6(d>M2fRO4_EiWkRWpJtEE49g)x?FzycTQS9HP@JlK4x#c1o+SfR
ze83>-Cxl3VUL4H&{;xH@P1I2kd`Cmot
z(@E`9`PmNf9Dpx*wEXTGF8#Q!mhn7EeuC8AY>hI0)lPa)|FzNmbUE4IK|DfVq`Qvz
z@igBE;eZd@)5LF6bUxd$;T-^toX}%FWQu1-+=T|t2c24D>>g&LsvVI*}
ze!n3<)*;dl43A=KqH=bgOX3<#ZE%3a6{(a|2
z|DO`yLHEZP&FeN3Kau)N>|<%)hxldGo;~MFo=bcwwf``U4|&9U!-be`WSF%7koZ?3
z{{BYrZ5gMHcqtr({g)DqB>t;a@)&)=?<^@Rw9Jr(aJksdpnegg
z`*JDyd1avVZ#i3ni^%?ADmU9S$(Imspmy%0c3wgJQflWBnpZYn2kJQ@MEBDUx}T0B|GCuf
z?3X0lKi5P0iTxlQtN!>R)mQmOSzpk7#5SJdblIh!3B62Nicq5
zoRMwPP_>6|sa@G_koKzl+n`+0-b3>%=x$=`PveP)#uF$mu@%z1)Jo5ZFwBbW0vN#2
zPcT>duOfa4rRxkx{wDD}Do^WH3E*T)_A^!bUqbwA
zkT{-4Xgs$-x#0FN^}7*;e(tSE;|pXnwLvnj0Q!=Ps?CkEe7kTDn-D1C4%0^m^Iv
z$c@pP$}Rk$j8nDq&*{Ds((XHlQ#&;1{`(|3`kC5ogvMbX@t;(CqjFR2>LZ$;SZV!4
zmH!H=U)QHH9yj^9jrxmcvg9j?Lo557}YMp2D
zaH`)4vV49a``-N}chZ1&QZISpfFmV$;TO|kYm(S_g8Wz)OFwp+Z)Z~dMz%?NRli%v
zf0&*VAtz#6N9`>{>o8EQVtXArIOZ#$tzS9RbH_E(zbenihEn|WfOskS8As!@++ghrxFx3~`wvEqKebId|NcL}1`wY>2P_?%y(0)Wey;hdn
zLu7wC-IpyDGG9xH_o4WM-%Ft4e+ne}QU6#3ic4$@;Bw@yEmEuaPoVbS(JuX0lKu5C
zfS`SNv*gFfu#Bfvy|+nzCfR>U^ILn9G}4j_I##p(1*d%A5KFH?ECCP@ByEgv!ru%z{0-QqjuYg<3mrd)B
zJ*gbRS~=7Xm-exI8P8a&bmSc&xwBPr)sKqkdBH}{3!^CAxiB%nbe&hof>G`B1eGtE
z;Ljxc?*7s~LgOvm4#f8P@sbCY%XA+iejePg(0`ET+v+~jrrP;tu!ySFO>GG9L5c$c%G8{Zkj)oP(SieKN?1ULgdHQ
zAnn!oFoo(dOwTnpl6^1oZzccGEX8&sm4647ziOW+P&rs=9(Xp{KSzGTbl;)nPGc60
zw@#X;ftlEvXYFAe3FGGo^pCIG3UMJhnBl2K;p~hA0_^_#V
zIG@^8h}u;(`RPsLn{~LfpG~|k3>2aqXdc^4JeTqtqj^Xld705p@rTAquu9oez1y^U
z-(r>iBTqoKRe~Y_?7yL
zoz_FVWPdNX#s2Hk`tNttK3xv!fF28t7{r7ALx)NJBl(#|^=_s4`N_o3qwyy|?+c2F
zPp5Vm)5gi4ARZAvJvS{P`v<8WJI<5oPEcHpR~Jg2N8BhWnO{{?T~g;Qt@W0a7$p_e
z6<(uc9vqC4!kJS_=DKU$^DFAS?%J7CCREl`yJwcpsdUS8sn3*@HI$-*(#ncOZexOT
zVZM7_$rN{8UB27vF7wvZIxFkvS5)JfnF~GcRHsUu3ri-JR@S*^cx&s+ARf>&YwMLH
zpEGM}rj%AMoUyQKPEF;sT4#NAnYX^wTTxRjQz*d=^Mm;U4^ts}a+vHPudK{njhDLT
z?s+Ad&Z_p*R#ba2^Z${JyRu?_1(q23nNeTosVJ+csjthg_f%GtL83BwQ?H3Drk7UF
zck^7ueR|xr=ea9t=bl$nn>q_KyihP@bt;Mp3ob6Kz7%R`?hJ2@$294@+OqP}in3WA
z@LyDOnVYIEMF@GdrE@CE3hQbru@ooP)K=~36zd@0U0PXLQ>NnBTNTC|$-Wq3J0rV2
zYE*ZW(f}RoQP1%!Q=Y*~5*3uPO5+ap!7kaIsP7b)$2pp(s>=8^W+(ANlgf=>`xocs
z<*93&U2kIGTv*UhRx)ED3@TLxwY4?129Vm?k{NCu|#D!I5i9skf}$T}QSUGB=x0=`O`$QI01-bDddRT6QsxZ}6e6yritAdM;SZ
zEU$H!Lg$8bYmT7hVRVZylDcNE(X05L&owE7){Y
zP0DtRO$Nq)Y%M@yJZ*ilzCYC$*DDPoye%^
z_0y`|a1M*!)MQ3Q74$(-JEimIyXTgOepUxJ`VuUsqMGXYNeFz+Ocm>LzZe
zP_iNP>QhhV{?HzGmU3R*jO26^AmOaAx@@|89=j^vtpJW;d%LSZYpr$HLH7ZV%zlrX
zhi|9It2Cx>{Gmo
zsnN@Bh6TO`X{Q7-f9RGWbwGVM}#?Yznwym8E0;s6sB
zUb6d9rO2r<)aoDJ>_|)EQ;4$H7c6$IB|J=NVr396vGRl3K4(hyRPC
zf(DP_hCL37YUUf2u*X3m)Vb)~GPT0GsijjBX93pKQbEnDsuA}&Y3PKOP$Hgj;EwG9
z0Un`Ym5i^is7xAwr^7vTA>>aD$aq_?a#xjk7V=?wVriXsLXBtPgz{3j7sGr+WEdUJ
zfEhlHi|Tr*DYfZtk2YyhgbZK^ul3el27QIOm|0p;3Dcpnauswz^;~H~SLMNET}%N~
zq6Fx4VI4k5sf%ae$W6m27{K%#XH_h@yt-L4C+0#+MoY%`FvJ@{K{Z}IH_?SlBw^R(
z)sYbt56<-D&2N0^T)5@bSHV*lMmBz-*IfrUXEEsl6RBzbMty&JMOisn;J_fNrAjmw
zX-#)uOaOXwA#~S>O
zb5tiNzq6|AO6Q5{73OLVQeGo_)*f(t4NSoI@S=N7Z6!uc-Bdu$9_C~?6N;OXPQIR?
zmH}strwFw-N*pQT4EnMgS{FB)9=GFkLb)5}
z??CvZ5j+W*+~yN)n%nZJCAM{#h{~2OO9@IM(ILfk@nKFVXhcr9y+ikwPXhS(0txYm
zFa=yZi8JsC)1gwxHkKJR=n3(rT!=#ebZ9XSibN6@r1B*iN8AtCs@9U?+JY*NcVT`h
zJlM#t3D)9iOBLWO&s=yOD6Gz}sDt5Ev<=}!@^}uU#6Fo~)yhf}-?r5sNZB{XS*_Fy;xR<-cyP5BV_Q0_$n
z=|>r1;cy$FlT9#j&1qZ;^SF{vl*%>U#p0)+5uhKiXHzcO1jWoplnpgWX{Fo%l!1$D
z6`ksCK!xp?Hra3d~}~rS9rI&fx_z^Rk9TqO3IF
zyvSV1w0iHfc{GgId0|dnYs|Z>wgTp5^X667*OeQkbLiGZPZW7|vcw?r_yYodz&1lB
zIKiQLpL5~V`l>nZTCsYZm^9ADK&HJVL@sROl7^avH|l*Sor-G}G;_?rPJ4oqerF5$(zZ;AZpSH!cP
zNFdc}gGuzMOjF13e`Xnvl9gO4kF}zjWP?k!Cc?7;8BS%Qg`dhK9u2tI`@#xO6T{#8
z74Z<_QW!$LA&K+~c!H`D?%H%yA{FU*p{GhMjbBR*40
zEnQQ)Ju)pCKn5UG~;tN!`ZK!8*
zwZtI1$X+i5GyU~VoqR1UR-tf8F`=fm2FHXFF<--%t1!tBQCHJU$hmNmyV~?LUV46o
zyK*i*UWloMqqKT1EV+vb9;8r>-fC(K8t`RBd_aPf<*O6%&>LSjlB!NjoG}S;1w7o9)uTBqR+N@ime%1bDse`HR8f{EUhBpKf(a)E
z6kp{LrfNBjBBZ4#n9buGAo&E7$dXu9gGWk8hwKxhEL2i^FjPd?1J=hVXs9axj{8lHM@9lU~^TT`F>{4O3v;06R!wfJg+
zoLkk2mq!)y8xM)*C7v0RR)^T6HC{B>2rJzUVl7F|Vz6xC+C}baC`Ni@#7{7(6m3hC
z7k(}6VnwC98fLcfQ#g}_$mO+iri|4FoxG$3`bJ45I)blf03
zX(^`oM7#^};gDSh-&25hao&<@d|8Z-MzxRvybHz0HBpOnVM@DtZv~_W?OD8FcB&`x
zeVY}=ha}9^KFlKd^q9<3O`W(|%1MtJ*D={t2He3u%r>~Yy_=_Yu4WcVMUrr)PA6ZS
z@;=W^Ozykf#QgS`Y-M^2QfBbnU0FFD8YMKQX&zdbg~kc5Jmy!r=fav2K9|GevHVJu
z8egI9sE>FP$g8fd!DlXLesG35B=0}iX~d$hTDlTf;hh4Tv=F#D0%m!23#-fUhJgbp
zXuQ9u&kWB%SB~OVcp1L;j=z6~#T@l!
zjV~KabI8m4;B~VHt;PiTBs%qwT8@W6k>kx)djwbVpa+<
zE4ZI91G>9FJNc{O1Wy0O{7m&Du-e<$CKvJeH!$F$z4UdFI1J$_zmg`>j<;a;eh5kv
z@1Cj}6S4i(HwRfx5+hj3?{~qCCZ%!Ga2JnjYK^!ZK@cWy?UgU8Z)~Pwl>>4SU+_vS
zcF+O{zUst^m2!f+qLNkf^t$qjdAun|z$}V%3kjG7I94xHS(9Ou*~VW+Gs`$bJG^C8
z!IT{4<8m2C_3HTBHJJ}qW6V6!TgF#-FN4KeES6~=@f}Z5Lik!N-hqn6*UPBKO~aLJ
z`V74kV}XiDxylv4hwWQ)NnxJquFlO;^)h~b@69f?wQ6_CXH(v0xrs^F<0j^}*<>rz
z+icuyl3a@vU%7%x_^ZiTm8hm7_!cj`FT@(dk2GgiQZyGO;0B^TiW`Fx(39khS^@cl
z10FGql9V$;nfPCa2VXIUyDxm*8QKzmhX#f^
zDw}j5I#cKNc2w7?qqI*}=05h-PI`bZxbJoQ&phtc-Chm$CB470QRmW(|Ni&i68L{p
z0COwRHV)cV7;9shw8&817P5nJU_~$WV>-bV0H__h-
zRNO;6qH(1ShwRtNzUf}sCo(jCGjWT?+lgB>{sQqFjlW6UuJN1)WV%ih?lR#X6YewN
z0TUiH;T?q(|9@Y
zT#dI8w`)8?+@bNDH>H24#>ZqO2Q~gF`ES>FFf9ET7bN@tn(Q+)ZYTdP
zjeke>sl+k7!)QAJuq7m48`sJSu*N
z#$&4dHLl`s*SJlUKmPD5Y-*fT@n>i}SCzlURs7`|H|TyD(zuGhQ{xu0x4M(#QSs+!
z+@Z=}<0}4UjXPEOYh1-2)wq@7vCm76N5${ZxQ*RfyxN&iE`54zoU99o*$=;)J
zgMRO)TjRklG29tOWwL+UR>^ZT?xJ*aH69^du5l;*E=7aJLpR9ZnNZiM@%G;PWjl;&
z_BNNak7+zmA?-7&lHp&umc~2gOFuS^e@6W!SL0Utou@X9-%aUuXx#IM
zEYIBP3k-=J}8jpXeb4^jEA)_8D*EKhZvD*tCF{v7hBxSiUG
zP2<4@(vL&q2F^e
zJTy=G329ul&rXf|$WK_~p?c{js_~C0UonkaVC5ILZjBpM&K6H{`}v;yWNF+(^<~v~
zutNIJ)wpWsc8$kYO8eCsPosVs*0`%b)$b+AaayUJyEGo4ai&@0R=>QyP2=`j$vZXP
zLG65##(ga^9(A2+&j(Zd4)UkCWsbCWYTQ{R>#hx}~Pc#!-=
zbY3p~bZh)l@?+E|*GuSInehyb$1av}S~cE6esVM(BR@8c2gr{@<7&KeYTQZrD%N=L
zGMO)r#_ytd8Z>T@AD_l8mq8Mw{@bSUP@{}rU8lxLE8X8S$e-d7>c19^8@00Bax|{mr%mGl
z@{_Ca82NE({AVi9VvPr=UAZ*wtfYF;xT;5=#$De?`)-Xps2nT{lk3a5OV&%9#yh^2
zJg9Nc4#_(;9%_+(H)-6rh|*I>dAZ?J&U(jz2|Dy?0s%&AJDjGk*vpd
zjjMX>(728Ktk!s>PWlOJ{BVkAlg7hTj}eW>s2;mDuIkaaJh@&XT~zNHA5G~7G;SLp
z?X#{(_T!{_v}!y?^BIT6gV)OIi#2XsDS5NTJ*q!yJVL)$s;*Q0E}!DhAb*Nm=gIgj
zI`>e2)VQigo5sUbkGUET;2#8l&8cx!{>2)%((h-l*7$i8e^}#zelq^ztCGt<_LXeF
zE{!|Cle}5uzE*jCo5t;nCGXU@i^_kK#zXXb|LQtb&Z^uT1jd`DxJk#nMke^tVm_7l*!?J8Mr?Ha$C{B&sCMSfOm+*Tv~
zgf*_(!zPVe$WKJ$u1e{rTjTdpJjT-Gda+RZ%+PqOO6J$9@n^_Sj>bb&&Nht)$d5zg
zs$DrX9{OIUyISL6N;jPf+73o{+{>JnH#arK`%vO7m{TRXlc$t9V=*SMm5XuHp%5T*VX7
zxQfT1`J*0>RpTliyT(;KE{&^rd>U8rgfy<=iD+Dvk3sVz6{m{Fs&N&MUE?Yqm&R2*
zL5-_;LK;``L^Q7AF=!s4;#BciHLl{ZYh1;n<|E3FiYKVqt9U{hSMfwNuHrH1eyjYe
zc&r*%@u>T=vRCo=Gv>xx+)$ut}Cw6b!ql0U7yBPx0?tOr)`z
z*(Y&kKa%;kF?-HK%pU%9Kz!?D9DdqAzJ(djiBrSa#5he^#91Fpm-7g-r=QRl_FDj&Oc@8I+-8NGnl>lTMFpO
z!uUzde-`6sGHzx32$pUR;}e*@jq!ZOa~a>lxSjC<%)i0PlXC~NKb!e+GJY2G<6(X{
zFJ|_o%)Wz_C+99^|0T2UWcHkwGy7+leK(7Ta}TpWhuPbiJ?9O~o?hXI(%8i8IrlMp
z`V+CjKFH$dyqVdnzkz@kv@`#l2bewm$phiPjd7PC@_#|b=P=&Rcp2jzjL&C$HRI)s
zhZqmA@(i*3a^A`8E191#}jb^q#I-YIkz(V
z+qi$mX=y|FaWOxf+nD{!%#Vx3$$2ibKZw~kGyk01nLRC~iFlmMo^uDYUm`5!|D23B
zGG5I1pDZ31^W~>_D3`SRu&KEK4#xXK3a=Z
z0?eNCW@b-IHp0G>#lv}k+0&oy74~h6+gP0KEM3ln%zh;+hjzxRn4buXhw~0*e-rbw
zn(><%4>5iV=)y%(-*>fIc_EDB@jLol-IJ5th
z*=Mlw=e(QQH?VkenLX#mw8Z!}huLQ^{uxU*$nwRxh1uW3?6Vk8XZ|BBznoi{{YlKe
zoTbZo4zquVrE6oH{&bf(8)AMq&t>+9vUKf?k7eA!_#-S`C*y}OdxMof=f%wapUjVo
z@qVlw8Ua~f=$i9#W=~&v5#BtEce8jREFR7qnEfth-^}be_c8keS)5T;&YU+hdoS}J
zVEjGC%UQadw=w&FvvLbE{ygLDjIU$V`Pm%=m-MPdnog=BJbK&l!(0uKuPRp6;Y|
zZ*>EJXE7dS{2|6O
zSUa4^cr)XR7;k5ME90Gvzr}cz@q-yJXYG7F^5TLFfOl@@z@ye$>Pjqycgqk#xZTRIT+7S5ROj9
z_h-DA@ue&SF2>)8|tqr4rarHM#@wAWe{>;9aasGZGz&QM=)%e!N
zIDfwoWL*6=1YXq6IQ)sx_}0NV{3+o0wwiJH)1&b%#CQQKhfc-^F&<|8khm9Ew`ZKU
z^9bYcC(7enlyUyvA;viTN#yv}&G<+bk8w_--MSgiV0>`g3#^|r4u4`jzGX44{+2SH
zv@(7~+}bd57(bG68{<~Sa~U7XxSjC>So{vghcSC6<3}-G%y>5AF2;{xyqxhomad2K
zfvm$fFn%oa<750W=BJr){=O!__;Jin8{@+n4>Eo{529~iuuW4d^F=0#;3D*
zvKT*^*;^UsKW~-8_^Hg^#`r4cKbP^-n7y6xT*e)Yk73-&`00!nGd`Aa7vpCzUe5S9
z#yyOm#drhbcE){-=P};Q_;|(xj9Z3c#+{7kFn$i>HpZtjp3C?Q#_f#HWZc0xfA8sJd=|4WX57Wf!NvHw%)XrQ
z^BDIq&flLlFs}XZH!ki`&`BsFm7l3V#Xbe(?8V^XPt~!G5cc1s~LAO
zejkgoobeiF?_u1-cmw0LjQbd`W4xL1DJbV9%6hUA+{$>E`N?72#<-2~8(Y<3VO0Vcf#vi86jSvyU-;FXP>e-^aLdUZVX6
zng0yN?`QTF#vfoji}42;w=&+&cn;(I{l1OyRm?t@@rN0=GyV_89gLsP^5taw6~>Dh
z=kM!Xj6cf!mowhMxQFq_7;j*F3rp9>_~XpJnelHJ4>0}&<86#T$#{_Qrxp@VthEW?__)l<6*|%WPUa={ubjA#>0$98GoDc7~>lm?`Hf<#*On6
z?Vo?&BZKkJS^O5p-(h~T7=M>>E937mp2PSi#%+vmW;~bi4;laO$N!eVe@kHBOTf|i
zU52Bj*CX)H`5jFmZ?EX_8HV9#d?{m{^s)PtFBYd8yN~_~{+~I-4xdn$^8N8J~-P3Wbl`=Pc9y$E%G)E1#@Q4c_E2)zJxChFKO
z07uV3Z9yFodN%3LI9Oe`5Z>Ky5`G5&A>aLs5r?-iUe_>X6W{qCN_BhtO+LXQK`Z{VeLEQ3r&6
z9Q84%eL}B7eJpB^(D$IuLG2RyR@BF#b_%@`^>Ea7p_ijR9<@#ArKm@swhFxn^$Dmg
zLf4`miP{i)0qPS`$NmuYkJ^ShBJ^z3qfm#1o{oAn>X6WrQJ;jmL+J6SPevUS`gGK%
zpbiK<8a2KG?D7dc9QA3aJwgvdor~Hf^kCFuP&a$SCei!wR+KxIR^oOYPP=|%yhF2ekvWOXyos7ov6wy%P0g)OMklqdpt8P3Wbl
zi%?sIUW9rIYKzddsHdVfgkFGp8tT|iQU9o&s3StpMtu(Iu+Y;{Pe&aRdNS%6s5^un
zk9sERpwOqIo`pIf^k~%hYN^X7^l;SYq4o$p40SPTm(YVzpO4xp^gz_JQQL*?gZcv0
zHlfo|Ux?Z&^iKFiu=0ygTZG<@`fsQWp|_weK^^-|)IVw$>WI)EqAo=p7J4JWfj^gkFle617$6MX0M#TZFDfU5(lhdI9Ph)Uj?+|EN8vBSOzceF^HY(9==Z
zq7Df?8Fd}%4xz`R_M#37eLCuT)B&MKqrMciPw3&OFGKASdKl^k)Gnb1qh5&GDfB?p
zi%{Ez?t}Vr)Hb2hQD1@DD)dhHWx4VzQCo!Gj`}LphR|D3FGd~vRn$LfAL@wEAEI7@
zIxO@?)Jsu^gnkuuBkB&J*P>pAIwWI*@
zQD2WbEcA5LD^Z7po{ahi)Ez>PM|~sepwOqIz6o_e=+UTeM(q=NIO)K8%f2t6A0)2Mwy
z4@dnk)E=RSp`cLH!(Ro6zZ~|Bc!z^iKHY;_~NFTZG<@
z`UTX6&|6Tyh&r}I)IaJF>WI)EqF#eKEc8ayYf*=UeiijP)Ez>vMg0=$pwQ2vei?N@
z=*Lm7N9_}O73vMBJwo4ux)Zfa=vz_0g4!wcO4P5SwhO%+^=qhYLN7)AI%=!Xi%`FT
z+9Gr<>NimvLN7r57V6k`QU9pJs3StpM*TMGu+Y;{Z$upudNS&FPH<
z`aRSEp+}>BAGJ^D;ix}A?Gbty>P@I!LJvm08MRaBfv7)3Z5O%^>W@&{gic5OF>0&O
zJK-1b%0EGE5qdl7Pf;5}Z$bST>e!E>{!vFzM}+p6+DHQ(5&A>aX{f_OZ$zDr
zIwbU~sC%I95PB`@o~VODKa08->VVLXqwbB`C-f@R_^P+dBlJC}Gf=yPz7_TUsGUNu
zMBN9qUFhYg@t;(6*@Rw-8h@3s%PRCD)cDn=E{o8$s0W}ngkFF;6LstdQU9p%)mv9Y
z=-H_8tHxbnp{JuBh&m+nWYh>tvFw|M7T|y5=eJEjj#B-tU~XEU#2cU0<}fx?Wm7L
zZ3w*u^$^st??wHiwxW&*{UPe1sKY{UL_G|3Na$BlABDO@=(VWvD-T^k(Dr5DdwUi6
zi?S^R%Rch<%J=7IXE2<0LhI%w+5J8bitDlso!Z4YkqrPpEtA6|L!b@|K}MF|L=~L#aZ@WHl%qEbu@mv
z%X^^1|NidxnnLvp5)n9BF1HGkgN2Eu$p4KnnWW0E@_V=Z{UCw~Y!pns$2!T>#fQ
z{Lzc@E)<0*>+AxMJjcGpxkmj!DDf|0&C$_lq^*hKmP8<
zNSgN$k)cc;Rpt<5R7ggo+SLCq{7+7fe=p^o^PiOWKIQNKar&7}I6YMDAZ2^ZY{DlF
zs6VLRRP8adsVROwH&yvnB-*Pz)%n82c?Y)U{Z&V>L5fasMQ?0S^&>$S%N90Bw6OlX
zg+YH#ZeQfa`^wgD#kk^IY@_z?R;^udZ2$8VNi>ImZ}BK;|HK~l*Qc`Ir~3ZC*k9z}
zkvzU+HsNwWygpOaSN;4%dD~Le2OED<)+ZZ(?EguB@GZ`gOHcZNaayHga$`v_r_$S%KSF@Hh#s5Z+pRxDWy#bIGwo#pa~@
zfF2)QeGa9!eo_|X)saS*+SR32@Mkm2Z_;h>AjgIYS#U3f;)2^D^yd@PyvN`jL$p9V
zi}NIY)&l(*T-%Lk-M71UZ+#~ay%>%X`oPrqzvlly^56G=$o~`H$oL->dPb*XO0F(;q9-
zpS((@U(3>`1kc(c66`Boo2FNsoL=5vr?==KnO^#y=?#GiHe_&b=|#Uv%HMG%f0@5k
z?J~WUUnR|-im;AvmU}O7v9RB%@
zYCn{}8gR4^<=OUSQhDzGx76iH?e)X^WqRXzdeBU>(y_5RWMj382yD?mBO(HrO<%}P%He3SI4z3#kEroR^c8Jm{h6Zfq?+rMD>#WAoCb|yJr?`naQ>G}yDIUaOZ3<1bEp?3^uwUHw#4%ry$$u><2q?P$NVPl
z7nEOIs)DHgqC{}94=m)o2Yn<;gnZy~X*}O(k;pe$;DR&eUEG<_!X7UfvbaZDh}kNZ
zjsvtToe6NEoU&q(I^!408{U<0wm5#nE7s1|$dWapjnHzpJ{^c&4#%#3iSoM`^^pmE
z0cu-9pN)EaLXSl~Gog=1y)dB<1O1=ekETNS=J#tmoXt_~Ma+)$_VVy&N$Evz1HJX(
zc>PCPP(KsbN$mlPGtnMoasHpibC?!SUoD>BKmE_*!Tw}kJ}xYuc;zSBrOeB8IBQd-
zXN$L|zN~(t7ehQ;Ux4wk{&Y6#M1P8oMg3sBJROa&0I(Vxowp~Bhk57aotrl+Zze2R
z{5fOPN3i^nWTnpTLjxX2ne&@f)n&p?g_
z%WHfot+4DRWsnO7^;==`k$oOa^IK1Oc~u&8r`+g8qO@V{BnuzY@-E8zTV9En-$`Hd
z0!1xV#)blH&x`YXR~koWF2kka7fy%&75TSCPk`$k{sK#(e?7#JxvT(kQrNgY&9R{%
z3(Kp>UvDXB`YQ9fUtp!^1@!VF{%_PPTTg`|fbr^#?964W!SD>bx1`m%-nTO?^J*L~
zmVq;TNde1ag^e$#<&XJ1a~Up@=4C!zV4QJ9{e~srXZPaFritKq$u9Z%2>6T!X@#w`
z($F(LclqBc^uKq8z5ebcSBh+8Hf;t!^78tAbm_7&aOsAE5m*tJo_~r>q|}9LSy-M3
zHx!(V=ZpMRM%PYA61hsc9L|h+Epr9_nWi3${anW_7Isv%E2X
z}Oa`|S#E1{8A>hMsra$Ax8oM302QztFz{o77xK%d8AX*%T{O-&Ivbt>syHt@+uz
z9ci78*27;dYMq;%QPk>Po3ZsMQI9asbTqEZfIMeJSAPm2!^&qyp}(NJXv_}pNJq=q
z=xCS-JH+xRG~{q0-e>oNEc;-^u*knVdeldv1TFyyWpsZq9m@I2T!;UJTj3)#G5L7Y
zb&foL(M-{d|MpMWjBox}Tzs-TX_qH2p_2>c$wTDHqvXjy9+g*KC{OPELnPZg_HUIZ|3D?R=?DBA=DaV?H;f!
z@^69aZ;-}N{a1^Jgf1_bv$+PgFUQz%rO;k7m+in>QiFpSh2fizMJ@9)ipCy&3%G=4
z4K2peav7|I?&_1dq73YDRTiR+{tM=Ph5naC54{bn;OU@X)GtM2>nvB!o7{56j;!cS
z&`cdi
zz%`kAhk(r?V1ua-hZ`;oT}}7E)rE~cv(u*dzZQ9@&%o0y=mj6DGMi3=Lc#zV0Cf!)
z9UCSXFJ(YUY`z~$B9XnW8{d=TgYcBubhIenZ4g5AbiDdIXbbfG1f`YP)JwSD7Ciz_
zc8im8{t3R%g-Yo938tag9*SV#@c#g`RHPUk0qH>1c1;%H*rAC))-Hx~bQ@7E1(v=u
zqM08+$>A`Kug9@y;-%L!a~Zz!jgAuofNUxFPOz{M-bNT#IiR_W3QcLb;-xHy|Fa_h
zuIQ7{q-2Bfo&g%(abS%-3Q>w2=Rr&G7C@bzng@4-!m{;+W8q2miswa1))!zYj)q{i
zj)e|Uid_df)X)!QMc{W~q#ZPwZ=-#{PPDFicn;ha{T&*cY$vJOl&H~7VA8c%6bLx(
zwf{My-_HJr?6(V4h1NfZ?jHu@t&hd;$1>r&w|+(IanY?1RTtL0Y=`pBjBh2Pcf(^Y
z6!sQ4hYe-myBL1`G5Gm?c=PUPDZmEgXz}4x6@wLT0+io%Fy3KJ`ZqvDL}!75i$~$b
ze@|SzJAl_tY5EFR@39Ac3qHDXKf@xR_96YkJzHuPUs`f}weKY2I|jZPv6uL8JWj;-
zl&BjSU)SE^YlHD$#Y6c{6<;Yfp+xy@+?a^3H+*wtFYz@(M2YwYvG`s|WG;32b$_x?
z@vVW!P!`{47T+(4B+TmfOBlQo@zsM;_4`cX;?(gK?^}FBljB?YcB1^gNhDzw--M+2
z-h)n|;(I7@aq9S1!_93U>URka28sIJ9u`R)xtDr<7$QlO+c+85P`W4)PbTXRIS@}V
zzE^{B!O=1ao{vM`{T$-WSwK#p2mLu!i~*OnxY_L56@eBTz_SX^go9VnJWEM*N;na{oN+l!xPIM>Hj%JGQe-^EfW6^tXYwQhK#f}2Gx2nktlma}LAxTVV66;|&
z1ugWyFCI~0Zt)sKRNj(jZK*if;m1T(;?1N8=gU
zM*V>;Ge$IRtncT5$&~}9_W0Au7)VA-@5XM(xE(Cv+amtn_#|C4)|+k3T!vp@&4&Q9
z^8K-*F;LQrn}jp(%~0X?{4v`Xw_*l!jtdvIR9PHtMJ;pJWI3R~ud9Xm$*9oQ18E*D
zzDx3Q<}&;d(DxVnl3E+z|m5f?aUw3?Z})O#`3W^#;kQ@P7C|ND+ac#
zA7s0zY^MW2R?%_YFcXU234IZhg~&q=e*u)uv1rtCVYX$;nBT8Dy9mzZp54+9z8#YW
z@8KL-t&?FHWKH3ibyuBO1i5gEpG3fZPzWm{g)L)>%GSdQ0xn2EE1&Go-;gEE7k`F@
zUu<}-n7k!g0JA{R7BF>-NWFLFvcAw(MJZ=q2aC(l5Gu3nQ(CUFA8CVBw{x#f#v#b(za9fJ&Y+*1JKJ|AnIb*Fn0OP58rp
zg)JqPJhALinVpfj48NU(Ph?x~E^Kka4UA?S>#^>3j{FNJSU@TGdw|3
z|DBkT(e)fW^U8WJ7`1z=1;)R^#tmsjWB!En;ndkJSNxd;qe8Uz8#qpQzrcF3K|Aj5
z`Vmgc@uU_KoC@A2XLR*~2a}ewa~v%*EYMuDpjzx>c4V%=FI)O!{vF3d$HzjO&c?p9fU>N(yP8ejKRm;n+8vOQ1ZA2vIHjjT|V%IBU~{Y
z#Rn&Tz#iW;0P=>XY~qw?Q5$+@qv$#SPEGOeD)fKmXgNF^+J1HpJV%az{7z}9`~k*8
zxC%ySc#bV9sT;
z{v9H8T*&Xa;AY3&a9ZRWzJ#><{J(AW%N7YQ5TNMsGdy?ogTV8#Q!YmzqNUy@?%FVl
zC0Z&xKb{NMfa9(_=!c^IA^Qi2`h&bW#%#@8_7GSUwp_6d>id`I!LPCUhMphoT7rqT
z4r<3NU6GxiRs?knQ4YaOWae)#YVCgveiUKBI@GI>!6N}o!8*MR3JpfmUcm{tvat~}
zm=A%^gzFy(s$AX+x1zk+c^7ou35_VvzZo2S0$nH%zyF3#qTmF4TnIkkx&kPjc*7`%
zOS|U7W!UiGp)#`xzkUb~ZU+bA;)uL>h`iVnPjn<+d4jkSI;y{`$p153=2q!q9x-kF
zK@CVdGCm!iildPHuDFNqaFPePb{byMj3A%6xFXya*U{^HMJqey`C=HWE*A+w+m$w%
z%N8KOmqJbWPaUInu*FKc9m=|Xm8$MJB5}B?$iEXBC|nzz4|NQ+?w^a5A`-7}+P6c`@23>sB?=#_^o=~I4$(@#gqTY5in~6;UMLzz|0Cq(
z-Ucwd4-H#S`T0)pDD0mA`>qPns`^hC@eCRO_FXq(nY8vlOQPRz1cbv1pb-*95pDh*
z^Y$ZTbu&sA-jiDU_mLLs5%rfB{faTP4tfGnJz7D-gXiQmxU|vr^-k;!KFAydbv8_s
zdMyAuN7F0baS-y4aG#Y6anm5fGU`9^1|&*6bJ;&cPQ@evt30!5e@L?HW}x6`u}HW7
zso-zx6Ku_nJ%2BO#s@{B)(5t)6MgQO=qu3q5>Gf6$gVgLC!q2fM#Kwu6-UdJS?bk9
zK^C+U=zj69X-tB%@z)v!R_*MVJ)W0>=%3aPx?visp5LMmzYLSj$KfWi42#K#-i8{!
zw6f=V!eiJK68RaX^7GrPJU=a<;8ya#nV%ekPvsN;$vM1+JT0bE!VK~Ob@n=S>ePC@yJd$>DY^;~wCGCAM-~mlx=zu6e&K}!udpZl!bKxH
z8p=vXQz!{PnzfkE;ZPPQh57#9=6Ndq`niu7xi>TZLgr9|YC>5PQIJg_i~w54K4_%(
zS9AKZ-_XN-BMlBRI}1IB_grk-TpZrT{uSM8$u^nUL|XU*;bupg=d)AKEIW*>ze8hY{poh<4oFR5?1(IValWDp!&}w!%~?0ZbKLgNaflYDIC=}R=mn6eI?c{M4XbNwU}{+<3x9`o
zM=Z*<^+(61&Ml?_OwydVvW0^bn8y
z7^`vR43-=9kX@!LFfBg8#BqPLcdDcSk5h9*>dcg26FVOXwDnk8LG)HWgHV2C-tO
z(wxg4fJ#I6{7<|CU_0wEo@Vq%E}&?Iuo{v*jMPhDrv9oO8Vi$`4A}Zssc~$F0wd(%
zsgXyeUSvST188PI^ntEeT__`?MXAhP!l|*v=rLf*Vqx6entTs?C=qt@F#goFTD%4$
zh05T+!)uE2*NpFn^6YV!XsLtPj9-iaY!moEFpXVxKAee3#0ro`e(Na7zuB_l_zrox
zX9O_q-p-2l1(MEfW6x+jJMw{P8qDnKnxBXMqp|
zYM!r3hVCt~E;~e@>}X>okXe$yA8EyYj(I}7oQ>AC{X_StQ>qz%>WeWai!m`VkP>LA
zmNRz(K34g-x^0D)fx4-!$s7h14Gy&ROC+CEEC?m}KL)YrM7vm_O|$}x46_`jdBCrW
z8X(<}6)vUQh}&a81kE&Hq)Y5>Olvkdp(sE@E)}$mEY$26H}PT@tC^JK7JKY_p0VV*J9RvwY1D)T{m=+RZLEW`nWVsreKd;
ziW*O!2N}0PwK3j;@b}m|z%VhOiFrLJr8w%RnXeF`8jC;qzR62e^ef13-HP6T1{Pa}
z_#yKf2nlw$${%g8kZq=a>;t+JLk4`RcmDR?lD!W?{q?pk<}pwjxb5h6Cwo-*4+qqtFHWh5NXihSXah8iL>aI
zW5K=R*xYwg{sgMdC48q4zF4cdvvWet9$=se9z?K;DH*o-t^+v4`8z8TDh`UR2ODT|
zv3~!c`~G{FR^3zq%qM`U2H_V&^vfiZ@JOrtcD#s1@J~_ML3&G9Qi%F09>E`&1DdYF
z&))ePV5bH6g`wSS{;~R1YaOi63($vFDGI}Md2c_C((noz<}9O*F-&LZarJevGbloM
z1$aG9CWsD$Vy|f}O8Fw%Y$lZv?WWPCBEGff!!FUh+gXgj)9qu({G9PNi3;bS#44}Q
zRJv*^BU~yk;=Mn-5**vGNI3STzeNj<#|wXWDRYBCvBNG&DEsBZsVRXTV16x`A0pbbVPmAK?c-*6vn8q_*+xVY_&hUizg920^}wv&wM*(+rMC{d&oUW@&88tjmh#i#s(F}Qi?tc3Z^*91X~;_D&i75;EuAe
z5Lj#v;&b9Lw1-}uK#~&Luh20riQy(M{IAiONlq^Cx$8lJmj6DvZ
z0W4$vF~s=qvAx61hi#63_+L*uzh+d9UBODke}#7Hek@Ro!afUZ?Pv%nPMFwbi&M>d
zShPV;SsyH~9o-~0bGFmp2>5GW@T3Y(`E&d(##sI6{5Sy=#616Ad&OSik13$oo{!u-
zU6&`~1*eGYvPP7;RP+-3y5*R<{3Z6@jM~~M-u=A6uCiMgdwN~Wj@&(qUA}A)DZ=YK
zJZ17ps)&byO8KOo`~c(nc~ew`f0wx9M>Ph|bx=GOO6Gs2;g;Y}-kGFtxJ^-QNq=>M
z{;B^1{S!e=XuGmwzdWo^=e1Wp%q`&Duv{{z&khHNA0cF4JJNnmdu9_@M>O)4gtX$2MC!!HA)%ov(?-3;_sxRb;zn##p8=oI_pS|+P{GZ6f4e??osUphL
zE+LO-{9omH>Aj=N^D*S~%JU|lk1CIEL_6AGylqFOPeqj_SUy0LArOS`u!n_v$=L_1
z{2_uw#w3Yul|QK8c5$ji6e4~h-gH5s_Ckz_#MXuGn{!YuUg|aVuqo=(cabbShz1W6
z((ZBS8UNC?r&@>SSRhgUDW4xmJb%n*5B{5c9_N-PwVyxZzjpxN>%T+r?9`rd%VYVU
z91F3^pMlOasMjD?Ip;KtQ8FE)SmjauwxeSl*FT!J6@R5w^?I7?udPu{db4dc8cTIA
z9xz;(HpKDUG4DYBZxi-=7WVb}M}+pi*0qls!{?!i=R5d(oBRAf+pjJ8dD}mp|G<8t
zu;)CFOrdX=#hWd$cix6uB>D#SXObWym-(G!!`rU4!_~3H$mgB@i{*ex
z*e8yE6^3eqC)tsL<~j9JV(UTQ8AnD6cJS3_$t-c6AHfA3Tp+8ddiPDH&I|3by|n@E
zZ^FqxeM*XcJCtz_lLmjmfTAh7==I2!YqC*^(Y$w=SJy0j3`S+f9%c0^(TjY{x1y
zX0Hz0R`2zfiKOZ9O3x#ln>ps;57^ys%46U@foDC|_A(^{ytoj@7=-n)8Pk
z5s-5boc&rbicUbop9d_&`Zpo4F&ijF-wrWT=iB*9M|DKv#Jg5f)Q^nUu>S?x{@BJ*8-t7-cz(a>8Gv)-E!lt$hpQL0$Sj@*UIGCCy%X!eBtwJ^=7PHye=
zW)wy3bTPHlCAoGI^ql(n{OI-b1?0KsY_a3~kTz9US9I(}m--n7Bi%TRR%$d1HYyEV
zV9i@rY|X14R<+FvFCJF)tMyFLp1noks=_XN0w-AWmY1p2V(Xpx#rah*)8gXrVyFH1
zG_RJUHLoua0g7ger>un}ck9yaWxAB{!IaK%{Ef176VEyD{EO`W9rw^<}sJtyV|L(hMLhMhS4QpB(5W3dK`rLxbN~TvCoSdIMxcl
z3Hv7M>qNu?TDyQwe4kav-fqoB2sUdQn;h!z8`ht$JH)t8!R^Phgxdfk+JD|~z~gV}
z`9@!rhUjGEnFNT0JQDv;v{#_}-&VQPw$825`IpFvTv@Td8fKm6`*?b4${376q%9Yw
z1b6M^{=GC6N95RPrQ;{$3#`Xa-$a1MS0&!9>Fga5lQoF4ZrEH9i5*ph9!W`{wX6iPK?LA3erELsoiX-)zjd
z?>inwUwmJOoz~?HF1lZe_y%eknTE#P=_0VNrKXX#AodxQ_Bf>M?=|*+T-Q`dRvJh*
zJMe01%6%uZX7}Nj4D+mKD-kY3l^9Ryn$U7j&^+e`v=#aoo-YC|{Bac=&*ZTl^*8(-oyy5u806k(}
z;XIcCT7??bgNoJroAgp@$^+P>xRDlO|B!pSw2iy&(KWgMW!;AV
z3b@4nG&KXSX`7*-1>u?vK{07!Xf~ilLq1sNt*{~kwC-Y&ZR?=jfl-JY9q6_-)+0MH
z+3eV|!}p`kME$Qw9cEpXx9UX_$gT!4_~1Ygy>fnRA)xVcLF{AvFnKvyZy+#O$H6l8
zz;PfSvqDd5((r-UqXMq|75cq*n&|i72(4c$qu)qSiQOoms2A32A>M#KNRZ1DBGQ2Q
zoL^2?%{5lDo8@gbUV(Yln2vz-=xROuD<<&S&q>Wuo7iEzNkov~7cK@opu=A45#D+a
zT6-VB2G%bK%Q^?9uL^tWSd?g-P}Z-yF1AK>1F+GN+#=2^2E9y|O_&f0q^N2WaZ@a2DLz
zKL`KtzwxnYU@Yy_NPjk^N7J{%O|#Uy|1{$J9PwEaX^O?=|3UuzuQ5z?1V@{A5iE`1
zCt5R$jv?{nX91=cr?3|j=9V4AT-o&4z5HS*VMlCKhHt?s+%2~gRfrMiuX>DuO}n2V
z`$M$3HTiI7!lN_`hj{EPr+t88<5tp+)|&Ck%71g!Y-{{Iu@_ejMj)Z${te_^n`Dbf
zXV|H?HS?CtqTLHKt#TaJ#Wa0C+i}sN%3tag&7%k6;5J3X=Vt~!u%jb7Vv^i0+gONY#qIIe
z90NJp<1nW-kQk?Ej@xMC^?Qd8VsR4szXUTDhc}4sy|L>7j+tJ}T|Fg{k?FD@n~vs4
z7}|?yLc~#XsZwD|zwn0KC8$K3?er>iE8H|ulDf%3m|O#dgi2bU^peO;p#4+eoA^A}
zE~v-e*a+de&}i5qQC~u$HxK=C2fSDXRJ4Sl>rl1*!rK#qeDQ)K$ZqM1&|f*W+AOw;
z^#FD3G3w}#_Osz-c-eb#>{-YPo7JlCF}BbiX_eoLm$AP1Cpms%sSZnxdKzi9dh2;2
z=qa7%SP#=HezM9JI|22K`EuF@9*({DzCGyw(Yp3J`Tsv_Yp>0%L91S8xbvvRwgA2fEHhoHMeU=r19uoXGi2{cjpPm9@_+1M0l+y8;
za;Mn+4H1~qhb&NIrb^HZZpTCts<#%2P{JF~eh$
z+=bV3@R}8b8YuST#I8Oeo)&21j|9`Poh=h~#0hv^WA6ai$mOnW>XKbZz$I=SQD4WB
zr&mIrLXSM{67u9E